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.
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.
15 use middle::borrowck::*;
16 use middle::borrowck::gather_loans::move_error::MoveSpanAndPath;
17 use middle::borrowck::gather_loans::move_error::{MoveError, MoveErrorCollector};
18 use middle::borrowck::move_data::*;
19 use middle::expr_use_visitor as euv;
20 use middle::mem_categorization as mc;
23 use syntax::codemap::Span;
24 use util::ppaux::Repr;
28 struct GatherMoveInfo {
32 span_path_opt: Option<MoveSpanAndPath>
35 pub fn gather_decl(bccx: &BorrowckCtxt,
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);
44 pub fn gather_move_from_expr(bccx: &BorrowckCtxt,
46 move_error_collector: &MoveErrorCollector,
47 move_expr_id: ast::NodeId,
49 move_reason: euv::MoveReason) {
50 let kind = match move_reason {
51 euv::DirectRefMove | euv::PatBindingMove => MoveExpr,
52 euv::CaptureMove => Captured
54 let move_info = GatherMoveInfo {
60 gather_move(bccx, move_data, move_error_collector, move_info);
63 pub fn gather_move_from_pat(bccx: &BorrowckCtxt,
65 move_error_collector: &MoveErrorCollector,
68 let pat_span_path_opt = match move_pat.node {
69 ast::PatIdent(_, ref path1, _) => {
70 Some(MoveSpanAndPath{span: move_pat.span,
75 let move_info = GatherMoveInfo {
79 span_path_opt: pat_span_path_opt,
81 gather_move(bccx, move_data, move_error_collector, move_info);
84 fn gather_move(bccx: &BorrowckCtxt,
86 move_error_collector: &MoveErrorCollector,
87 move_info: GatherMoveInfo) {
88 debug!("gather_move(move_id={}, cmt={})",
89 move_info.id, move_info.cmt.repr(bccx.tcx));
91 let potentially_illegal_move =
92 check_and_get_illegal_move_origin(bccx, &move_info.cmt);
93 match potentially_illegal_move {
94 Some(illegal_move_origin) => {
95 debug!("illegal_move_origin={}", illegal_move_origin.repr(bccx.tcx));
96 let error = MoveError::with_move_info(illegal_move_origin,
97 move_info.span_path_opt);
98 move_error_collector.add_error(error);
104 match opt_loan_path(&move_info.cmt) {
106 move_data.add_move(bccx.tcx, loan_path,
107 move_info.id, move_info.kind);
110 // move from rvalue or unsafe pointer, hence ok
115 pub fn gather_assignment(bccx: &BorrowckCtxt,
116 move_data: &MoveData,
117 assignment_id: ast::NodeId,
118 assignment_span: Span,
119 assignee_loan_path: Rc<LoanPath>,
120 assignee_id: ast::NodeId,
121 mode: euv::MutateMode) {
122 move_data.add_assignment(bccx.tcx,
130 fn check_and_get_illegal_move_origin(bccx: &BorrowckCtxt,
131 cmt: &mc::cmt) -> Option<mc::cmt> {
133 mc::cat_deref(_, _, mc::BorrowedPtr(..)) |
134 mc::cat_deref(_, _, mc::Implicit(..)) |
135 mc::cat_deref(_, _, mc::GcPtr) |
136 mc::cat_deref(_, _, mc::UnsafePtr(..)) |
137 mc::cat_upvar(..) | mc::cat_static_item |
138 mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Many, .. }) => {
142 // Can move out of captured upvars only if the destination closure
143 // type is 'once'. 1-shot stack closures emit the copied_upvar form
144 // (see mem_categorization.rs).
145 mc::cat_copied_upvar(mc::CopiedUpvar { onceness: ast::Once, .. }) => {
155 mc::cat_downcast(ref b) |
156 mc::cat_interior(ref b, _) => {
157 match ty::get(b.ty).sty {
158 ty::ty_struct(did, _) | ty::ty_enum(did, _) => {
159 if ty::has_dtor(bccx.tcx, did) {
162 check_and_get_illegal_move_origin(bccx, b)
166 check_and_get_illegal_move_origin(bccx, b)
171 mc::cat_deref(ref b, _, mc::OwnedPtr) |
172 mc::cat_discr(ref b, _) => {
173 check_and_get_illegal_move_origin(bccx, b)