Skip to content

Commit 32d0dbd

Browse files
Rymanpnkfelix
authored andcommitted
librustc: Forbid partial reinitialization of uninitialized structures or
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!)
1 parent 0fdca30 commit 32d0dbd

File tree

6 files changed

+173
-1
lines changed

6 files changed

+173
-1
lines changed

src/librustc_borrowck/borrowck/check_loans.rs

+23-1
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,26 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
745745
use_kind, lp_base);
746746
}
747747
LpExtend(ref lp_base, _, LpInterior(InteriorField(_))) => {
748+
match lp_base.to_type().sty {
749+
ty::ty_struct(def_id, _) | ty::ty_enum(def_id, _) => {
750+
if ty::has_dtor(self.tcx(), def_id) {
751+
// In the case where the owner implements drop, then
752+
// the path must be initialized to prevent a case of
753+
// partial reinitialization
754+
let loan_path = owned_ptr_base_path_rc(lp_base);
755+
self.move_data.each_move_of(id, &loan_path, |_, _| {
756+
self.bccx
757+
.report_partial_reinitialization_of_uninitialized_structure(
758+
span,
759+
&*loan_path);
760+
false
761+
});
762+
return;
763+
}
764+
},
765+
_ => {},
766+
}
767+
748768
// assigning to `P.f` is ok if assigning to `P` is ok
749769
self.check_if_assigned_path_is_moved(id, span,
750770
use_kind, lp_base);
@@ -775,10 +795,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
775795
mark_variable_as_used_mut(self, assignee_cmt);
776796
}
777797
}
798+
778799
return;
779800
}
780801

781-
// Initializations are OK.
802+
// Initializations are OK if and only if they aren't partial
803+
// reinitialization of a partially-uninitialized structure.
782804
if mode == euv::Init {
783805
return
784806
}

src/librustc_borrowck/borrowck/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,18 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
686686
}
687687
}
688688

689+
pub fn report_partial_reinitialization_of_uninitialized_structure(
690+
&self,
691+
span: Span,
692+
lp: &LoanPath<'tcx>) {
693+
self.tcx
694+
.sess
695+
.span_err(span,
696+
(format!("partial reinitialization of uninitialized \
697+
structure `{}`",
698+
self.loan_path_to_string(lp))).as_slice());
699+
}
700+
689701
pub fn report_reassigned_immutable_variable(&self,
690702
span: Span,
691703
lp: &LoanPath<'tcx>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct Test;
12+
13+
struct Test2 {
14+
b: Option<Test>,
15+
}
16+
17+
struct Test3(Option<Test>);
18+
19+
impl Drop for Test {
20+
fn drop(&mut self) {
21+
println!("dropping!");
22+
}
23+
}
24+
25+
impl Drop for Test2 {
26+
fn drop(&mut self) {}
27+
}
28+
29+
impl Drop for Test3 {
30+
fn drop(&mut self) {}
31+
}
32+
33+
fn stuff() {
34+
let mut t = Test2 { b: None };
35+
let u = Test;
36+
drop(t);
37+
t.b = Some(u);
38+
//~^ ERROR partial reinitialization of uninitialized structure `t`
39+
40+
let mut t = Test3(None);
41+
let u = Test;
42+
drop(t);
43+
t.0 = Some(u);
44+
//~^ ERROR partial reinitialization of uninitialized structure `t`
45+
}
46+
47+
fn main() {
48+
stuff()
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct Test {
12+
a: isize,
13+
b: Option<Box<Test>>,
14+
}
15+
16+
impl Drop for Test {
17+
fn drop(&mut self) {
18+
println!("Dropping {}", self.a);
19+
}
20+
}
21+
22+
fn stuff() {
23+
let mut t = Test { a: 1, b: None};
24+
let mut u = Test { a: 2, b: Some(Box::new(t))};
25+
t.b = Some(Box::new(u));
26+
//~^ ERROR partial reinitialization of uninitialized structure `t`
27+
println!("done");
28+
}
29+
30+
fn main() {
31+
stuff();
32+
println!("Hello, world!")
33+
}
34+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
use std::mem;
11+
12+
struct Test { f: usize }
13+
impl Drop for Test {
14+
fn drop(&mut self) {}
15+
}
16+
17+
fn main() {
18+
let mut x = (Test { f: 2 }, Test { f: 4 });
19+
mem::drop(x.0);
20+
x.0.f = 3;
21+
//~^ ERROR partial reinitialization of uninitialized structure `x.0`
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
struct Test;
12+
13+
struct Test2(Option<Test>);
14+
15+
impl Drop for Test {
16+
fn drop(&mut self) {
17+
println!("dropping!");
18+
}
19+
}
20+
21+
impl Drop for Test2 {
22+
fn drop(&mut self) {}
23+
}
24+
25+
fn stuff() {
26+
let mut x : (Test2, Test2);
27+
(x.0).0 = Some(Test);
28+
//~^ ERROR partial reinitialization of uninitialized structure `x.0`
29+
}
30+
31+
fn main() {
32+
stuff()
33+
}

0 commit comments

Comments
 (0)