]> git.proxmox.com Git - rustc.git/blame - src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / librustc_borrowck / borrowck / gather_loans / gather_moves.rs
CommitLineData
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
13use borrowck::*;
14use borrowck::gather_loans::move_error::MoveSpanAndPath;
15use borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector};
16use borrowck::move_data::*;
17use rustc::middle::expr_use_visitor as euv;
18use rustc::middle::mem_categorization as mc;
92a42be0 19use rustc::middle::mem_categorization::Categorization;
85aaf69f 20use rustc::middle::mem_categorization::InteriorOffsetKind as Kind;
54a0048b 21use rustc::ty;
62682a34 22
1a4d82fc
JJ
23use std::rc::Rc;
24use syntax::ast;
3157f602 25use syntax_pos::Span;
54a0048b 26use rustc::hir::{self, PatKind};
1a4d82fc
JJ
27
28struct GatherMoveInfo<'tcx> {
29 id: ast::NodeId,
30 kind: MoveKind,
31 cmt: mc::cmt<'tcx>,
32 span_path_opt: Option<MoveSpanAndPath>
33}
34
35pub 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) {
c30ab7b3 40 let ty = bccx.tcx.tables().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
45pub 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
64pub 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
95pub 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 {
3157f602 101 PatKind::Binding(_, ref path1, _) => {
1a4d82fc 102 Some(MoveSpanAndPath{span: move_pat.span,
a7813a04 103 name: path1.node})
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
116fn 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);
3157f602
XL
125 if let Some(illegal_move_origin) = potentially_illegal_move {
126 debug!("illegal_move_origin={:?}", illegal_move_origin);
127 let error = MoveError::with_move_info(illegal_move_origin,
128 move_info.span_path_opt);
129 move_error_collector.add_error(error);
130 return;
1a4d82fc
JJ
131 }
132
133 match opt_loan_path(&move_info.cmt) {
134 Some(loan_path) => {
135 move_data.add_move(bccx.tcx, loan_path,
136 move_info.id, move_info.kind);
137 }
138 None => {
62682a34 139 // move from rvalue or raw pointer, hence ok
1a4d82fc
JJ
140 }
141 }
142}
143
144pub fn gather_assignment<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
145 move_data: &MoveData<'tcx>,
146 assignment_id: ast::NodeId,
147 assignment_span: Span,
148 assignee_loan_path: Rc<LoanPath<'tcx>>,
149 assignee_id: ast::NodeId,
150 mode: euv::MutateMode) {
151 move_data.add_assignment(bccx.tcx,
152 assignee_loan_path,
153 assignment_id,
154 assignment_span,
155 assignee_id,
156 mode);
157}
158
85aaf69f 159// (keep in sync with move_error::report_cannot_move_out_of )
1a4d82fc
JJ
160fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
161 cmt: &mc::cmt<'tcx>)
162 -> Option<mc::cmt<'tcx>> {
163 match cmt.cat {
9e0c209e
SL
164 Categorization::Deref(.., mc::BorrowedPtr(..)) |
165 Categorization::Deref(.., mc::Implicit(..)) |
166 Categorization::Deref(.., mc::UnsafePtr(..)) |
92a42be0 167 Categorization::StaticItem => {
1a4d82fc
JJ
168 Some(cmt.clone())
169 }
170
92a42be0
SL
171 Categorization::Rvalue(..) |
172 Categorization::Local(..) |
173 Categorization::Upvar(..) => {
1a4d82fc
JJ
174 None
175 }
176
92a42be0
SL
177 Categorization::Downcast(ref b, _) |
178 Categorization::Interior(ref b, mc::InteriorField(_)) |
179 Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
1a4d82fc 180 match b.ty.sty {
9e0c209e 181 ty::TyAdt(def, _) => {
e9174d1e 182 if def.has_dtor() {
1a4d82fc
JJ
183 Some(cmt.clone())
184 } else {
185 check_and_get_illegal_move_origin(bccx, b)
186 }
187 }
9e0c209e 188 ty::TySlice(..) => Some(cmt.clone()),
1a4d82fc
JJ
189 _ => {
190 check_and_get_illegal_move_origin(bccx, b)
191 }
192 }
193 }
194
92a42be0 195 Categorization::Interior(_, mc::InteriorElement(Kind::Index, _)) => {
85aaf69f
SL
196 // Forbid move of arr[i] for arr: [T; 3]; see RFC 533.
197 Some(cmt.clone())
198 }
199
92a42be0 200 Categorization::Deref(ref b, _, mc::Unique) => {
1a4d82fc
JJ
201 check_and_get_illegal_move_origin(bccx, b)
202 }
203 }
204}