enumerations that implement the `Drop` trait.
This breaks code like:
struct Struct {
f: String,
g: String,
}
impl Drop for Struct { ... }
fn main() {
let x = Struct { ... };
drop(x);
x.f = ...;
}
Change this code to not create partially-initialized structures. For
example:
struct Struct {
f: String,
g: String,
}
impl Drop for Struct { ... }
fn main() {
let x = Struct { ... };
drop(x);
x = Struct {
f: ...,
g: ...,
}
}
Closes #18571.
[breaking-change]
----
(Joint authorship by pcwalton and Ryman; thanks all!)
use_kind, lp_base);
}
LpExtend(ref lp_base, _, LpInterior(InteriorField(_))) => {
+ 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
+ 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;
+ }
+ },
+ _ => {},
+ }
+
// 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;
}
- // Initializations are OK.
+ // Initializations are OK if and only if they aren't partial
+ // reinitialization of a partially-uninitialized structure.
if mode == euv::Init {
return
}
}
}
+ 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());
+ }
+
pub fn report_reassigned_immutable_variable(&self,
span: Span,
lp: &LoanPath<'tcx>,
--- /dev/null
+// 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()
+}
--- /dev/null
+// 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!")
+}
+
--- /dev/null
+// 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`
+}
--- /dev/null
+// 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()
+}