Skip to content

Commit e78fac5

Browse files
committed
Handle the case of partially captured drop type
1 parent f2e52ff commit e78fac5

File tree

1 file changed

+23
-19
lines changed

1 file changed

+23
-19
lines changed

compiler/rustc_typeck/src/check/upvar.rs

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
639639
/// `w[c]`.
640640
/// Notation:
641641
/// - Ty(place): Type of place
642-
/// - `(a, b)`: Represents the function parameters `base_path_ty` and `captured_projs`
642+
/// - `(a, b)`: Represents the function parameters `base_path_ty` and `captured_by_move_projs`
643643
/// respectively.
644644
/// ```
645645
/// (Ty(w), [ &[p, x], &[c] ])
@@ -700,7 +700,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
700700
closure_def_id: DefId,
701701
closure_span: Span,
702702
base_path_ty: Ty<'tcx>,
703-
captured_projs: Vec<&[Projection<'tcx>]>,
703+
captured_by_move_projs: Vec<&[Projection<'tcx>]>,
704704
) -> bool {
705705
let needs_drop = |ty: Ty<'tcx>| {
706706
ty.needs_drop(self.tcx, self.tcx.param_env(closure_def_id.expect_local()))
@@ -725,33 +725,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
725725
//
726726
// eg. If `a.b` is captured and we are processing `a.b`, then we can't have the closure also
727727
// capture `a.b.c`, because that voilates min capture.
728-
let is_completely_captured = captured_projs.iter().any(|projs| projs.is_empty());
728+
let is_completely_captured = captured_by_move_projs.iter().any(|projs| projs.is_empty());
729729

730-
assert!(!is_completely_captured || (captured_projs.len() == 1));
730+
assert!(!is_completely_captured || (captured_by_move_projs.len() == 1));
731731

732732
if is_completely_captured {
733733
// The place is captured entirely, so doesn't matter if needs dtor, it will be drop
734734
// when the closure is dropped.
735735
return false;
736736
}
737737

738+
if captured_by_move_projs.is_empty() {
739+
return needs_drop(base_path_ty);
740+
}
741+
738742
if is_drop_defined_for_ty {
739743
// If drop is implemented for this type then we need it to be fully captured,
740-
// which we know it is not because of the previous check. Therefore we need to
741-
// do migrate.
742-
return true;
743-
}
744+
// and we know it is not completely captured because of the previous checks.
744745

745-
if captured_projs.is_empty() {
746-
return needs_drop(base_path_ty);
746+
// Note that this is a bug in the user code that will be reported by the
747+
// borrow checker, since we can't move out of drop types.
748+
749+
// The bug exists in the user's code pre-migration, and we don't migrate here.
750+
return false;
747751
}
748752

749753
match base_path_ty.kind() {
750754
// Observations:
751-
// - `captured_projs` is not empty. Therefore we can call
752-
// `captured_projs.first().unwrap()` safely.
753-
// - All entries in `captured_projs` have atleast one projection.
754-
// Therefore we can call `captured_projs.first().unwrap().first().unwrap()` safely.
755+
// - `captured_by_move_projs` is not empty. Therefore we can call
756+
// `captured_by_move_projs.first().unwrap()` safely.
757+
// - All entries in `captured_by_move_projs` have atleast one projection.
758+
// Therefore we can call `captured_by_move_projs.first().unwrap().first().unwrap()` safely.
755759

756760
// We don't capture derefs in case of move captures, which would have be applied to
757761
// access any further paths.
@@ -761,19 +765,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
761765

762766
ty::Adt(def, substs) => {
763767
// Multi-varaint enums are captured in entirety,
764-
// which would've been handled in the case of single empty slice in `captured_projs`.
768+
// which would've been handled in the case of single empty slice in `captured_by_move_projs`.
765769
assert_eq!(def.variants.len(), 1);
766770

767771
// Only Field projections can be applied to a non-box Adt.
768772
assert!(
769-
captured_projs.iter().all(|projs| matches!(
773+
captured_by_move_projs.iter().all(|projs| matches!(
770774
projs.first().unwrap().kind,
771775
ProjectionKind::Field(..)
772776
))
773777
);
774778
def.variants.get(VariantIdx::new(0)).unwrap().fields.iter().enumerate().any(
775779
|(i, field)| {
776-
let paths_using_field = captured_projs
780+
let paths_using_field = captured_by_move_projs
777781
.iter()
778782
.filter_map(|projs| {
779783
if let ProjectionKind::Field(field_idx, _) =
@@ -800,14 +804,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
800804
ty::Tuple(..) => {
801805
// Only Field projections can be applied to a tuple.
802806
assert!(
803-
captured_projs.iter().all(|projs| matches!(
807+
captured_by_move_projs.iter().all(|projs| matches!(
804808
projs.first().unwrap().kind,
805809
ProjectionKind::Field(..)
806810
))
807811
);
808812

809813
base_path_ty.tuple_fields().enumerate().any(|(i, element_ty)| {
810-
let paths_using_field = captured_projs
814+
let paths_using_field = captured_by_move_projs
811815
.iter()
812816
.filter_map(|projs| {
813817
if let ProjectionKind::Field(field_idx, _) = projs.first().unwrap().kind

0 commit comments

Comments
 (0)