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 /*!
12 * Computes moves.
13 */
14
15 use mc = middle::mem_categorization;
16 use middle::borrowck::*;
17 use middle::borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector};
18 use middle::borrowck::gather_loans::move_error::MoveSpanAndPath;
19 use middle::borrowck::move_data::*;
20 use euv = middle::expr_use_visitor;
21 use middle::ty;
22 use syntax::ast;
23 use syntax::codemap::Span;
24 use util::ppaux::Repr;
25
26 use std::rc::Rc;
27
28 struct GatherMoveInfo {
29 id: ast::NodeId,
30 kind: MoveKind,
31 cmt: mc::cmt,
32 span_path_opt: Option<MoveSpanAndPath>
33 }
34
35 pub fn gather_decl(bccx: &BorrowckCtxt,
36 move_data: &MoveData,
37 decl_id: ast::NodeId,
38 _decl_span: Span,
39 var_id: ast::NodeId) {
40 let loan_path = Rc::new(LpVar(var_id));
41 move_data.add_move(bccx.tcx, loan_path, decl_id, Declared);
42 }
43
44 pub fn gather_move_from_expr(bccx: &BorrowckCtxt,
45 move_data: &MoveData,
46 move_error_collector: &MoveErrorCollector,
47 move_expr_id: ast::NodeId,
48 cmt: mc::cmt) {
49 let move_info = GatherMoveInfo {
50 id: move_expr_id,
51 kind: MoveExpr,
52 cmt: cmt,
53 span_path_opt: None,
54 };
55 gather_move(bccx, move_data, move_error_collector, move_info);
56 }
57
58 pub fn gather_move_from_pat(bccx: &BorrowckCtxt,
59 move_data: &MoveData,
60 move_error_collector: &MoveErrorCollector,
61 move_pat: &ast::Pat,
62 cmt: mc::cmt) {
63 let pat_span_path_opt = match move_pat.node {
64 ast::PatIdent(_, ref path, _) => {
65 Some(MoveSpanAndPath::with_span_and_path(move_pat.span,
66 (*path).clone()))
67 },
68 _ => None,
69 };
70 let move_info = GatherMoveInfo {
71 id: move_pat.id,
72 kind: MovePat,
73 cmt: cmt,
74 span_path_opt: pat_span_path_opt,
75 };
76 gather_move(bccx, move_data, move_error_collector, move_info);
77 }
78
79 fn gather_move(bccx: &BorrowckCtxt,
80 move_data: &MoveData,
81 move_error_collector: &MoveErrorCollector,
82 move_info: GatherMoveInfo) {
83 debug!("gather_move(move_id={}, cmt={})",
84 move_info.id, move_info.cmt.repr(bccx.tcx));
85
86 let potentially_illegal_move =
87 check_and_get_illegal_move_origin(bccx, &move_info.cmt);
88 match potentially_illegal_move {
89 Some(illegal_move_origin) => {
90 debug!("illegal_move_origin={}", illegal_move_origin.repr(bccx.tcx));
91 let error = MoveError::with_move_info(illegal_move_origin,
92 move_info.span_path_opt);
93 move_error_collector.add_error(error);
94 return
95 }
96 None => ()
97 }
98
99 match opt_loan_path(&move_info.cmt) {
100 Some(loan_path) => {
101 move_data.add_move(bccx.tcx, loan_path,
102 move_info.id, move_info.kind);
103 }
104 None => {
105 // move from rvalue or unsafe pointer, hence ok
106 }
107 }
108 }
109
110 pub fn gather_assignment(bccx: &BorrowckCtxt,
111 move_data: &MoveData,
112 assignment_id: ast::NodeId,
113 assignment_span: Span,
114 assignee_loan_path: Rc<LoanPath>,
115 assignee_id: ast::NodeId,
116 mode: euv::MutateMode) {
117 move_data.add_assignment(bccx.tcx,
118 assignee_loan_path,
119 assignment_id,
120 assignment_span,
121 assignee_id,
122 mode);
123 }
124
125 fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
126 cmt: &mc::cmt) -> Option<mc::cmt> {
127 match cmt.cat {
128 mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
129 mc::cat_deref(_, _, mc::GcPtr) |
130 mc::cat_deref(_, _, mc::UnsafePtr(..)) |
131 mc::cat_upvar(..) | mc::cat_static_item |
132 mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {
133 Some(cmt.clone())
134 }
135
136 // Can move out of captured upvars only if the destination closure
137 // type is 'once'. 1-shot stack closures emit the copied_upvar form
138 // (see mem_categorization.rs).
139 mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Once, .. }) => {
140 None
141 }
142
143 mc::cat_rvalue(..) |
144 mc::cat_local(..) |
145 mc::cat_arg(..) => {
146 None
147 }
148
149 mc::cat_downcast(ref b) |
150 mc::cat_interior(ref b, _) => {
151 match ty::get(b.ty).sty {
152 ty::ty_struct(did, _) | ty::ty_enum(did, _) => {
153 if ty::has_dtor(bccx.tcx, did) {
154 Some(cmt.clone())
155 } else {
156 check_and_get_illegal_move_origin(bccx, b)
157 }
158 }
159 _ => {
160 check_and_get_illegal_move_origin(bccx, b)
161 }
162 }
163 }
164
165 mc::cat_deref(ref b, _, mc::OwnedPtr) |
166 mc::cat_discr(ref b, _) => {
167 check_and_get_illegal_move_origin(bccx, b)
168 }
169 }
170 }
librustc/middle/borrowck/gather_loans/gather_moves.rs:78:1-78:1 -fn- definition:
fn gather_move(bccx: &BorrowckCtxt,
move_data: &MoveData,
move_error_collector: &MoveErrorCollector,
references:- 275: };
76: gather_move(bccx, move_data, move_error_collector, move_info);
77: }
librustc/middle/borrowck/gather_loans/gather_moves.rs:27:1-27:1 -struct- definition:
struct GatherMoveInfo {
id: ast::NodeId,
kind: MoveKind,
references:- 348: cmt: mc::cmt) {
49: let move_info = GatherMoveInfo {
50: id: move_expr_id,
--
81: move_error_collector: &MoveErrorCollector,
82: move_info: GatherMoveInfo) {
83: debug!("gather_move(move_id={}, cmt={})",
librustc/middle/borrowck/gather_loans/gather_moves.rs:124:1-124:1 -fn- definition:
fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
cmt: &mc::cmt) -> Option<mc::cmt> {
match cmt.cat {
references:- 486: let potentially_illegal_move =
87: check_and_get_illegal_move_origin(bccx, &move_info.cmt);
88: match potentially_illegal_move {
--
155: } else {
156: check_and_get_illegal_move_origin(bccx, b)
157: }
--
166: mc::cat_discr(ref b, _) => {
167: check_and_get_illegal_move_origin(bccx, b)
168: }