Change:
So I was curious how Drop handles cycles, because this could lead to dangling pointers, which is why . And indeed the below example does not call Drop. But is moved into , so why does this compile at all?
Nominating, seems like a soundness hole.
This is an issue with zeroing dynamic drops (which are going to be removed: rust-lang/rfcs) – when is moved, its drop flag is cleared, which prevents the destructor of from running. A clearer example is:
Structs that implement drop are not supposed to be in a partially initialized state. We already prevents moves out from individual fields, but we also need to prevent individual fields from being re-initialized. cc since (iirc?) he was working on the patches that made us more accepting around re-initializing fields and so forth, and maybe this bug is of interest to him.
So we are not supposed to allow structs that implement drop to be partially initialized. We already disallow going from fully-initialized to partially initialized. But it seems (from the first example) that we missed disallowing going from fully-uninitialized to partially initializd. That needs to be fixed. Assigning P-backcompat-lang, 1.0.
While this will hopefully be fixed soon, as there is a PR up, it seems to have fallen through the cracks as a P-backcompat-lang issue that is only on the 1.0 milestone and not 1.0 beta. Nominating for 1.0 beta. (Also, I guess I will try to run through and find any other such overlooked issues.)
Assigning 1.0 beta.

Discussion:
lp: &Rc<LoanPath<'tcx>>) { debug!("check_if_path_is_moved(id={}, use_kind={:?}, lp={})", id, use_kind, lp.repr(self.bccx.tcx)); <ins> // FIXME (22079): if you find yourself tempted to cut and paste // the body below and then specializing the error reporting, // consider refactoring this instead! </ins> let base_lp = owned_ptr_base_path_rc(lp); self.move_data.each_move_of(id, &base_lp, |the_move, moved_lp| { self.bccx.report_use_of_moved_value(

use_kind, lp_base); } LpExtend(ref lp_base, _, LpInterior(InteriorField(_))) => { <ins> match lp_base.to_type().sty { ty::ty_struct(def_id, _) | ty::ty_enum(def_id, _) => { if ty::has_dtor(self.tcx(), def_id) { // In the case where the owner implements drop, then // the path must be initialized to prevent a case of // partial reinitialization // // FIXME (22079): could refactor via hypothetical // generalized check_if_path_is_moved let loan_path = owned_ptr_base_path_rc(lp_base); self.move_data.each_move_of(id, &loan_path, |_, _| { self.bccx .report_partial_reinitialization_of_uninitialized_structure( span, &*loan_path); false }); return; } }, _ => {}, } </ins> // assigning to `P.f` is ok if assigning to `P` is ok self.check_if_assigned_path_is_moved(id, span, use_kind, lp_base);

mark_variable_as_used_mut(self, assignee_cmt); } } return; } <del> // Initializations are OK. </del> <ins> // Initializations are OK if and only if they aren't partial // reinitialization of a partially-uninitialized structure. </ins> if mode == euv::Init { return }

} } <ins> pub fn report_partial_reinitialization_of_uninitialized_structure( &self, span: Span, lp: &LoanPath<'tcx>) { self.tcx .sess .span_err(span, (format!("partial reinitialization of uninitialized  structure `{}`", self.loan_path_to_string(lp))).as_slice()); } </ins> pub fn report_reassigned_immutable_variable(&self, span: Span, lp: &LoanPath<'tcx>,

<ins> // Copyright 2014-2015 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. struct Test; struct Test2 { b: Option<Test>, } struct Test3(Option<Test>); impl Drop for Test { fn drop(&mut self) { println!("dropping!"); } } impl Drop for Test2 { fn drop(&mut self) {} } impl Drop for Test3 { fn drop(&mut self) {} } fn stuff() { let mut t = Test2 { b: None }; let u = Test; drop(t); t.b = Some(u); //~^ ERROR partial reinitialization of uninitialized structure `t` let mut t = Test3(None); let u = Test; drop(t); t.0 = Some(u); //~^ ERROR partial reinitialization of uninitialized structure `t` } fn main() { stuff() } </ins>

<ins> // Copyright 2014-2015 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. struct Test { a: isize, b: Option<Box<Test>>, } impl Drop for Test { fn drop(&mut self) { println!("Dropping {}", self.a); } } fn stuff() { let mut t = Test { a: 1, b: None}; let mut u = Test { a: 2, b: Some(Box::new(t))}; t.b = Some(Box::new(u)); //~^ ERROR partial reinitialization of uninitialized structure `t` println!("done"); } fn main() { stuff(); println!("Hello, world!") } </ins>

<ins> // Copyright 2015 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. use std::mem; struct Test { f: usize } impl Drop for Test { fn drop(&mut self) {} } fn main() { let mut x = (Test { f: 2 }, Test { f: 4 }); mem::drop(x.0); x.0.f = 3; //~^ ERROR partial reinitialization of uninitialized structure `x.0` } </ins>

<ins> // Copyright 2015 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. struct Test; struct Test2(Option<Test>); impl Drop for Test { fn drop(&mut self) { println!("dropping!"); } } impl Drop for Test2 { fn drop(&mut self) {} } fn stuff() { let mut x : (Test2, Test2); (x.0).0 = Some(Test); //~^ ERROR partial reinitialization of uninitialized structure `x.0` } fn main() { stuff() } </ins>