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