]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | // Copyright 2012-2013 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 | ||
11 | //! Computes moves. | |
12 | ||
13 | use borrowck::*; | |
14 | use borrowck::gather_loans::move_error::MoveSpanAndPath; | |
15 | use borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector}; | |
16 | use borrowck::move_data::*; | |
17 | use rustc::middle::expr_use_visitor as euv; | |
18 | use rustc::middle::mem_categorization as mc; | |
92a42be0 | 19 | use rustc::middle::mem_categorization::Categorization; |
85aaf69f | 20 | use rustc::middle::mem_categorization::InteriorOffsetKind as Kind; |
54a0048b | 21 | use rustc::ty; |
62682a34 | 22 | |
1a4d82fc JJ |
23 | use std::rc::Rc; |
24 | use syntax::ast; | |
25 | use syntax::codemap::Span; | |
54a0048b | 26 | use rustc::hir::{self, PatKind}; |
1a4d82fc JJ |
27 | |
28 | struct GatherMoveInfo<'tcx> { | |
29 | id: ast::NodeId, | |
30 | kind: MoveKind, | |
31 | cmt: mc::cmt<'tcx>, | |
32 | span_path_opt: Option<MoveSpanAndPath> | |
33 | } | |
34 | ||
35 | pub fn gather_decl<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
36 | move_data: &MoveData<'tcx>, | |
37 | decl_id: ast::NodeId, | |
38 | _decl_span: Span, | |
39 | var_id: ast::NodeId) { | |
c1a9b12d | 40 | let ty = bccx.tcx.node_id_to_type(var_id); |
1a4d82fc JJ |
41 | let loan_path = Rc::new(LoanPath::new(LpVar(var_id), ty)); |
42 | move_data.add_move(bccx.tcx, loan_path, decl_id, Declared); | |
43 | } | |
44 | ||
45 | pub fn gather_move_from_expr<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
46 | move_data: &MoveData<'tcx>, | |
92a42be0 | 47 | move_error_collector: &mut MoveErrorCollector<'tcx>, |
1a4d82fc JJ |
48 | move_expr_id: ast::NodeId, |
49 | cmt: mc::cmt<'tcx>, | |
50 | move_reason: euv::MoveReason) { | |
51 | let kind = match move_reason { | |
52 | euv::DirectRefMove | euv::PatBindingMove => MoveExpr, | |
53 | euv::CaptureMove => Captured | |
54 | }; | |
55 | let move_info = GatherMoveInfo { | |
56 | id: move_expr_id, | |
57 | kind: kind, | |
58 | cmt: cmt, | |
59 | span_path_opt: None, | |
60 | }; | |
61 | gather_move(bccx, move_data, move_error_collector, move_info); | |
62 | } | |
63 | ||
64 | pub fn gather_match_variant<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
65 | move_data: &MoveData<'tcx>, | |
92a42be0 | 66 | _move_error_collector: &mut MoveErrorCollector<'tcx>, |
e9174d1e | 67 | move_pat: &hir::Pat, |
1a4d82fc JJ |
68 | cmt: mc::cmt<'tcx>, |
69 | mode: euv::MatchMode) { | |
70 | let tcx = bccx.tcx; | |
62682a34 SL |
71 | debug!("gather_match_variant(move_pat={}, cmt={:?}, mode={:?})", |
72 | move_pat.id, cmt, mode); | |
1a4d82fc JJ |
73 | |
74 | let opt_lp = opt_loan_path(&cmt); | |
75 | match opt_lp { | |
76 | Some(lp) => { | |
77 | match lp.kind { | |
78 | LpDowncast(ref base_lp, _) => | |
79 | move_data.add_variant_match( | |
80 | tcx, lp.clone(), move_pat.id, base_lp.clone(), mode), | |
54a0048b SL |
81 | _ => bug!("should only call gather_match_variant \ |
82 | for cat_downcast cmt"), | |
1a4d82fc JJ |
83 | } |
84 | } | |
85 | None => { | |
86 | // We get None when input to match is non-path (e.g. | |
87 | // temporary result like a function call). Since no | |
88 | // loan-path is being matched, no need to record a | |
89 | // downcast. | |
90 | return; | |
91 | } | |
92 | } | |
93 | } | |
94 | ||
95 | pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
96 | move_data: &MoveData<'tcx>, | |
92a42be0 | 97 | move_error_collector: &mut MoveErrorCollector<'tcx>, |
e9174d1e | 98 | move_pat: &hir::Pat, |
1a4d82fc JJ |
99 | cmt: mc::cmt<'tcx>) { |
100 | let pat_span_path_opt = match move_pat.node { | |
7453a54e | 101 | PatKind::Ident(_, ref path1, _) => { |
1a4d82fc | 102 | Some(MoveSpanAndPath{span: move_pat.span, |
b039eaaf | 103 | name: path1.node.name}) |
1a4d82fc JJ |
104 | }, |
105 | _ => None, | |
106 | }; | |
107 | let move_info = GatherMoveInfo { | |
108 | id: move_pat.id, | |
109 | kind: MovePat, | |
110 | cmt: cmt, | |
111 | span_path_opt: pat_span_path_opt, | |
112 | }; | |
113 | gather_move(bccx, move_data, move_error_collector, move_info); | |
114 | } | |
115 | ||
116 | fn gather_move<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
117 | move_data: &MoveData<'tcx>, | |
92a42be0 | 118 | move_error_collector: &mut MoveErrorCollector<'tcx>, |
1a4d82fc | 119 | move_info: GatherMoveInfo<'tcx>) { |
62682a34 SL |
120 | debug!("gather_move(move_id={}, cmt={:?})", |
121 | move_info.id, move_info.cmt); | |
1a4d82fc JJ |
122 | |
123 | let potentially_illegal_move = | |
124 | check_and_get_illegal_move_origin(bccx, &move_info.cmt); | |
125 | match potentially_illegal_move { | |
126 | Some(illegal_move_origin) => { | |
62682a34 | 127 | debug!("illegal_move_origin={:?}", illegal_move_origin); |
1a4d82fc JJ |
128 | let error = MoveError::with_move_info(illegal_move_origin, |
129 | move_info.span_path_opt); | |
130 | move_error_collector.add_error(error); | |
131 | return | |
132 | } | |
133 | None => () | |
134 | } | |
135 | ||
136 | match opt_loan_path(&move_info.cmt) { | |
137 | Some(loan_path) => { | |
138 | move_data.add_move(bccx.tcx, loan_path, | |
139 | move_info.id, move_info.kind); | |
140 | } | |
141 | None => { | |
62682a34 | 142 | // move from rvalue or raw pointer, hence ok |
1a4d82fc JJ |
143 | } |
144 | } | |
145 | } | |
146 | ||
147 | pub fn gather_assignment<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, | |
148 | move_data: &MoveData<'tcx>, | |
149 | assignment_id: ast::NodeId, | |
150 | assignment_span: Span, | |
151 | assignee_loan_path: Rc<LoanPath<'tcx>>, | |
152 | assignee_id: ast::NodeId, | |
153 | mode: euv::MutateMode) { | |
154 | move_data.add_assignment(bccx.tcx, | |
155 | assignee_loan_path, | |
156 | assignment_id, | |
157 | assignment_span, | |
158 | assignee_id, | |
159 | mode); | |
160 | } | |
161 | ||
85aaf69f | 162 | // (keep in sync with move_error::report_cannot_move_out_of ) |
1a4d82fc JJ |
163 | fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, |
164 | cmt: &mc::cmt<'tcx>) | |
165 | -> Option<mc::cmt<'tcx>> { | |
166 | match cmt.cat { | |
92a42be0 SL |
167 | Categorization::Deref(_, _, mc::BorrowedPtr(..)) | |
168 | Categorization::Deref(_, _, mc::Implicit(..)) | | |
169 | Categorization::Deref(_, _, mc::UnsafePtr(..)) | | |
170 | Categorization::StaticItem => { | |
1a4d82fc JJ |
171 | Some(cmt.clone()) |
172 | } | |
173 | ||
92a42be0 SL |
174 | Categorization::Rvalue(..) | |
175 | Categorization::Local(..) | | |
176 | Categorization::Upvar(..) => { | |
1a4d82fc JJ |
177 | None |
178 | } | |
179 | ||
92a42be0 SL |
180 | Categorization::Downcast(ref b, _) | |
181 | Categorization::Interior(ref b, mc::InteriorField(_)) | | |
182 | Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => { | |
1a4d82fc | 183 | match b.ty.sty { |
e9174d1e SL |
184 | ty::TyStruct(def, _) | ty::TyEnum(def, _) => { |
185 | if def.has_dtor() { | |
1a4d82fc JJ |
186 | Some(cmt.clone()) |
187 | } else { | |
188 | check_and_get_illegal_move_origin(bccx, b) | |
189 | } | |
190 | } | |
191 | _ => { | |
192 | check_and_get_illegal_move_origin(bccx, b) | |
193 | } | |
194 | } | |
195 | } | |
196 | ||
92a42be0 | 197 | Categorization::Interior(_, mc::InteriorElement(Kind::Index, _)) => { |
85aaf69f SL |
198 | // Forbid move of arr[i] for arr: [T; 3]; see RFC 533. |
199 | Some(cmt.clone()) | |
200 | } | |
201 | ||
92a42be0 | 202 | Categorization::Deref(ref b, _, mc::Unique) => { |
1a4d82fc JJ |
203 | check_and_get_illegal_move_origin(bccx, b) |
204 | } | |
205 | } | |
206 | } |