is_cleanup: bool)
-> Vec<BasicBlock>
{
- let mut succ = succ;
let mut unwind_succ = if is_cleanup {
None
} else {
c.unwind
};
- let mut update_drop_flag = true;
+
+ let mut succ = self.new_block(
+ c, c.is_cleanup, TerminatorKind::Goto { target: succ }
+ );
+
+ // Always clear the "master" drop flag at the bottom of the
+ // ladder. This is needed because the "master" drop flag
+ // protects the ADT's discriminant, which is invalidated
+ // after the ADT is dropped.
+ self.set_drop_flag(
+ Location { block: succ, statement_index: 0 },
+ c.path,
+ DropFlagState::Absent
+ );
fields.iter().rev().enumerate().map(|(i, &(ref lv, path))| {
- let drop_block = match path {
- Some(path) => {
- debug!("drop_ladder: for std field {} ({:?})", i, lv);
-
- self.elaborated_drop_block(&DropCtxt {
- source_info: c.source_info,
- is_cleanup: is_cleanup,
- init_data: c.init_data,
- lvalue: lv,
- path: path,
- succ: succ,
- unwind: unwind_succ,
- })
- }
- None => {
- debug!("drop_ladder: for rest field {} ({:?})", i, lv);
-
- let blk = self.complete_drop(&DropCtxt {
- source_info: c.source_info,
- is_cleanup: is_cleanup,
- init_data: c.init_data,
- lvalue: lv,
- path: c.path,
- succ: succ,
- unwind: unwind_succ,
- }, update_drop_flag);
-
- // the drop flag has been updated - updating
- // it again would clobber it.
- update_drop_flag = false;
-
- blk
- }
+ succ = if let Some(path) = path {
+ debug!("drop_ladder: for std field {} ({:?})", i, lv);
+
+ self.elaborated_drop_block(&DropCtxt {
+ source_info: c.source_info,
+ is_cleanup: is_cleanup,
+ init_data: c.init_data,
+ lvalue: lv,
+ path: path,
+ succ: succ,
+ unwind: unwind_succ,
+ })
+ } else {
+ debug!("drop_ladder: for rest field {} ({:?})", i, lv);
+
+ self.complete_drop(&DropCtxt {
+ source_info: c.source_info,
+ is_cleanup: is_cleanup,
+ init_data: c.init_data,
+ lvalue: lv,
+ path: c.path,
+ succ: succ,
+ unwind: unwind_succ,
+ }, false)
};
- succ = drop_block;
unwind_succ = unwind_ladder.as_ref().map(|p| p[i]);
-
- drop_block
+ succ
}).collect()
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Check that drop elaboration clears the "master" discriminant
+// drop flag even if it protects no fields.
+
+struct Good(usize);
+impl Drop for Good {
+ #[inline(never)]
+ fn drop(&mut self) {
+ println!("dropping Good({})", self.0);
+ }
+}
+
+struct Void;
+impl Drop for Void {
+ #[inline(never)]
+ fn drop(&mut self) {
+ panic!("Suddenly, a Void appears.");
+ }
+}
+
+enum E {
+ Never(Void),
+ Fine(Good)
+}
+
+fn main() {
+ let mut go = true;
+
+ loop {
+ let next;
+ match go {
+ true => next = E::Fine(Good(123)),
+ false => return,
+ }
+
+ match next {
+ E::Never(_) => return,
+ E::Fine(_good) => go = false,
+ }
+
+ // `next` is dropped and StorageDead'd here. We must reset the
+ // discriminant's drop flag to avoid random variants being
+ // dropped.
+ }
+}