Skip to content

Commit 5c25145

Browse files
Fix drop elaboration and move analysis for unsafe binders
1 parent 3ccd62d commit 5c25145

File tree

9 files changed

+56
-14
lines changed

9 files changed

+56
-14
lines changed

compiler/rustc_borrowck/src/lib.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1953,13 +1953,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> {
19531953
ProjectionElem::OpaqueCast(_) |
19541954
ProjectionElem::ConstantIndex { .. } |
19551955
// assigning to P[i] requires P to be valid.
1956-
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) |
1957-
ProjectionElem::UnsafeBinderCast(..) =>
1956+
ProjectionElem::Downcast(_/*adt_def*/, _/*variant_idx*/) =>
19581957
// assigning to (P->variant) is okay if assigning to `P` is okay
19591958
//
19601959
// FIXME: is this true even if P is an adt with a dtor?
19611960
{ }
19621961

1962+
ProjectionElem::UnsafeBinderCast(..) => {
1963+
check_parent_of_field(self, location, place_base, span, state);
1964+
}
1965+
19631966
// assigning to (*P) requires P to be initialized
19641967
ProjectionElem::Deref => {
19651968
self.check_if_full_path_is_moved(

compiler/rustc_borrowck/src/prefixes.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,15 @@ impl<'tcx> Iterator for Prefixes<'tcx> {
6666
self.next = Some(cursor_base);
6767
return Some(cursor);
6868
}
69+
ProjectionElem::UnsafeBinderCast(..) => {
70+
self.next = Some(cursor_base);
71+
return Some(cursor);
72+
}
6973
ProjectionElem::Downcast(..)
7074
| ProjectionElem::Subslice { .. }
7175
| ProjectionElem::OpaqueCast { .. }
7276
| ProjectionElem::ConstantIndex { .. }
73-
| ProjectionElem::Index(_)
74-
| ProjectionElem::UnsafeBinderCast(..) => {
77+
| ProjectionElem::Index(_) => {
7578
cursor = cursor_base;
7679
continue 'cursor;
7780
}

compiler/rustc_mir_dataflow/src/elaborate_drops.rs

+23-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{fmt, iter};
22

3+
use rustc_hir::UnsafeBinderCastKind;
34
use rustc_hir::lang_items::LangItem;
45
use rustc_index::Idx;
56
use rustc_middle::mir::patch::MirPatch;
@@ -152,6 +153,11 @@ pub trait DropElaborator<'a, 'tcx>: fmt::Debug {
152153
///
153154
/// This is only relevant for array patterns, which can move out of individual array elements.
154155
fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option<Self::Path>;
156+
157+
/// Returns the subpath of casting an unsafe binder.
158+
///
159+
/// If this returns `None`, elements of `path` will not get a dedicated drop flag.
160+
fn unsafe_binder_subpath(&self, path: Self::Path) -> Option<Self::Path>;
155161
}
156162

157163
#[derive(Debug)]
@@ -847,7 +853,7 @@ where
847853
/// ADT, both in the success case or if one of the destructors fail.
848854
fn open_drop(&mut self) -> BasicBlock {
849855
let ty = self.place_ty(self.place);
850-
match ty.kind() {
856+
match *ty.kind() {
851857
ty::Closure(_, args) => self.open_drop_for_tuple(args.as_closure().upvar_tys()),
852858
ty::CoroutineClosure(_, args) => {
853859
self.open_drop_for_tuple(args.as_coroutine_closure().upvar_tys())
@@ -860,13 +866,26 @@ where
860866
// See librustc_body/transform/coroutine.rs for more details.
861867
ty::Coroutine(_, args) => self.open_drop_for_tuple(args.as_coroutine().upvar_tys()),
862868
ty::Tuple(fields) => self.open_drop_for_tuple(fields),
863-
ty::Adt(def, args) => self.open_drop_for_adt(*def, args),
869+
ty::Adt(def, args) => self.open_drop_for_adt(def, args),
864870
ty::Dynamic(..) => self.complete_drop(self.succ, self.unwind),
865871
ty::Array(ety, size) => {
866872
let size = size.try_eval_target_usize(self.tcx(), self.elaborator.param_env());
867-
self.open_drop_for_array(*ety, size)
873+
self.open_drop_for_array(ety, size)
874+
}
875+
ty::Slice(ety) => self.drop_loop_pair(ety),
876+
ty::UnsafeBinder(binder) => {
877+
let ty = self.tcx().instantiate_bound_regions_with_erased(binder.into());
878+
let fields = vec![(
879+
self.place.project_deeper(
880+
&[ProjectionElem::UnsafeBinderCast(UnsafeBinderCastKind::Unwrap, ty)],
881+
self.tcx(),
882+
),
883+
self.elaborator.unsafe_binder_subpath(self.path),
884+
)];
885+
886+
let (succ, unwind) = self.drop_ladder_bottom();
887+
self.drop_ladder(fields, succ, unwind).0
868888
}
869-
ty::Slice(ety) => self.drop_loop_pair(*ety),
870889

871890
_ => span_bug!(self.source_info.span, "open drop from non-ADT `{:?}`", ty),
872891
}

compiler/rustc_mir_dataflow/src/move_paths/builder.rs

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::mem;
22

3+
use rustc_hir::UnsafeBinderCastKind;
34
use rustc_index::IndexVec;
45
use rustc_middle::mir::tcx::{PlaceTy, RvalueInitializationState};
56
use rustc_middle::mir::*;
@@ -215,7 +216,7 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
215216
| ty::Infer(_)
216217
| ty::Error(_)
217218
| ty::Placeholder(_) => bug!(
218-
"When Place contains ProjectionElem::Field it's type shouldn't be {place_ty:#?}"
219+
"When Place contains ProjectionElem::Field its type shouldn't be {place_ty:#?}"
219220
),
220221
},
221222
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => {
@@ -233,15 +234,18 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> {
233234
}
234235
_ => bug!("Unexpected type {place_ty:#?}"),
235236
},
237+
ProjectionElem::UnsafeBinderCast(UnsafeBinderCastKind::Unwrap, _) => {}
238+
ProjectionElem::UnsafeBinderCast(UnsafeBinderCastKind::Wrap, _) => {
239+
union_path.get_or_insert(base);
240+
}
236241
// `OpaqueCast`:Only transmutes the type, so no moves there.
237242
// `Downcast` :Only changes information about a `Place` without moving.
238243
// `Subtype` :Only transmutes the type, so moves.
239244
// `UnsafeBinderCast`: Only transmutes the place without moving.
240245
// So it's safe to skip these.
241246
ProjectionElem::OpaqueCast(_)
242247
| ProjectionElem::Subtype(_)
243-
| ProjectionElem::Downcast(_, _)
244-
| ProjectionElem::UnsafeBinderCast(_, _) => (),
248+
| ProjectionElem::Downcast(_, _) => (),
245249
}
246250
let elem_ty = PlaceTy::from_ty(place_ty).projection_ty(tcx, elem).ty;
247251
if !(self.filter)(elem_ty) {

compiler/rustc_mir_transform/src/elaborate_drops.rs

+6
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,12 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for ElaborateDropsCtxt<'a, 'tcx> {
226226
})
227227
}
228228

229+
fn unsafe_binder_subpath(&self, path: Self::Path) -> Option<Self::Path> {
230+
rustc_mir_dataflow::move_path_children_matching(self.move_data(), path, |e| {
231+
matches!(e, ProjectionElem::UnsafeBinderCast(..))
232+
})
233+
}
234+
229235
fn get_drop_flag(&mut self, path: Self::Path) -> Option<Operand<'tcx>> {
230236
self.drop_flag(path).map(Operand::Copy)
231237
}

compiler/rustc_mir_transform/src/gvn.rs

+3
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
905905
ProjectionElem::Downcast(symbol, idx) => ProjectionElem::Downcast(symbol, idx),
906906
ProjectionElem::OpaqueCast(idx) => ProjectionElem::OpaqueCast(idx),
907907
ProjectionElem::Subtype(idx) => ProjectionElem::Subtype(idx),
908+
ProjectionElem::UnsafeBinderCast(kind, ty) => {
909+
ProjectionElem::UnsafeBinderCast(kind, ty)
910+
}
908911
})
909912
}
910913

