]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //! A different sort of visitor for walking fn bodies. Unlike the |
2 | //! normal visitor, which just walks the entire body in one shot, the | |
3 | //! `ExprUseVisitor` determines how expressions are being used. | |
4 | ||
1a4d82fc JJ |
5 | pub use self::LoanCause::*; |
6 | pub use self::ConsumeMode::*; | |
7 | pub use self::MoveReason::*; | |
8 | pub use self::MatchMode::*; | |
9 | use self::TrackMatchMode::*; | |
10 | use self::OverloadedCallType::*; | |
11 | ||
54a0048b | 12 | use hir::def::Def; |
abe05a73 | 13 | use hir::def_id::DefId; |
a7813a04 | 14 | use infer::InferCtxt; |
1a4d82fc | 15 | use middle::mem_categorization as mc; |
ea8adc8c | 16 | use middle::region; |
54a0048b | 17 | use ty::{self, TyCtxt, adjustment}; |
1a4d82fc | 18 | |
54a0048b | 19 | use hir::{self, PatKind}; |
0531ce1d | 20 | use rustc_data_structures::sync::Lrc; |
83c7162d | 21 | use std::rc::Rc; |
e9174d1e | 22 | use syntax::ast; |
1a4d82fc | 23 | use syntax::ptr::P; |
3157f602 | 24 | use syntax_pos::Span; |
abe05a73 | 25 | use util::nodemap::ItemLocalSet; |
1a4d82fc JJ |
26 | |
27 | /////////////////////////////////////////////////////////////////////////// | |
28 | // The Delegate trait | |
29 | ||
30 | /// This trait defines the callbacks you can expect to receive when | |
31 | /// employing the ExprUseVisitor. | |
32 | pub trait Delegate<'tcx> { | |
33 | // The value found at `cmt` is either copied or moved, depending | |
34 | // on mode. | |
35 | fn consume(&mut self, | |
36 | consume_id: ast::NodeId, | |
37 | consume_span: Span, | |
83c7162d | 38 | cmt: &mc::cmt_<'tcx>, |
1a4d82fc JJ |
39 | mode: ConsumeMode); |
40 | ||
41 | // The value found at `cmt` has been determined to match the | |
42 | // pattern binding `matched_pat`, and its subparts are being | |
43 | // copied or moved depending on `mode`. Note that `matched_pat` | |
44 | // is called on all variant/structs in the pattern (i.e., the | |
45 | // interior nodes of the pattern's tree structure) while | |
46 | // consume_pat is called on the binding identifiers in the pattern | |
47 | // (which are leaves of the pattern's tree structure). | |
48 | // | |
49 | // Note that variants/structs and identifiers are disjoint; thus | |
50 | // `matched_pat` and `consume_pat` are never both called on the | |
51 | // same input pattern structure (though of `consume_pat` can be | |
52 | // called on a subpart of an input passed to `matched_pat). | |
53 | fn matched_pat(&mut self, | |
e9174d1e | 54 | matched_pat: &hir::Pat, |
83c7162d | 55 | cmt: &mc::cmt_<'tcx>, |
1a4d82fc JJ |
56 | mode: MatchMode); |
57 | ||
58 | // The value found at `cmt` is either copied or moved via the | |
59 | // pattern binding `consume_pat`, depending on mode. | |
60 | fn consume_pat(&mut self, | |
e9174d1e | 61 | consume_pat: &hir::Pat, |
83c7162d | 62 | cmt: &mc::cmt_<'tcx>, |
1a4d82fc JJ |
63 | mode: ConsumeMode); |
64 | ||
65 | // The value found at `borrow` is being borrowed at the point | |
66 | // `borrow_id` for the region `loan_region` with kind `bk`. | |
67 | fn borrow(&mut self, | |
68 | borrow_id: ast::NodeId, | |
69 | borrow_span: Span, | |
83c7162d | 70 | cmt: &mc::cmt_<'tcx>, |
7cac9316 | 71 | loan_region: ty::Region<'tcx>, |
1a4d82fc JJ |
72 | bk: ty::BorrowKind, |
73 | loan_cause: LoanCause); | |
74 | ||
75 | // The local variable `id` is declared but not initialized. | |
76 | fn decl_without_init(&mut self, | |
77 | id: ast::NodeId, | |
78 | span: Span); | |
79 | ||
80 | // The path at `cmt` is being assigned to. | |
81 | fn mutate(&mut self, | |
82 | assignment_id: ast::NodeId, | |
83 | assignment_span: Span, | |
83c7162d | 84 | assignee_cmt: &mc::cmt_<'tcx>, |
1a4d82fc JJ |
85 | mode: MutateMode); |
86 | } | |
87 | ||
c34b1796 | 88 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
89 | pub enum LoanCause { |
90 | ClosureCapture(Span), | |
91 | AddrOf, | |
92 | AutoRef, | |
9346a6ac | 93 | AutoUnsafe, |
1a4d82fc JJ |
94 | RefBinding, |
95 | OverloadedOperator, | |
96 | ClosureInvocation, | |
97 | ForLoop, | |
98 | MatchDiscriminant | |
99 | } | |
100 | ||
c34b1796 | 101 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
102 | pub enum ConsumeMode { |
103 | Copy, // reference to x where x has a type that copies | |
104 | Move(MoveReason), // reference to x where x has a type that moves | |
105 | } | |
106 | ||
c34b1796 | 107 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
108 | pub enum MoveReason { |
109 | DirectRefMove, | |
110 | PatBindingMove, | |
111 | CaptureMove, | |
112 | } | |
113 | ||
c34b1796 | 114 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
115 | pub enum MatchMode { |
116 | NonBindingMatch, | |
117 | BorrowingMatch, | |
118 | CopyingMatch, | |
119 | MovingMatch, | |
120 | } | |
121 | ||
c34b1796 | 122 | #[derive(Copy, Clone, PartialEq, Debug)] |
85aaf69f | 123 | enum TrackMatchMode { |
1a4d82fc JJ |
124 | Unknown, |
125 | Definite(MatchMode), | |
126 | Conflicting, | |
127 | } | |
128 | ||
85aaf69f | 129 | impl TrackMatchMode { |
1a4d82fc JJ |
130 | // Builds up the whole match mode for a pattern from its constituent |
131 | // parts. The lattice looks like this: | |
132 | // | |
133 | // Conflicting | |
134 | // / \ | |
135 | // / \ | |
136 | // Borrowing Moving | |
137 | // \ / | |
138 | // \ / | |
139 | // Copying | |
140 | // | | |
141 | // NonBinding | |
142 | // | | |
143 | // Unknown | |
144 | // | |
145 | // examples: | |
146 | // | |
147 | // * `(_, some_int)` pattern is Copying, since | |
148 | // NonBinding + Copying => Copying | |
149 | // | |
150 | // * `(some_int, some_box)` pattern is Moving, since | |
151 | // Copying + Moving => Moving | |
152 | // | |
153 | // * `(ref x, some_box)` pattern is Conflicting, since | |
154 | // Borrowing + Moving => Conflicting | |
155 | // | |
156 | // Note that the `Unknown` and `Conflicting` states are | |
157 | // represented separately from the other more interesting | |
158 | // `Definite` states, which simplifies logic here somewhat. | |
159 | fn lub(&mut self, mode: MatchMode) { | |
160 | *self = match (*self, mode) { | |
161 | // Note that clause order below is very significant. | |
162 | (Unknown, new) => Definite(new), | |
163 | (Definite(old), new) if old == new => Definite(old), | |
164 | ||
165 | (Definite(old), NonBindingMatch) => Definite(old), | |
166 | (Definite(NonBindingMatch), new) => Definite(new), | |
167 | ||
168 | (Definite(old), CopyingMatch) => Definite(old), | |
169 | (Definite(CopyingMatch), new) => Definite(new), | |
170 | ||
171 | (Definite(_), _) => Conflicting, | |
172 | (Conflicting, _) => *self, | |
173 | }; | |
174 | } | |
175 | ||
176 | fn match_mode(&self) -> MatchMode { | |
177 | match *self { | |
178 | Unknown => NonBindingMatch, | |
179 | Definite(mode) => mode, | |
180 | Conflicting => { | |
181 | // Conservatively return MovingMatch to let the | |
182 | // compiler continue to make progress. | |
183 | MovingMatch | |
184 | } | |
185 | } | |
186 | } | |
187 | } | |
188 | ||
c34b1796 | 189 | #[derive(Copy, Clone, PartialEq, Debug)] |
1a4d82fc JJ |
190 | pub enum MutateMode { |
191 | Init, | |
192 | JustWrite, // x = y | |
193 | WriteAndRead, // x += y | |
194 | } | |
195 | ||
c34b1796 | 196 | #[derive(Copy, Clone)] |
1a4d82fc JJ |
197 | enum OverloadedCallType { |
198 | FnOverloadedCall, | |
199 | FnMutOverloadedCall, | |
200 | FnOnceOverloadedCall, | |
201 | } | |
202 | ||
203 | impl OverloadedCallType { | |
0bf4aa26 | 204 | fn from_trait_id(tcx: TyCtxt<'_, '_, '_>, trait_id: DefId) -> OverloadedCallType { |
62682a34 | 205 | for &(maybe_function_trait, overloaded_call_type) in &[ |
ea8adc8c XL |
206 | (tcx.lang_items().fn_once_trait(), FnOnceOverloadedCall), |
207 | (tcx.lang_items().fn_mut_trait(), FnMutOverloadedCall), | |
208 | (tcx.lang_items().fn_trait(), FnOverloadedCall) | |
62682a34 | 209 | ] { |
1a4d82fc JJ |
210 | match maybe_function_trait { |
211 | Some(function_trait) if function_trait == trait_id => { | |
212 | return overloaded_call_type | |
213 | } | |
214 | _ => continue, | |
215 | } | |
216 | } | |
217 | ||
54a0048b | 218 | bug!("overloaded call didn't map to known function trait") |
1a4d82fc JJ |
219 | } |
220 | ||
0bf4aa26 | 221 | fn from_method_id(tcx: TyCtxt<'_, '_, '_>, method_id: DefId) -> OverloadedCallType { |
476ff2be SL |
222 | let method = tcx.associated_item(method_id); |
223 | OverloadedCallType::from_trait_id(tcx, method.container.id()) | |
1a4d82fc JJ |
224 | } |
225 | } | |
226 | ||
227 | /////////////////////////////////////////////////////////////////////////// | |
228 | // The ExprUseVisitor type | |
229 | // | |
041b39d2 | 230 | // This is the code that actually walks the tree. |
a7813a04 XL |
231 | pub struct ExprUseVisitor<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { |
232 | mc: mc::MemCategorizationContext<'a, 'gcx, 'tcx>, | |
0531ce1d | 233 | delegate: &'a mut dyn Delegate<'tcx>, |
7cac9316 | 234 | param_env: ty::ParamEnv<'tcx>, |
1a4d82fc JJ |
235 | } |
236 | ||
041b39d2 | 237 | // If the MC results in an error, it's because the type check |
1a4d82fc JJ |
238 | // failed (or will fail, when the error is uncovered and reported |
239 | // during writeback). In this case, we just ignore this part of the | |
240 | // code. | |
241 | // | |
242 | // Note that this macro appears similar to try!(), but, unlike try!(), | |
243 | // it does not propagate the error. | |
244 | macro_rules! return_if_err { | |
245 | ($inp: expr) => ( | |
246 | match $inp { | |
247 | Ok(v) => v, | |
c1a9b12d SL |
248 | Err(()) => { |
249 | debug!("mc reported err"); | |
250 | return | |
251 | } | |
1a4d82fc JJ |
252 | } |
253 | ) | |
254 | } | |
255 | ||
041b39d2 | 256 | impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx, 'tcx> { |
abe05a73 XL |
257 | /// Creates the ExprUseVisitor, configuring it with the various options provided: |
258 | /// | |
259 | /// - `delegate` -- who receives the callbacks | |
260 | /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`) | |
261 | /// - `region_scope_tree` --- region scope tree for the code being analyzed | |
262 | /// - `tables` --- typeck results for the code being analyzed | |
263 | /// - `rvalue_promotable_map` --- if you care about rvalue promotion, then provide | |
264 | /// the map here (it can be computed with `tcx.rvalue_promotable_map(def_id)`). | |
265 | /// `None` means that rvalues will be given more conservative lifetimes. | |
266 | /// | |
267 | /// See also `with_infer`, which is used *during* typeck. | |
0531ce1d | 268 | pub fn new(delegate: &'a mut (dyn Delegate<'tcx>+'a), |
041b39d2 XL |
269 | tcx: TyCtxt<'a, 'tcx, 'tcx>, |
270 | param_env: ty::ParamEnv<'tcx>, | |
ea8adc8c | 271 | region_scope_tree: &'a region::ScopeTree, |
abe05a73 | 272 | tables: &'a ty::TypeckTables<'tcx>, |
0531ce1d | 273 | rvalue_promotable_map: Option<Lrc<ItemLocalSet>>) |
3157f602 XL |
274 | -> Self |
275 | { | |
041b39d2 | 276 | ExprUseVisitor { |
abe05a73 XL |
277 | mc: mc::MemCategorizationContext::new(tcx, |
278 | region_scope_tree, | |
279 | tables, | |
280 | rvalue_promotable_map), | |
041b39d2 XL |
281 | delegate, |
282 | param_env, | |
283 | } | |
3157f602 | 284 | } |
041b39d2 | 285 | } |
3157f602 | 286 | |
041b39d2 | 287 | impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { |
0531ce1d | 288 | pub fn with_infer(delegate: &'a mut (dyn Delegate<'tcx>+'a), |
041b39d2 XL |
289 | infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, |
290 | param_env: ty::ParamEnv<'tcx>, | |
ea8adc8c | 291 | region_scope_tree: &'a region::ScopeTree, |
041b39d2 XL |
292 | tables: &'a ty::TypeckTables<'tcx>) |
293 | -> Self | |
e9174d1e | 294 | { |
a7813a04 | 295 | ExprUseVisitor { |
ea8adc8c | 296 | mc: mc::MemCategorizationContext::with_infer(infcx, region_scope_tree, tables), |
7cac9316 XL |
297 | delegate, |
298 | param_env, | |
a7813a04 | 299 | } |
1a4d82fc JJ |
300 | } |
301 | ||
32a655c1 | 302 | pub fn consume_body(&mut self, body: &hir::Body) { |
cc61c64b XL |
303 | debug!("consume_body(body={:?})", body); |
304 | ||
32a655c1 | 305 | for arg in &body.arguments { |
83c7162d XL |
306 | let arg_ty = return_if_err!(self.mc.pat_ty_adjusted(&arg.pat)); |
307 | debug!("consume_body: arg_ty = {:?}", arg_ty); | |
1a4d82fc | 308 | |
ea8adc8c | 309 | let fn_body_scope_r = |
b7449926 XL |
310 | self.tcx().mk_region(ty::ReScope( |
311 | region::Scope { | |
312 | id: body.value.hir_id.local_id, | |
313 | data: region::ScopeData::Node | |
0bf4aa26 | 314 | })); |
83c7162d | 315 | let arg_cmt = Rc::new(self.mc.cat_rvalue( |
8faf50e0 | 316 | arg.hir_id, |
1a4d82fc | 317 | arg.pat.span, |
9e0c209e | 318 | fn_body_scope_r, // Args live only as long as the fn body. |
83c7162d | 319 | arg_ty)); |
1a4d82fc | 320 | |
7453a54e | 321 | self.walk_irrefutable_pat(arg_cmt, &arg.pat); |
1a4d82fc | 322 | } |
32a655c1 SL |
323 | |
324 | self.consume_expr(&body.value); | |
1a4d82fc JJ |
325 | } |
326 | ||
a7813a04 | 327 | fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { |
041b39d2 | 328 | self.mc.tcx |
1a4d82fc JJ |
329 | } |
330 | ||
331 | fn delegate_consume(&mut self, | |
332 | consume_id: ast::NodeId, | |
333 | consume_span: Span, | |
83c7162d | 334 | cmt: &mc::cmt_<'tcx>) { |
62682a34 SL |
335 | debug!("delegate_consume(consume_id={}, cmt={:?})", |
336 | consume_id, cmt); | |
85aaf69f | 337 | |
83c7162d | 338 | let mode = copy_or_move(&self.mc, self.param_env, cmt, DirectRefMove); |
1a4d82fc JJ |
339 | self.delegate.consume(consume_id, consume_span, cmt, mode); |
340 | } | |
341 | ||
476ff2be | 342 | fn consume_exprs(&mut self, exprs: &[hir::Expr]) { |
85aaf69f | 343 | for expr in exprs { |
7453a54e | 344 | self.consume_expr(&expr); |
1a4d82fc JJ |
345 | } |
346 | } | |
347 | ||
e9174d1e | 348 | pub fn consume_expr(&mut self, expr: &hir::Expr) { |
62682a34 | 349 | debug!("consume_expr(expr={:?})", expr); |
1a4d82fc JJ |
350 | |
351 | let cmt = return_if_err!(self.mc.cat_expr(expr)); | |
83c7162d | 352 | self.delegate_consume(expr.id, expr.span, &cmt); |
1a4d82fc JJ |
353 | self.walk_expr(expr); |
354 | } | |
355 | ||
356 | fn mutate_expr(&mut self, | |
0bf4aa26 | 357 | span: Span, |
e9174d1e SL |
358 | assignment_expr: &hir::Expr, |
359 | expr: &hir::Expr, | |
1a4d82fc JJ |
360 | mode: MutateMode) { |
361 | let cmt = return_if_err!(self.mc.cat_expr(expr)); | |
0bf4aa26 | 362 | self.delegate.mutate(assignment_expr.id, span, &cmt, mode); |
1a4d82fc JJ |
363 | self.walk_expr(expr); |
364 | } | |
365 | ||
366 | fn borrow_expr(&mut self, | |
e9174d1e | 367 | expr: &hir::Expr, |
7cac9316 | 368 | r: ty::Region<'tcx>, |
1a4d82fc JJ |
369 | bk: ty::BorrowKind, |
370 | cause: LoanCause) { | |
62682a34 SL |
371 | debug!("borrow_expr(expr={:?}, r={:?}, bk={:?})", |
372 | expr, r, bk); | |
1a4d82fc JJ |
373 | |
374 | let cmt = return_if_err!(self.mc.cat_expr(expr)); | |
83c7162d | 375 | self.delegate.borrow(expr.id, expr.span, &cmt, r, bk, cause); |
1a4d82fc | 376 | |
1a4d82fc JJ |
377 | self.walk_expr(expr) |
378 | } | |
379 | ||
e9174d1e | 380 | fn select_from_expr(&mut self, expr: &hir::Expr) { |
1a4d82fc JJ |
381 | self.walk_expr(expr) |
382 | } | |
383 | ||
e9174d1e | 384 | pub fn walk_expr(&mut self, expr: &hir::Expr) { |
62682a34 | 385 | debug!("walk_expr(expr={:?})", expr); |
1a4d82fc JJ |
386 | |
387 | self.walk_adjustment(expr); | |
388 | ||
389 | match expr.node { | |
8faf50e0 | 390 | hir::ExprKind::Path(_) => { } |
1a4d82fc | 391 | |
8faf50e0 | 392 | hir::ExprKind::Type(ref subexpr, _) => { |
7453a54e | 393 | self.walk_expr(&subexpr) |
9cc50fc6 SL |
394 | } |
395 | ||
0bf4aa26 | 396 | hir::ExprKind::Unary(hir::UnDeref, ref base) => { // *base |
7cac9316 | 397 | self.select_from_expr(&base); |
1a4d82fc JJ |
398 | } |
399 | ||
0bf4aa26 | 400 | hir::ExprKind::Field(ref base, _) => { // base.f |
7453a54e | 401 | self.select_from_expr(&base); |
1a4d82fc JJ |
402 | } |
403 | ||
0bf4aa26 | 404 | hir::ExprKind::Index(ref lhs, ref rhs) => { // lhs[rhs] |
7cac9316 XL |
405 | self.select_from_expr(&lhs); |
406 | self.consume_expr(&rhs); | |
1a4d82fc JJ |
407 | } |
408 | ||
0bf4aa26 | 409 | hir::ExprKind::Call(ref callee, ref args) => { // callee(args) |
7453a54e | 410 | self.walk_callee(expr, &callee); |
1a4d82fc JJ |
411 | self.consume_exprs(args); |
412 | } | |
413 | ||
8faf50e0 | 414 | hir::ExprKind::MethodCall(.., ref args) => { // callee.m(args) |
1a4d82fc JJ |
415 | self.consume_exprs(args); |
416 | } | |
417 | ||
8faf50e0 | 418 | hir::ExprKind::Struct(_, ref fields, ref opt_with) => { |
9e0c209e | 419 | self.walk_struct_expr(fields, opt_with); |
1a4d82fc JJ |
420 | } |
421 | ||
8faf50e0 | 422 | hir::ExprKind::Tup(ref exprs) => { |
1a4d82fc JJ |
423 | self.consume_exprs(exprs); |
424 | } | |
425 | ||
8faf50e0 | 426 | hir::ExprKind::If(ref cond_expr, ref then_expr, ref opt_else_expr) => { |
7453a54e | 427 | self.consume_expr(&cond_expr); |
cc61c64b | 428 | self.walk_expr(&then_expr); |
85aaf69f | 429 | if let Some(ref else_expr) = *opt_else_expr { |
7453a54e | 430 | self.consume_expr(&else_expr); |
1a4d82fc JJ |
431 | } |
432 | } | |
433 | ||
8faf50e0 | 434 | hir::ExprKind::Match(ref discr, ref arms, _) => { |
83c7162d | 435 | let discr_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&discr))); |
cc61c64b | 436 | let r = self.tcx().types.re_empty; |
9e0c209e | 437 | self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant); |
1a4d82fc JJ |
438 | |
439 | // treatment of the discriminant is handled while walking the arms. | |
85aaf69f | 440 | for arm in arms { |
1a4d82fc JJ |
441 | let mode = self.arm_move_mode(discr_cmt.clone(), arm); |
442 | let mode = mode.match_mode(); | |
443 | self.walk_arm(discr_cmt.clone(), arm, mode); | |
444 | } | |
445 | } | |
446 | ||
8faf50e0 | 447 | hir::ExprKind::Array(ref exprs) => { |
1a4d82fc JJ |
448 | self.consume_exprs(exprs); |
449 | } | |
450 | ||
8faf50e0 | 451 | hir::ExprKind::AddrOf(m, ref base) => { // &base |
1a4d82fc JJ |
452 | // make sure that the thing we are pointing out stays valid |
453 | // for the lifetime `scope_r` of the resulting ptr: | |
041b39d2 | 454 | let expr_ty = return_if_err!(self.mc.expr_ty(expr)); |
b7449926 | 455 | if let ty::Ref(r, _, _) = expr_ty.sty { |
c1a9b12d | 456 | let bk = ty::BorrowKind::from_mutbl(m); |
7453a54e | 457 | self.borrow_expr(&base, r, bk, AddrOf); |
c1a9b12d | 458 | } |
1a4d82fc JJ |
459 | } |
460 | ||
8faf50e0 | 461 | hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => { |
54a0048b SL |
462 | for (o, output) in ia.outputs.iter().zip(outputs) { |
463 | if o.is_indirect { | |
464 | self.consume_expr(output); | |
9cc50fc6 | 465 | } else { |
0bf4aa26 XL |
466 | self.mutate_expr( |
467 | output.span, | |
468 | expr, | |
469 | output, | |
470 | if o.is_rw { | |
471 | MutateMode::WriteAndRead | |
472 | } else { | |
473 | MutateMode::JustWrite | |
474 | }, | |
475 | ); | |
9cc50fc6 | 476 | } |
1a4d82fc | 477 | } |
54a0048b | 478 | self.consume_exprs(inputs); |
1a4d82fc JJ |
479 | } |
480 | ||
8faf50e0 | 481 | hir::ExprKind::Continue(..) | |
0731742a XL |
482 | hir::ExprKind::Lit(..) | |
483 | hir::ExprKind::Err => {} | |
1a4d82fc | 484 | |
8faf50e0 | 485 | hir::ExprKind::Loop(ref blk, _, _) => { |
7453a54e | 486 | self.walk_block(&blk); |
1a4d82fc JJ |
487 | } |
488 | ||
8faf50e0 | 489 | hir::ExprKind::While(ref cond_expr, ref blk, _) => { |
7453a54e SL |
490 | self.consume_expr(&cond_expr); |
491 | self.walk_block(&blk); | |
1a4d82fc JJ |
492 | } |
493 | ||
8faf50e0 | 494 | hir::ExprKind::Unary(_, ref lhs) => { |
7cac9316 | 495 | self.consume_expr(&lhs); |
1a4d82fc JJ |
496 | } |
497 | ||
8faf50e0 | 498 | hir::ExprKind::Binary(_, ref lhs, ref rhs) => { |
7cac9316 XL |
499 | self.consume_expr(&lhs); |
500 | self.consume_expr(&rhs); | |
1a4d82fc JJ |
501 | } |
502 | ||
8faf50e0 | 503 | hir::ExprKind::Block(ref blk, _) => { |
7453a54e | 504 | self.walk_block(&blk); |
1a4d82fc JJ |
505 | } |
506 | ||
8faf50e0 | 507 | hir::ExprKind::Break(_, ref opt_expr) | hir::ExprKind::Ret(ref opt_expr) => { |
85aaf69f | 508 | if let Some(ref expr) = *opt_expr { |
7453a54e | 509 | self.consume_expr(&expr); |
1a4d82fc JJ |
510 | } |
511 | } | |
512 | ||
8faf50e0 | 513 | hir::ExprKind::Assign(ref lhs, ref rhs) => { |
0bf4aa26 | 514 | self.mutate_expr(expr.span, expr, &lhs, MutateMode::JustWrite); |
7453a54e | 515 | self.consume_expr(&rhs); |
1a4d82fc JJ |
516 | } |
517 | ||
8faf50e0 | 518 | hir::ExprKind::Cast(ref base, _) => { |
7453a54e | 519 | self.consume_expr(&base); |
1a4d82fc JJ |
520 | } |
521 | ||
8faf50e0 | 522 | hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => { |
041b39d2 | 523 | if self.mc.tables.is_method_call(expr) { |
7cac9316 XL |
524 | self.consume_expr(lhs); |
525 | } else { | |
0bf4aa26 | 526 | self.mutate_expr(expr.span, expr, &lhs, MutateMode::WriteAndRead); |
b039eaaf | 527 | } |
7cac9316 | 528 | self.consume_expr(&rhs); |
1a4d82fc JJ |
529 | } |
530 | ||
8faf50e0 | 531 | hir::ExprKind::Repeat(ref base, _) => { |
7453a54e | 532 | self.consume_expr(&base); |
1a4d82fc JJ |
533 | } |
534 | ||
8faf50e0 | 535 | hir::ExprKind::Closure(.., fn_decl_span, _) => { |
a7813a04 | 536 | self.walk_captures(expr, fn_decl_span) |
1a4d82fc JJ |
537 | } |
538 | ||
8faf50e0 | 539 | hir::ExprKind::Box(ref base) => { |
7453a54e | 540 | self.consume_expr(&base); |
1a4d82fc | 541 | } |
ea8adc8c | 542 | |
8faf50e0 | 543 | hir::ExprKind::Yield(ref value) => { |
ea8adc8c XL |
544 | self.consume_expr(&value); |
545 | } | |
1a4d82fc JJ |
546 | } |
547 | } | |
548 | ||
e9174d1e | 549 | fn walk_callee(&mut self, call: &hir::Expr, callee: &hir::Expr) { |
041b39d2 | 550 | let callee_ty = return_if_err!(self.mc.expr_ty_adjusted(callee)); |
62682a34 SL |
551 | debug!("walk_callee: callee={:?} callee_ty={:?}", |
552 | callee, callee_ty); | |
1a4d82fc | 553 | match callee_ty.sty { |
b7449926 | 554 | ty::FnDef(..) | ty::FnPtr(_) => { |
1a4d82fc JJ |
555 | self.consume_expr(callee); |
556 | } | |
b7449926 | 557 | ty::Error => { } |
1a4d82fc | 558 | _ => { |
ff7c6d11 XL |
559 | if let Some(def) = self.mc.tables.type_dependent_defs().get(call.hir_id) { |
560 | let def_id = def.def_id(); | |
b7449926 XL |
561 | let call_scope = region::Scope { |
562 | id: call.hir_id.local_id, | |
563 | data: region::ScopeData::Node | |
564 | }; | |
ff7c6d11 XL |
565 | match OverloadedCallType::from_method_id(self.tcx(), def_id) { |
566 | FnMutOverloadedCall => { | |
567 | let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope)); | |
568 | self.borrow_expr(callee, | |
569 | call_scope_r, | |
570 | ty::MutBorrow, | |
571 | ClosureInvocation); | |
572 | } | |
573 | FnOverloadedCall => { | |
574 | let call_scope_r = self.tcx().mk_region(ty::ReScope(call_scope)); | |
575 | self.borrow_expr(callee, | |
576 | call_scope_r, | |
577 | ty::ImmBorrow, | |
578 | ClosureInvocation); | |
579 | } | |
580 | FnOnceOverloadedCall => self.consume_expr(callee), | |
1a4d82fc | 581 | } |
ff7c6d11 XL |
582 | } else { |
583 | self.tcx().sess.delay_span_bug(call.span, | |
584 | "no type-dependent def for overloaded call"); | |
1a4d82fc JJ |
585 | } |
586 | } | |
587 | } | |
588 | } | |
589 | ||
e9174d1e | 590 | fn walk_stmt(&mut self, stmt: &hir::Stmt) { |
1a4d82fc | 591 | match stmt.node { |
8faf50e0 | 592 | hir::StmtKind::Decl(ref decl, _) => { |
1a4d82fc | 593 | match decl.node { |
8faf50e0 | 594 | hir::DeclKind::Local(ref local) => { |
7453a54e | 595 | self.walk_local(&local); |
1a4d82fc JJ |
596 | } |
597 | ||
8faf50e0 | 598 | hir::DeclKind::Item(_) => { |
1a4d82fc JJ |
599 | // we don't visit nested items in this visitor, |
600 | // only the fn body we were given. | |
601 | } | |
602 | } | |
603 | } | |
604 | ||
8faf50e0 XL |
605 | hir::StmtKind::Expr(ref expr, _) | |
606 | hir::StmtKind::Semi(ref expr, _) => { | |
7453a54e | 607 | self.consume_expr(&expr); |
1a4d82fc | 608 | } |
1a4d82fc JJ |
609 | } |
610 | } | |
611 | ||
e9174d1e | 612 | fn walk_local(&mut self, local: &hir::Local) { |
1a4d82fc JJ |
613 | match local.init { |
614 | None => { | |
94b46f34 | 615 | local.pat.each_binding(|_, hir_id, span, _| { |
0731742a | 616 | let node_id = self.mc.tcx.hir().hir_to_node_id(hir_id); |
94b46f34 | 617 | self.delegate.decl_without_init(node_id, span); |
1a4d82fc JJ |
618 | }) |
619 | } | |
620 | ||
621 | Some(ref expr) => { | |
622 | // Variable declarations with | |
623 | // initializers are considered | |
624 | // "assigns", which is handled by | |
625 | // `walk_pat`: | |
7453a54e | 626 | self.walk_expr(&expr); |
83c7162d | 627 | let init_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&expr))); |
7453a54e | 628 | self.walk_irrefutable_pat(init_cmt, &local.pat); |
1a4d82fc JJ |
629 | } |
630 | } | |
631 | } | |
632 | ||
633 | /// Indicates that the value of `blk` will be consumed, meaning either copied or moved | |
634 | /// depending on its type. | |
e9174d1e | 635 | fn walk_block(&mut self, blk: &hir::Block) { |
1a4d82fc JJ |
636 | debug!("walk_block(blk.id={})", blk.id); |
637 | ||
85aaf69f | 638 | for stmt in &blk.stmts { |
92a42be0 | 639 | self.walk_stmt(stmt); |
1a4d82fc JJ |
640 | } |
641 | ||
85aaf69f | 642 | if let Some(ref tail_expr) = blk.expr { |
7453a54e | 643 | self.consume_expr(&tail_expr); |
1a4d82fc JJ |
644 | } |
645 | } | |
646 | ||
647 | fn walk_struct_expr(&mut self, | |
9cc50fc6 | 648 | fields: &[hir::Field], |
e9174d1e | 649 | opt_with: &Option<P<hir::Expr>>) { |
1a4d82fc | 650 | // Consume the expressions supplying values for each field. |
85aaf69f | 651 | for field in fields { |
7453a54e | 652 | self.consume_expr(&field.expr); |
1a4d82fc JJ |
653 | } |
654 | ||
655 | let with_expr = match *opt_with { | |
656 | Some(ref w) => &**w, | |
657 | None => { return; } | |
658 | }; | |
659 | ||
83c7162d | 660 | let with_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&with_expr))); |
1a4d82fc JJ |
661 | |
662 | // Select just those fields of the `with` | |
663 | // expression that will actually be used | |
9e0c209e | 664 | match with_cmt.ty.sty { |
b7449926 | 665 | ty::Adt(adt, substs) if adt.is_struct() => { |
9e0c209e | 666 | // Consume those fields of the with expression that are needed. |
83c7162d XL |
667 | for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() { |
668 | let is_mentioned = fields.iter().any(|f| { | |
669 | self.tcx().field_index(f.id, self.mc.tables) == f_index | |
670 | }); | |
671 | if !is_mentioned { | |
9e0c209e SL |
672 | let cmt_field = self.mc.cat_field( |
673 | &*with_expr, | |
674 | with_cmt.clone(), | |
83c7162d | 675 | f_index, |
94b46f34 | 676 | with_field.ident, |
9e0c209e SL |
677 | with_field.ty(self.tcx(), substs) |
678 | ); | |
83c7162d | 679 | self.delegate_consume(with_expr.id, with_expr.span, &cmt_field); |
9e0c209e | 680 | } |
1a4d82fc | 681 | } |
1a4d82fc | 682 | } |
9e0c209e SL |
683 | _ => { |
684 | // the base expression should always evaluate to a | |
685 | // struct; however, when EUV is run during typeck, it | |
686 | // may not. This will generate an error earlier in typeck, | |
687 | // so we can just ignore it. | |
688 | if !self.tcx().sess.has_errors() { | |
689 | span_bug!( | |
690 | with_expr.span, | |
691 | "with expression doesn't evaluate to a struct"); | |
692 | } | |
1a4d82fc | 693 | } |
9e0c209e | 694 | } |
1a4d82fc JJ |
695 | |
696 | // walk the with expression so that complex expressions | |
697 | // are properly handled. | |
698 | self.walk_expr(with_expr); | |
1a4d82fc JJ |
699 | } |
700 | ||
701 | // Invoke the appropriate delegate calls for anything that gets | |
702 | // consumed or borrowed as part of the automatic adjustment | |
703 | // process. | |
e9174d1e | 704 | fn walk_adjustment(&mut self, expr: &hir::Expr) { |
041b39d2 | 705 | let adjustments = self.mc.tables.expr_adjustments(expr); |
7cac9316 XL |
706 | let mut cmt = return_if_err!(self.mc.cat_expr_unadjusted(expr)); |
707 | for adjustment in adjustments { | |
708 | debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment); | |
c30ab7b3 SL |
709 | match adjustment.kind { |
710 | adjustment::Adjust::NeverToAny | | |
711 | adjustment::Adjust::ReifyFnPointer | | |
712 | adjustment::Adjust::UnsafeFnPointer | | |
8bb4bdeb | 713 | adjustment::Adjust::ClosureFnPointer | |
7cac9316 XL |
714 | adjustment::Adjust::MutToConstPointer | |
715 | adjustment::Adjust::Unsize => { | |
9346a6ac AL |
716 | // Creating a closure/fn-pointer or unsizing consumes |
717 | // the input and stores it into the resulting rvalue. | |
83c7162d | 718 | self.delegate_consume(expr.id, expr.span, &cmt); |
9346a6ac | 719 | } |
c30ab7b3 | 720 | |
7cac9316 XL |
721 | adjustment::Adjust::Deref(None) => {} |
722 | ||
723 | // Autoderefs for overloaded Deref calls in fact reference | |
724 | // their receiver. That is, if we have `(*x)` where `x` | |
725 | // is of type `Rc<T>`, then this in fact is equivalent to | |
726 | // `x.deref()`. Since `deref()` is declared with `&self`, | |
727 | // this is an autoref of `x`. | |
728 | adjustment::Adjust::Deref(Some(ref deref)) => { | |
729 | let bk = ty::BorrowKind::from_mutbl(deref.mutbl); | |
83c7162d | 730 | self.delegate.borrow(expr.id, expr.span, &cmt, deref.region, bk, AutoRef); |
1a4d82fc | 731 | } |
1a4d82fc | 732 | |
7cac9316 | 733 | adjustment::Adjust::Borrow(ref autoref) => { |
83c7162d | 734 | self.walk_autoref(expr, &cmt, autoref); |
7cac9316 | 735 | } |
1a4d82fc | 736 | } |
7cac9316 | 737 | cmt = return_if_err!(self.mc.cat_expr_adjusted(expr, cmt, &adjustment)); |
1a4d82fc JJ |
738 | } |
739 | } | |
740 | ||
7cac9316 XL |
741 | /// Walks the autoref `autoref` applied to the autoderef'd |
742 | /// `expr`. `cmt_base` is the mem-categorized form of `expr` | |
743 | /// after all relevant autoderefs have occurred. | |
1a4d82fc | 744 | fn walk_autoref(&mut self, |
e9174d1e | 745 | expr: &hir::Expr, |
83c7162d | 746 | cmt_base: &mc::cmt_<'tcx>, |
7cac9316 XL |
747 | autoref: &adjustment::AutoBorrow<'tcx>) { |
748 | debug!("walk_autoref(expr.id={} cmt_base={:?} autoref={:?})", | |
9346a6ac | 749 | expr.id, |
62682a34 | 750 | cmt_base, |
7cac9316 | 751 | autoref); |
1a4d82fc | 752 | |
9346a6ac | 753 | match *autoref { |
c30ab7b3 | 754 | adjustment::AutoBorrow::Ref(r, m) => { |
1a4d82fc JJ |
755 | self.delegate.borrow(expr.id, |
756 | expr.span, | |
9346a6ac | 757 | cmt_base, |
9e0c209e | 758 | r, |
2c00a5a8 | 759 | ty::BorrowKind::from_mutbl(m.into()), |
1a4d82fc JJ |
760 | AutoRef); |
761 | } | |
9346a6ac | 762 | |
c30ab7b3 | 763 | adjustment::AutoBorrow::RawPtr(m) => { |
62682a34 | 764 | debug!("walk_autoref: expr.id={} cmt_base={:?}", |
9346a6ac | 765 | expr.id, |
62682a34 | 766 | cmt_base); |
9346a6ac AL |
767 | |
768 | // Converting from a &T to *T (or &mut T to *mut T) is | |
769 | // treated as borrowing it for the enclosing temporary | |
770 | // scope. | |
ea8adc8c | 771 | let r = self.tcx().mk_region(ty::ReScope( |
b7449926 XL |
772 | region::Scope { |
773 | id: expr.hir_id.local_id, | |
774 | data: region::ScopeData::Node | |
775 | })); | |
9346a6ac AL |
776 | |
777 | self.delegate.borrow(expr.id, | |
778 | expr.span, | |
779 | cmt_base, | |
780 | r, | |
781 | ty::BorrowKind::from_mutbl(m), | |
782 | AutoUnsafe); | |
c34b1796 | 783 | } |
1a4d82fc | 784 | } |
1a4d82fc JJ |
785 | } |
786 | ||
e9174d1e | 787 | fn arm_move_mode(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm) -> TrackMatchMode { |
1a4d82fc | 788 | let mut mode = Unknown; |
85aaf69f | 789 | for pat in &arm.pats { |
7453a54e | 790 | self.determine_pat_move_mode(discr_cmt.clone(), &pat, &mut mode); |
1a4d82fc JJ |
791 | } |
792 | mode | |
793 | } | |
794 | ||
e9174d1e | 795 | fn walk_arm(&mut self, discr_cmt: mc::cmt<'tcx>, arm: &hir::Arm, mode: MatchMode) { |
85aaf69f | 796 | for pat in &arm.pats { |
7453a54e | 797 | self.walk_pat(discr_cmt.clone(), &pat, mode); |
1a4d82fc JJ |
798 | } |
799 | ||
0bf4aa26 XL |
800 | if let Some(hir::Guard::If(ref e)) = arm.guard { |
801 | self.consume_expr(e) | |
1a4d82fc JJ |
802 | } |
803 | ||
7453a54e | 804 | self.consume_expr(&arm.body); |
1a4d82fc JJ |
805 | } |
806 | ||
0731742a | 807 | /// Walks a pat that occurs in isolation (i.e., top-level of fn |
1a4d82fc | 808 | /// arg or let binding. *Not* a match arm or nested pat.) |
e9174d1e | 809 | fn walk_irrefutable_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat) { |
1a4d82fc JJ |
810 | let mut mode = Unknown; |
811 | self.determine_pat_move_mode(cmt_discr.clone(), pat, &mut mode); | |
812 | let mode = mode.match_mode(); | |
813 | self.walk_pat(cmt_discr, pat, mode); | |
814 | } | |
815 | ||
816 | /// Identifies any bindings within `pat` and accumulates within | |
817 | /// `mode` whether the overall pattern/match structure is a move, | |
818 | /// copy, or borrow. | |
819 | fn determine_pat_move_mode(&mut self, | |
820 | cmt_discr: mc::cmt<'tcx>, | |
e9174d1e | 821 | pat: &hir::Pat, |
85aaf69f | 822 | mode: &mut TrackMatchMode) { |
0bf4aa26 XL |
823 | debug!("determine_pat_move_mode cmt_discr={:?} pat={:?}", cmt_discr, pat); |
824 | ||
041b39d2 | 825 | return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| { |
3b2f2976 | 826 | if let PatKind::Binding(..) = pat.node { |
0bf4aa26 XL |
827 | let bm = *self.mc.tables.pat_binding_modes() |
828 | .get(pat.hir_id) | |
829 | .expect("missing binding mode"); | |
3b2f2976 XL |
830 | match bm { |
831 | ty::BindByReference(..) => | |
832 | mode.lub(BorrowingMatch), | |
833 | ty::BindByValue(..) => { | |
834 | match copy_or_move(&self.mc, self.param_env, &cmt_pat, PatBindingMove) { | |
835 | Copy => mode.lub(CopyingMatch), | |
836 | Move(..) => mode.lub(MovingMatch), | |
837 | } | |
1a4d82fc JJ |
838 | } |
839 | } | |
840 | } | |
841 | })); | |
842 | } | |
843 | ||
844 | /// The core driver for walking a pattern; `match_mode` must be | |
0731742a | 845 | /// established up front, e.g., via `determine_pat_move_mode` (see |
1a4d82fc | 846 | /// also `walk_irrefutable_pat` for patterns that stand alone). |
5bcae85e | 847 | fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) { |
2c912e08 | 848 | debug!("walk_pat(cmt_discr={:?}, pat={:?})", cmt_discr, pat); |
1a4d82fc | 849 | |
8faf50e0 | 850 | let tcx = self.tcx(); |
7cac9316 | 851 | let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self; |
041b39d2 | 852 | return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| { |
ea8adc8c | 853 | if let PatKind::Binding(_, canonical_id, ..) = pat.node { |
2c912e08 XL |
854 | debug!( |
855 | "walk_pat: binding cmt_pat={:?} pat={:?} match_mode={:?}", | |
856 | cmt_pat, | |
857 | pat, | |
858 | match_mode, | |
859 | ); | |
8faf50e0 XL |
860 | if let Some(&bm) = mc.tables.pat_binding_modes().get(pat.hir_id) { |
861 | debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); | |
862 | ||
863 | // pat_ty: the type of the binding being produced. | |
864 | let pat_ty = return_if_err!(mc.node_ty(pat.hir_id)); | |
865 | debug!("walk_pat: pat_ty={:?}", pat_ty); | |
866 | ||
867 | // Each match binding is effectively an assignment to the | |
868 | // binding being produced. | |
869 | let def = Def::Local(canonical_id); | |
870 | if let Ok(ref binding_cmt) = mc.cat_def(pat.hir_id, pat.span, pat_ty, def) { | |
871 | delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init); | |
872 | } | |
5bcae85e | 873 | |
8faf50e0 XL |
874 | // It is also a borrow or copy/move of the value being matched. |
875 | match bm { | |
876 | ty::BindByReference(m) => { | |
b7449926 | 877 | if let ty::Ref(r, _, _) = pat_ty.sty { |
8faf50e0 XL |
878 | let bk = ty::BorrowKind::from_mutbl(m); |
879 | delegate.borrow(pat.id, pat.span, &cmt_pat, r, bk, RefBinding); | |
880 | } | |
881 | } | |
882 | ty::BindByValue(..) => { | |
883 | let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove); | |
884 | debug!("walk_pat binding consuming pat"); | |
885 | delegate.consume_pat(pat, &cmt_pat, mode); | |
c1a9b12d | 886 | } |
1a4d82fc | 887 | } |
8faf50e0 XL |
888 | } else { |
889 | tcx.sess.delay_span_bug(pat.span, "missing binding mode"); | |
1a4d82fc JJ |
890 | } |
891 | } | |
892 | })); | |
893 | ||
894 | // Do a second pass over the pattern, calling `matched_pat` on | |
895 | // the interior nodes (enum variants and structs), as opposed | |
896 | // to the above loop's visit of than the bindings that form | |
897 | // the leaves of the pattern tree structure. | |
041b39d2 | 898 | return_if_err!(mc.cat_pattern(cmt_discr, pat, |cmt_pat, pat| { |
476ff2be SL |
899 | let qpath = match pat.node { |
900 | PatKind::Path(ref qpath) | | |
901 | PatKind::TupleStruct(ref qpath, ..) | | |
902 | PatKind::Struct(ref qpath, ..) => qpath, | |
903 | _ => return | |
904 | }; | |
3b2f2976 | 905 | let def = mc.tables.qpath_def(qpath, pat.hir_id); |
476ff2be SL |
906 | match def { |
907 | Def::Variant(variant_did) | | |
908 | Def::VariantCtor(variant_did, ..) => { | |
041b39d2 | 909 | let downcast_cmt = mc.cat_downcast_if_needed(pat, cmt_pat, variant_did); |
1a4d82fc | 910 | |
5bcae85e | 911 | debug!("variant downcast_cmt={:?} pat={:?}", downcast_cmt, pat); |
83c7162d | 912 | delegate.matched_pat(pat, &downcast_cmt, match_mode); |
1a4d82fc | 913 | } |
476ff2be SL |
914 | Def::Struct(..) | Def::StructCtor(..) | Def::Union(..) | |
915 | Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => { | |
5bcae85e | 916 | debug!("struct cmt_pat={:?} pat={:?}", cmt_pat, pat); |
83c7162d | 917 | delegate.matched_pat(pat, &cmt_pat, match_mode); |
1a4d82fc | 918 | } |
476ff2be | 919 | _ => {} |
1a4d82fc JJ |
920 | } |
921 | })); | |
922 | } | |
923 | ||
a7813a04 | 924 | fn walk_captures(&mut self, closure_expr: &hir::Expr, fn_decl_span: Span) { |
62682a34 | 925 | debug!("walk_captures({:?})", closure_expr); |
1a4d82fc | 926 | |
c1a9b12d | 927 | self.tcx().with_freevars(closure_expr.id, |freevars| { |
85aaf69f | 928 | for freevar in freevars { |
0731742a XL |
929 | let var_hir_id = self.tcx().hir().node_to_hir_id(freevar.var_id()); |
930 | let closure_def_id = self.tcx().hir().local_def_id(closure_expr.id); | |
3b2f2976 | 931 | let upvar_id = ty::UpvarId { |
a1dfa0c6 | 932 | var_path: ty::UpvarPath { hir_id: var_hir_id }, |
abe05a73 | 933 | closure_expr_id: closure_def_id.to_local(), |
3b2f2976 | 934 | }; |
041b39d2 | 935 | let upvar_capture = self.mc.tables.upvar_capture(upvar_id); |
8faf50e0 | 936 | let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.hir_id, |
a7813a04 | 937 | fn_decl_span, |
ea8adc8c | 938 | freevar)); |
85aaf69f SL |
939 | match upvar_capture { |
940 | ty::UpvarCapture::ByValue => { | |
041b39d2 | 941 | let mode = copy_or_move(&self.mc, |
7cac9316 XL |
942 | self.param_env, |
943 | &cmt_var, | |
944 | CaptureMove); | |
83c7162d | 945 | self.delegate.consume(closure_expr.id, freevar.span, &cmt_var, mode); |
85aaf69f SL |
946 | } |
947 | ty::UpvarCapture::ByRef(upvar_borrow) => { | |
948 | self.delegate.borrow(closure_expr.id, | |
a7813a04 | 949 | fn_decl_span, |
83c7162d | 950 | &cmt_var, |
85aaf69f SL |
951 | upvar_borrow.region, |
952 | upvar_borrow.kind, | |
953 | ClosureCapture(freevar.span)); | |
954 | } | |
1a4d82fc JJ |
955 | } |
956 | } | |
957 | }); | |
958 | } | |
959 | ||
1a4d82fc | 960 | fn cat_captured_var(&mut self, |
8faf50e0 | 961 | closure_hir_id: hir::HirId, |
1a4d82fc | 962 | closure_span: Span, |
ea8adc8c | 963 | upvar: &hir::Freevar) |
83c7162d | 964 | -> mc::McResult<mc::cmt_<'tcx>> { |
1a4d82fc JJ |
965 | // Create the cmt for the variable being borrowed, from the |
966 | // caller's perspective | |
0731742a | 967 | let var_hir_id = self.tcx().hir().node_to_hir_id(upvar.var_id()); |
3b2f2976 | 968 | let var_ty = self.mc.node_ty(var_hir_id)?; |
8faf50e0 | 969 | self.mc.cat_def(closure_hir_id, closure_span, var_ty, upvar.def) |
1a4d82fc JJ |
970 | } |
971 | } | |
972 | ||
041b39d2 | 973 | fn copy_or_move<'a, 'gcx, 'tcx>(mc: &mc::MemCategorizationContext<'a, 'gcx, 'tcx>, |
7cac9316 | 974 | param_env: ty::ParamEnv<'tcx>, |
83c7162d | 975 | cmt: &mc::cmt_<'tcx>, |
a7813a04 XL |
976 | move_reason: MoveReason) |
977 | -> ConsumeMode | |
1a4d82fc | 978 | { |
0731742a | 979 | if !mc.type_is_copy_modulo_regions(param_env, cmt.ty, cmt.span) { |
1a4d82fc JJ |
980 | Move(move_reason) |
981 | } else { | |
982 | Copy | |
983 | } | |
984 | } |