Skip to content

Commit ba2efe9

Browse files
committed
Auto merge of #22219 - pnkfelix:partial-reinit, r=pnkfelix
borrowck: Prevent partial reinitialization of uninitialized structures This is a pnkfelix-swiped squash of #22079, which was a rebase and revision of #18963 Fixes #18571.
2 parents 39b463f + 6cc3b00 commit ba2efe9

File tree

6 files changed

+181
-1
lines changed

6 files changed

+181
-1
lines changed

src/librustc_borrowck/borrowck/check_loans.rs

+31-1
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
699699
lp: &Rc<LoanPath<'tcx>>) {
700700
debug!("check_if_path_is_moved(id={}, use_kind={:?}, lp={})",
701701
id, use_kind, lp.repr(self.bccx.tcx));
702+
703+
// FIXME (22079): if you find yourself tempted to cut and paste
704+
// the body below and then specializing the error reporting,
705+
// consider refactoring this instead!
706+
702707
let base_lp = owned_ptr_base_path_rc(lp);
703708
self.move_data.each_move_of(id, &base_lp, |the_move, moved_lp| {
704709
self.bccx.report_use_of_moved_value(
@@ -745,6 +750,29 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
745750
use_kind, lp_base);
746751
}
747752
LpExtend(ref lp_base, _, LpInterior(InteriorField(_))) => {
753+
match lp_base.to_type().sty {
754+
ty::ty_struct(def_id, _) | ty::ty_enum(def_id, _) => {
755+
if ty::has_dtor(self.tcx(), def_id) {
756+
// In the case where the owner implements drop, then
757+
// the path must be initialized to prevent a case of
758+
// partial reinitialization
759+
//
760+
// FIXME (22079): could refactor via hypothetical
761+
// generalized check_if_path_is_moved
762+
let loan_path = owned_ptr_base_path_rc(lp_base);
763+
self.move_data.each_move_of(id, &loan_path, |_, _| {
764+
self.bccx
765+
.report_partial_reinitialization_of_uninitialized_structure(
766+
span,
767+
&*loan_path);
768+
false
769+
});
770+
return;
771+
}
772+
},
773+
_ => {},
774+
}
775+
748776
// assigning to `P.f` is ok if assigning to `P` is ok
749777
self.check_if_assigned_path_is_moved(id, span,
750778
use_kind, lp_base);
@@ -775,10 +803,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
775803
mark_variable_as_used_mut(self, assignee_cmt);
776804
}
777805
}
806+
778807
return;
779808
}
780809

781-
// Initializations are OK.
810+
// Initializations are OK if and only if they aren't partial
811+
// reinitialization of a partially-uninitialized structure.
782812
if mode == euv::Init {
783813
return
784814
}

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)