compiler/rustc_mir_transform/src/shim.rs

+3
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,9 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
393393
fn array_subpath(&self, _path: Self::Path, _index: u64, _size: u64) -> Option<Self::Path> {
394394
None
395395
}
396+
fn unsafe_binder_subpath(&self, _path: Self::Path) -> Option<Self::Path> {
397+
None
398+
}
396399
}
397400

398401
fn build_thread_local_shim<'tcx>(

compiler/rustc_trait_selection/src/traits/select/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -2342,8 +2342,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
23422342
| ty::Never
23432343
| ty::Char => ty::Binder::dummy(Vec::new()),
23442344

2345-
// TODO: binder needs opening
2346-
ty::UnsafeBinder(_) => todo!(),
2345+
// FIXME(unsafe_binders): Squash the double binder for now, I guess.
2346+
ty::UnsafeBinder(_) => return Err(SelectionError::Unimplemented),
23472347

23482348
// Treat this like `struct str([u8]);`
23492349
ty::Str => ty::Binder::dummy(vec![Ty::new_slice(self.tcx(), self.tcx().types.u8)]),

compiler/rustc_ty_utils/src/instance.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ fn resolve_instance_raw<'tcx>(
4747
| ty::Adt(..)
4848
| ty::Dynamic(..)
4949
| ty::Array(..)
50-
| ty::Slice(..) => {}
50+
| ty::Slice(..)
51+
| ty::UnsafeBinder(..) => {}
5152
// Drop shims can only be built from ADTs.
5253
_ => return Ok(None),
5354
}

0 commit comments

Comments
 (0)