diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 073b6dae0c385..633fb9d7b2d2a 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -748,13 +748,26 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { if mode != euv::Init { check_for_assignment_to_borrowed_path( self, assignment_id, assignment_span, assignee_cmt.clone()); - mark_variable_as_used_mut(self, assignee_cmt); + mark_variable_as_used_mut(self, assignee_cmt.clone()); } } + + // Check for partial reinitialization of a fully uninitialized structure. + match assignee_cmt.cat { + mc::cat_interior(ref container_cmt, _) | mc::cat_downcast(ref container_cmt) => { + check_for_illegal_initialization(self, + assignment_id, + assignment_span, + container_cmt); + } + mc::cat_rvalue(_) | mc::cat_static_item | mc::cat_upvar(_) | mc::cat_local(_) | + mc::cat_deref(_, _, _) => {} + } 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 } @@ -929,6 +942,39 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { false }); } + + fn check_for_illegal_initialization(this: &CheckLoanCtxt, + assignment_id: ast::NodeId, + span: Span, + assignee_cmt: &mc::cmt) { + let local_id = match assignee_cmt.cat { + mc::cat_interior(ref container_cmt, _) | mc::cat_downcast(ref container_cmt) => { + return check_for_illegal_initialization(this, + assignment_id, + span, + container_cmt) + } + mc::cat_local(local_id) => local_id, + mc::cat_rvalue(_) | mc::cat_static_item | mc::cat_upvar(_) | + mc::cat_deref(..) => return, + }; + + let struct_id = match ty::get(assignee_cmt.ty).sty { + ty::ty_struct(def_id, _) => def_id, + _ => return, + }; + if !ty::has_dtor(this.tcx(), struct_id) { + return + } + + let loan_path = Rc::new(LpVar(local_id)); + this.move_data.each_move_of(assignment_id, &loan_path, |_, _| { + this.bccx.report_partial_reinitialization_of_uninitialized_structure( + span, + &*loan_path); + false + }); + } } pub fn report_illegal_mutation(&self, diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 4e2b280eba686..1925fb421fda1 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -597,6 +597,18 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } + pub fn report_partial_reinitialization_of_uninitialized_structure( + &self, + span: Span, + lp: &LoanPath) { + 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, diff --git a/src/test/compile-fail/borrowck-partial-reinit-1.rs b/src/test/compile-fail/borrowck-partial-reinit-1.rs new file mode 100644 index 0000000000000..7f47eb504fbfc --- /dev/null +++ b/src/test/compile-fail/borrowck-partial-reinit-1.rs @@ -0,0 +1,37 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Test; + +struct Test2 { + b: Option, +} + +impl Drop for Test { + fn drop(&mut self) { + println!("dropping!"); + } +} + +impl Drop for Test2 { + 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 +} + +fn main() { + stuff() +} diff --git a/src/test/compile-fail/borrowck-partial-reinit-2.rs b/src/test/compile-fail/borrowck-partial-reinit-2.rs new file mode 100644 index 0000000000000..70995a024f1d4 --- /dev/null +++ b/src/test/compile-fail/borrowck-partial-reinit-2.rs @@ -0,0 +1,34 @@ +// Copyright 2014 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Test { + a: int, + b: Option>, +} + +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 t)}; + t.b = Some(box u); + //~^ ERROR partial reinitialization of uninitialized structure + println!("done"); +} + +fn main() { + stuff(); + println!("Hello, world!") +} +