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.
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
::InteriorOffsetKind
as Kind
;
20 use rustc
::middle
::ty
;
24 use syntax
::codemap
::Span
;
26 struct GatherMoveInfo
<'tcx
> {
30 span_path_opt
: Option
<MoveSpanAndPath
>
33 pub fn gather_decl
<'a
, 'tcx
>(bccx
: &BorrowckCtxt
<'a
, 'tcx
>,
34 move_data
: &MoveData
<'tcx
>,
37 var_id
: ast
::NodeId
) {
38 let ty
= bccx
.tcx
.node_id_to_type(var_id
);
39 let loan_path
= Rc
::new(LoanPath
::new(LpVar(var_id
), ty
));
40 move_data
.add_move(bccx
.tcx
, loan_path
, decl_id
, Declared
);
43 pub fn gather_move_from_expr
<'a
, 'tcx
>(bccx
: &BorrowckCtxt
<'a
, 'tcx
>,
44 move_data
: &MoveData
<'tcx
>,
45 move_error_collector
: &MoveErrorCollector
<'tcx
>,
46 move_expr_id
: ast
::NodeId
,
48 move_reason
: euv
::MoveReason
) {
49 let kind
= match move_reason
{
50 euv
::DirectRefMove
| euv
::PatBindingMove
=> MoveExpr
,
51 euv
::CaptureMove
=> Captured
53 let move_info
= GatherMoveInfo
{
59 gather_move(bccx
, move_data
, move_error_collector
, move_info
);
62 pub fn gather_match_variant
<'a
, 'tcx
>(bccx
: &BorrowckCtxt
<'a
, 'tcx
>,
63 move_data
: &MoveData
<'tcx
>,
64 _move_error_collector
: &MoveErrorCollector
<'tcx
>,
67 mode
: euv
::MatchMode
) {
69 debug
!("gather_match_variant(move_pat={}, cmt={:?}, mode={:?})",
70 move_pat
.id
, cmt
, mode
);
72 let opt_lp
= opt_loan_path(&cmt
);
76 LpDowncast(ref base_lp
, _
) =>
77 move_data
.add_variant_match(
78 tcx
, lp
.clone(), move_pat
.id
, base_lp
.clone(), mode
),
79 _
=> panic
!("should only call gather_match_variant \
80 for cat_downcast cmt"),
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
93 pub fn gather_move_from_pat
<'a
, 'tcx
>(bccx
: &BorrowckCtxt
<'a
, 'tcx
>,
94 move_data
: &MoveData
<'tcx
>,
95 move_error_collector
: &MoveErrorCollector
<'tcx
>,
98 let pat_span_path_opt
= match move_pat
.node
{
99 ast
::PatIdent(_
, ref path1
, _
) => {
100 Some(MoveSpanAndPath
{span
: move_pat
.span
,
105 let move_info
= GatherMoveInfo
{
109 span_path_opt
: pat_span_path_opt
,
111 gather_move(bccx
, move_data
, move_error_collector
, move_info
);
114 fn gather_move
<'a
, 'tcx
>(bccx
: &BorrowckCtxt
<'a
, 'tcx
>,
115 move_data
: &MoveData
<'tcx
>,
116 move_error_collector
: &MoveErrorCollector
<'tcx
>,
117 move_info
: GatherMoveInfo
<'tcx
>) {
118 debug
!("gather_move(move_id={}, cmt={:?})",
119 move_info
.id
, move_info
.cmt
);
121 let potentially_illegal_move
=
122 check_and_get_illegal_move_origin(bccx
, &move_info
.cmt
);
123 match potentially_illegal_move
{
124 Some(illegal_move_origin
) => {
125 debug
!("illegal_move_origin={:?}", illegal_move_origin
);
126 let error
= MoveError
::with_move_info(illegal_move_origin
,
127 move_info
.span_path_opt
);
128 move_error_collector
.add_error(error
);
134 match opt_loan_path(&move_info
.cmt
) {
136 move_data
.add_move(bccx
.tcx
, loan_path
,
137 move_info
.id
, move_info
.kind
);
140 // move from rvalue or raw pointer, hence ok
145 pub fn gather_assignment
<'a
, 'tcx
>(bccx
: &BorrowckCtxt
<'a
, 'tcx
>,
146 move_data
: &MoveData
<'tcx
>,
147 assignment_id
: ast
::NodeId
,
148 assignment_span
: Span
,
149 assignee_loan_path
: Rc
<LoanPath
<'tcx
>>,
150 assignee_id
: ast
::NodeId
,
151 mode
: euv
::MutateMode
) {
152 move_data
.add_assignment(bccx
.tcx
,
160 // (keep in sync with move_error::report_cannot_move_out_of )
161 fn check_and_get_illegal_move_origin
<'a
, 'tcx
>(bccx
: &BorrowckCtxt
<'a
, 'tcx
>,
163 -> Option
<mc
::cmt
<'tcx
>> {
165 mc
::cat_deref(_
, _
, mc
::BorrowedPtr(..)) |
166 mc
::cat_deref(_
, _
, mc
::Implicit(..)) |
167 mc
::cat_deref(_
, _
, mc
::UnsafePtr(..)) |
168 mc
::cat_static_item
=> {
174 mc
::cat_upvar(..) => {
178 mc
::cat_downcast(ref b
, _
) |
179 mc
::cat_interior(ref b
, mc
::InteriorField(_
)) |
180 mc
::cat_interior(ref b
, mc
::InteriorElement(Kind
::Pattern
, _
)) => {
182 ty
::TyStruct(did
, _
) | ty
::TyEnum(did
, _
) => {
183 if bccx
.tcx
.has_dtor(did
) {
186 check_and_get_illegal_move_origin(bccx
, b
)
190 check_and_get_illegal_move_origin(bccx
, b
)
195 mc
::cat_interior(_
, mc
::InteriorElement(Kind
::Index
, _
)) => {
196 // Forbid move of arr[i] for arr: [T; 3]; see RFC 533.
200 mc
::cat_deref(ref b
, _
, mc
::Unique
) => {
201 check_and_get_illegal_move_origin(bccx
, b
)