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
::Categorization
;
20 use rustc
::middle
::mem_categorization
::InteriorOffsetKind
as Kind
;
21 use rustc
::ty
::{self, Ty}
;
26 use rustc
::hir
::{self, PatKind}
;
28 struct GatherMoveInfo
<'tcx
> {
32 span_path_opt
: Option
<MoveSpanAndPath
>
35 pub fn gather_decl
<'a
, 'tcx
>(bccx
: &BorrowckCtxt
<'a
, 'tcx
>,
36 move_data
: &MoveData
<'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
);
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
,
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
: &mut 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 _
=> bug
!("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
: &mut MoveErrorCollector
<'tcx
>,
98 let pat_span_path_opt
= match move_pat
.node
{
99 PatKind
::Binding(_
, _
, 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
: &mut 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 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
);
131 match opt_loan_path(&move_info
.cmt
) {
133 move_data
.add_move(bccx
.tcx
, loan_path
,
134 move_info
.id
, move_info
.kind
);
137 // move from rvalue or raw pointer, hence ok
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
,
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
>,
160 -> Option
<mc
::cmt
<'tcx
>> {
162 Categorization
::Deref(.., mc
::BorrowedPtr(..)) |
163 Categorization
::Deref(.., mc
::Implicit(..)) |
164 Categorization
::Deref(.., mc
::UnsafePtr(..)) |
165 Categorization
::StaticItem
=> {
169 Categorization
::Rvalue(..) |
170 Categorization
::Local(..) |
171 Categorization
::Upvar(..) => {
175 Categorization
::Downcast(ref b
, _
) |
176 Categorization
::Interior(ref b
, mc
::InteriorField(_
)) |
177 Categorization
::Interior(ref b
, mc
::InteriorElement(Kind
::Pattern
, _
)) => {
179 ty
::TyAdt(def
, _
) => {
180 if def
.has_dtor(bccx
.tcx
) {
183 check_and_get_illegal_move_origin(bccx
, b
)
186 ty
::TySlice(..) => Some(cmt
.clone()),
188 check_and_get_illegal_move_origin(bccx
, b
)
193 Categorization
::Interior(_
, mc
::InteriorElement(Kind
::Index
, _
)) => {
194 // Forbid move of arr[i] for arr: [T; 3]; see RFC 533.
198 Categorization
::Deref(ref b
, _
, mc
::Unique
) => {
199 check_and_get_illegal_move_origin(bccx
, b
)