Skip to content

Commit b23d910

Browse files
Skip Drop terminators for enum variants without drop glue
When doing drop elaboration for an `enum` that may or may not be moved out of (an open drop), we check the discriminant of the `enum` to see whether the live variant has any drop flags and then check the drop flags to see whether we need to drop each field. Sometimes, however, the live variant has no move paths. In this case, we still emit a drop terminator for the entire enum after checking the enum discriminant. This commit skips emitting the drop terminator when the "otherwise" variants, those without move paths, have no drop glue. This was frequently the case with `Option`, as the `None` variant has no drop glue and no move path.
1 parent a29424a commit b23d910

File tree

1 file changed

+30
-15
lines changed

1 file changed

+30
-15
lines changed

src/librustc_mir/util/elaborate_drops.rs

+30-15
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,9 @@ where
153153
// FIXME: I think we should just control the flags externally,
154154
// and then we do not need this machinery.
155155
pub fn elaborate_drop(&mut self, bb: BasicBlock) {
156-
debug!("elaborate_drop({:?})", self);
156+
debug!("elaborate_drop({:?}, {:?})", bb, self);
157157
let style = self.elaborator.drop_style(self.path, DropFlagMode::Deep);
158-
debug!("elaborate_drop({:?}): live - {:?}", self, style);
158+
debug!("elaborate_drop({:?}, {:?}): live - {:?}", bb, self, style);
159159
match style {
160160
DropStyle::Dead => {
161161
self.elaborator
@@ -426,25 +426,21 @@ where
426426
let mut unwind_blocks =
427427
if unwind.is_cleanup() { None } else { Some(Vec::with_capacity(adt.variants.len())) };
428428

429+
let mut have_otherwise_with_drop_glue = false;
429430
let mut have_otherwise = false;
430431
let tcx = self.tcx();
431432

432433
for (variant_index, discr) in adt.discriminants(tcx) {
434+
let variant = &adt.variants[variant_index];
433435
let subpath = self.elaborator.downcast_subpath(self.path, variant_index);
436+
434437
if let Some(variant_path) = subpath {
435438
let base_place = tcx.mk_place_elem(
436439
self.place.clone(),
437-
ProjectionElem::Downcast(
438-
Some(adt.variants[variant_index].ident.name),
439-
variant_index,
440-
),
441-
);
442-
let fields = self.move_paths_for_fields(
443-
&base_place,
444-
variant_path,
445-
&adt.variants[variant_index],
446-
substs,
440+
ProjectionElem::Downcast(Some(variant.ident.name), variant_index),
447441
);
442+
let fields =
443+
self.move_paths_for_fields(&base_place, variant_path, &variant, substs);
448444
values.push(discr.val);
449445
if let Unwind::To(unwind) = unwind {
450446
// We can't use the half-ladder from the original
@@ -474,16 +470,30 @@ where
474470
normal_blocks.push(normal);
475471
} else {
476472
have_otherwise = true;
473+
474+
let param_env = self.elaborator.param_env();
475+
let have_field_with_drop_glue = variant
476+
.fields
477+
.iter()
478+
.any(|field| field.ty(tcx, substs).needs_drop(tcx, param_env));
479+
if have_field_with_drop_glue {
480+
have_otherwise_with_drop_glue = true;
481+
}
477482
}
478483
}
479484

480-
if have_otherwise {
485+
if !have_otherwise {
486+
values.pop();
487+
} else if !have_otherwise_with_drop_glue {
488+
normal_blocks.push(self.goto_block(succ, unwind));
489+
if let Unwind::To(unwind) = unwind {
490+
unwind_blocks.as_mut().unwrap().push(self.goto_block(unwind, Unwind::InCleanup));
491+
}
492+
} else {
481493
normal_blocks.push(self.drop_block(succ, unwind));
482494
if let Unwind::To(unwind) = unwind {
483495
unwind_blocks.as_mut().unwrap().push(self.drop_block(unwind, Unwind::InCleanup));
484496
}
485-
} else {
486-
values.pop();
487497
}
488498

489499
(
@@ -929,6 +939,11 @@ where
929939
self.new_block(unwind, block)
930940
}
931941

942+
fn goto_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
943+
let block = TerminatorKind::Goto { target };
944+
self.new_block(unwind, block)
945+
}
946+
932947
fn drop_flag_test_block(
933948
&mut self,
934949
on_set: BasicBlock,

0 commit comments

Comments
 (0)