1 use crate::util
::elaborate_drops
::DropFlagState
;
2 use rustc
::mir
::{self, Body, Location}
;
3 use rustc
::ty
::{self, TyCtxt}
;
5 use super::indexes
::MovePathIndex
;
6 use super::move_paths
::{InitKind, LookupResult, MoveData}
;
7 use super::MoveDataParamEnv
;
9 pub fn move_path_children_matching
<'tcx
, F
>(
10 move_data
: &MoveData
<'tcx
>,
13 ) -> Option
<MovePathIndex
>
15 F
: FnMut(&mir
::PlaceElem
<'tcx
>) -> bool
,
17 let mut next_child
= move_data
.move_paths
[path
].first_child
;
18 while let Some(child_index
) = next_child
{
19 let move_path_children
= &move_data
.move_paths
[child_index
];
20 if let Some(elem
) = move_path_children
.place
.projection
.last() {
22 return Some(child_index
);
25 next_child
= move_path_children
.next_sibling
;
31 /// When enumerating the child fragments of a path, don't recurse into
32 /// paths (1.) past arrays, slices, and pointers, nor (2.) into a type
33 /// that implements `Drop`.
35 /// Places behind references or arrays are not tracked by elaboration
36 /// and are always assumed to be initialized when accessible. As
37 /// references and indexes can be reseated, trying to track them can
38 /// only lead to trouble.
40 /// Places behind ADT's with a Drop impl are not tracked by
41 /// elaboration since they can never have a drop-flag state that
42 /// differs from that of the parent with the Drop impl.
44 /// In both cases, the contents can only be accessed if and only if
45 /// their parents are initialized. This implies for example that there
46 /// is no need to maintain separate drop flags to track such state.
48 // FIXME: we have to do something for moving slice patterns.
49 fn place_contents_drop_state_cannot_differ
<'tcx
>(
52 place
: &mir
::Place
<'tcx
>,
54 let ty
= place
.ty(body
, tcx
).ty
;
58 "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
63 ty
::Slice(..) | ty
::Ref(..) | ty
::RawPtr(..) => {
65 "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
70 ty
::Adt(def
, _
) if (def
.has_dtor(tcx
) && !def
.is_box()) || def
.is_union() => {
72 "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} Drop => true",
81 pub(crate) fn on_lookup_result_bits
<'tcx
, F
>(
84 move_data
: &MoveData
<'tcx
>,
85 lookup_result
: LookupResult
,
88 F
: FnMut(MovePathIndex
),
91 LookupResult
::Parent(..) => {
92 // access to untracked value - do not touch children
94 LookupResult
::Exact(e
) => on_all_children_bits(tcx
, body
, move_data
, e
, each_child
),
98 pub(crate) fn on_all_children_bits
<'tcx
, F
>(
101 move_data
: &MoveData
<'tcx
>,
102 move_path_index
: MovePathIndex
,
105 F
: FnMut(MovePathIndex
),
107 fn is_terminal_path
<'tcx
>(
110 move_data
: &MoveData
<'tcx
>,
113 place_contents_drop_state_cannot_differ(tcx
, body
, &move_data
.move_paths
[path
].place
)
116 fn on_all_children_bits
<'tcx
, F
>(
119 move_data
: &MoveData
<'tcx
>,
120 move_path_index
: MovePathIndex
,
123 F
: FnMut(MovePathIndex
),
125 each_child(move_path_index
);
127 if is_terminal_path(tcx
, body
, move_data
, move_path_index
) {
131 let mut next_child_index
= move_data
.move_paths
[move_path_index
].first_child
;
132 while let Some(child_index
) = next_child_index
{
133 on_all_children_bits(tcx
, body
, move_data
, child_index
, each_child
);
134 next_child_index
= move_data
.move_paths
[child_index
].next_sibling
;
137 on_all_children_bits(tcx
, body
, move_data
, move_path_index
, &mut each_child
);
140 pub(crate) fn on_all_drop_children_bits
<'tcx
, F
>(
143 ctxt
: &MoveDataParamEnv
<'tcx
>,
147 F
: FnMut(MovePathIndex
),
149 on_all_children_bits(tcx
, body
, &ctxt
.move_data
, path
, |child
| {
150 let place
= &ctxt
.move_data
.move_paths
[path
].place
;
151 let ty
= place
.ty(body
, tcx
).ty
;
152 debug
!("on_all_drop_children_bits({:?}, {:?} : {:?})", path
, place
, ty
);
154 let erased_ty
= tcx
.erase_regions(&ty
);
155 if erased_ty
.needs_drop(tcx
, ctxt
.param_env
) {
158 debug
!("on_all_drop_children_bits - skipping")
163 pub(crate) fn drop_flag_effects_for_function_entry
<'tcx
, F
>(
166 ctxt
: &MoveDataParamEnv
<'tcx
>,
169 F
: FnMut(MovePathIndex
, DropFlagState
),
171 let move_data
= &ctxt
.move_data
;
172 for arg
in body
.args_iter() {
173 let place
= mir
::Place
::from(arg
);
174 let lookup_result
= move_data
.rev_lookup
.find(place
.as_ref());
175 on_lookup_result_bits(tcx
, body
, move_data
, lookup_result
, |mpi
| {
176 callback(mpi
, DropFlagState
::Present
)
181 pub(crate) fn drop_flag_effects_for_location
<'tcx
, F
>(
184 ctxt
: &MoveDataParamEnv
<'tcx
>,
188 F
: FnMut(MovePathIndex
, DropFlagState
),
190 let move_data
= &ctxt
.move_data
;
191 debug
!("drop_flag_effects_for_location({:?})", loc
);
193 // first, move out of the RHS
194 for mi
in &move_data
.loc_map
[loc
] {
195 let path
= mi
.move_path_index(move_data
);
196 debug
!("moving out of path {:?}", move_data
.move_paths
[path
]);
198 on_all_children_bits(tcx
, body
, move_data
, path
, |mpi
| callback(mpi
, DropFlagState
::Absent
))
201 debug
!("drop_flag_effects: assignment for location({:?})", loc
);
203 for_location_inits(tcx
, body
, move_data
, loc
, |mpi
| callback(mpi
, DropFlagState
::Present
));
206 pub(crate) fn for_location_inits
<'tcx
, F
>(
209 move_data
: &MoveData
<'tcx
>,
213 F
: FnMut(MovePathIndex
),
215 for ii
in &move_data
.init_loc_map
[loc
] {
216 let init
= move_data
.inits
[*ii
];
219 let path
= init
.path
;
221 on_all_children_bits(tcx
, body
, move_data
, path
, &mut callback
)
223 InitKind
::Shallow
=> {
227 InitKind
::NonPanicPathOnly
=> (),