Skip to content

Commit 4954e3e

Browse files
committed
fixes internal compiler error:
librustc_mir/transform/elaborate_drops.rs — drop of untracked, uninitialized value Fix #48962 r? @nikomatsakis
1 parent 75af15e commit 4954e3e

File tree

4 files changed

+161
-21
lines changed

4 files changed

+161
-21
lines changed

src/librustc_mir/borrow_check/error_reporting.rs

+17
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,23 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
3737
.collect::<Vec<_>>();
3838

3939
if mois.is_empty() {
40+
let root_place = self.prefixes(&place, PrefixSet::All)
41+
.last()
42+
.unwrap();
43+
44+
if self.moved_error_reported
45+
.contains(&root_place.clone())
46+
{
47+
debug!(
48+
"report_use_of_moved_or_uninitialized place: {:?} errors was suppressed",
49+
root_place
50+
);
51+
return;
52+
}
53+
54+
self.moved_error_reported
55+
.insert(root_place.clone());
56+
4057
let item_msg = match self.describe_place(place) {
4158
Some(name) => format!("`{}`", name),
4259
None => "value".to_owned(),

src/librustc_mir/borrow_check/mod.rs

+63-21
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
239239
},
240240
access_place_error_reported: FxHashSet(),
241241
reservation_error_reported: FxHashSet(),
242+
moved_error_reported: FxHashSet(),
242243
nonlexical_regioncx: opt_regioncx,
243244
nonlexical_cause_info: None,
244245
};
@@ -285,6 +286,9 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
285286
/// but it is currently inconvenient to track down the BorrowIndex
286287
/// at the time we detect and report a reservation error.
287288
reservation_error_reported: FxHashSet<Place<'tcx>>,
289+
/// This field keeps track of errors reported in the checking of moved variables,
290+
/// so that we don't report report seemingly duplicate errors.
291+
moved_error_reported: FxHashSet<Place<'tcx>>,
288292
/// Non-lexical region inference context, if NLL is enabled. This
289293
/// contains the results from region inference and lets us e.g.
290294
/// find out which CFG points are contained in each borrow region.
@@ -368,7 +372,7 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
368372
LocalMutationIsAllowed::No,
369373
flow_state,
370374
);
371-
self.check_if_path_is_moved(
375+
self.check_if_path_or_subpath_is_moved(
372376
context,
373377
InitializationRequiringAction::Use,
374378
(output, span),
@@ -963,7 +967,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
963967
// Write of P[i] or *P, or WriteAndRead of any P, requires P init'd.
964968
match mode {
965969
MutateMode::WriteAndRead => {
966-
self.check_if_path_is_moved(
970+
self.check_if_path_or_subpath_is_moved(
967971
context,
968972
InitializationRequiringAction::Update,
969973
place_span,
@@ -1023,7 +1027,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10231027
flow_state,
10241028
);
10251029

1026-
self.check_if_path_is_moved(
1030+
self.check_if_path_or_subpath_is_moved(
10271031
context,
10281032
InitializationRequiringAction::Borrow,
10291033
(place, span),
@@ -1051,7 +1055,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10511055
LocalMutationIsAllowed::No,
10521056
flow_state,
10531057
);
1054-
self.check_if_path_is_moved(
1058+
self.check_if_path_or_subpath_is_moved(
10551059
context,
10561060
InitializationRequiringAction::Use,
10571061
(place, span),
@@ -1098,7 +1102,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
10981102
);
10991103

11001104
// Finally, check if path was already moved.
1101-
self.check_if_path_is_moved(
1105+
self.check_if_path_or_subpath_is_moved(
11021106
context,
11031107
InitializationRequiringAction::Use,
11041108
(place, span),
@@ -1116,7 +1120,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
11161120
);
11171121

11181122
// Finally, check if path was already moved.
1119-
self.check_if_path_is_moved(
1123+
self.check_if_path_or_subpath_is_moved(
11201124
context,
11211125
InitializationRequiringAction::Use,
11221126
(place, span),
@@ -1267,7 +1271,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
12671271
LocalMutationIsAllowed::No,
12681272
flow_state,
12691273
);
1270-
// We do not need to call `check_if_path_is_moved`
1274+
// We do not need to call `check_if_path_or_subpath_is_moved`
12711275
// again, as we already called it when we made the
12721276
// initial reservation.
12731277
}
@@ -1320,18 +1324,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
13201324
//
13211325
// 1. Move of `a.b.c`, use of `a.b.c`
13221326
// 2. Move of `a.b.c`, use of `a.b.c.d` (without first reinitializing `a.b.c.d`)
1323-
// 3. Move of `a.b.c`, use of `a` or `a.b`
1324-
// 4. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with
1327+
// 3. Uninitialized `(a.b.c: &_)`, use of `*a.b.c`; note that with
13251328
// partial initialization support, one might have `a.x`
13261329
// initialized but not `a.b`.
13271330
//
13281331
// OK scenarios:
13291332
//
1330-
// 5. Move of `a.b.c`, use of `a.b.d`
1331-
// 6. Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1332-
// 7. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
1333+
// 4. Move of `a.b.c`, use of `a.b.d`
1334+
// 5. Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1335+
// 6. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
13331336
// must have been initialized for the use to be sound.
1334-
// 8. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
1337+
// 7. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
13351338

13361339
// The dataflow tracks shallow prefixes distinctly (that is,
13371340
// field-accesses on P distinctly from P itself), in order to
@@ -1350,9 +1353,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
13501353
// have a MovePath, that should capture the initialization
13511354
// state for the place scenario.
13521355
//
1353-
// This code covers scenarios 1, 2, and 4.
1356+
// This code covers scenarios 1, 2, and 3.
13541357

1355-
debug!("check_if_path_is_moved part1 place: {:?}", place);
1358+
debug!("check_if_path_is_moved place: {:?}", place);
13561359
match self.move_path_closest_to(place) {
13571360
Ok(mpi) => {
13581361
if maybe_uninits.contains(&mpi) {
@@ -1372,18 +1375,52 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
13721375
// ancestors; dataflow recurs on children when parents
13731376
// move (to support partial (re)inits).
13741377
//
1375-
// (I.e. querying parents breaks scenario 8; but may want
1378+
// (I.e. querying parents breaks scenario 7; but may want
13761379
// to do such a query based on partial-init feature-gate.)
13771380
}
1381+
}
1382+
1383+
fn check_if_path_or_subpath_is_moved(
1384+
&mut self,
1385+
context: Context,
1386+
desired_action: InitializationRequiringAction,
1387+
place_span: (&Place<'tcx>, Span),
1388+
flow_state: &Flows<'cx, 'gcx, 'tcx>,
1389+
) {
1390+
// FIXME: analogous code in check_loans first maps `place` to
1391+
// its base_path ... but is that what we want here?
1392+
let place = self.base_path(place_span.0);
1393+
1394+
let maybe_uninits = &flow_state.uninits;
1395+
let curr_move_outs = &flow_state.move_outs;
1396+
1397+
// Bad scenarios:
1398+
//
1399+
// 1. Move of `a.b.c`, use of `a` or `a.b`
1400+
// partial initialization support, one might have `a.x`
1401+
// initialized but not `a.b`.
1402+
// 2. All bad scenarios from `check_if_path_is_moved`
1403+
//
1404+
// OK scenarios:
1405+
//
1406+
// 3. Move of `a.b.c`, use of `a.b.d`
1407+
// 4. Uninitialized `a.x`, initialized `a.b`, use of `a.b`
1408+
// 5. Copied `(a.b: &_)`, use of `*(a.b).c`; note that `a.b`
1409+
// must have been initialized for the use to be sound.
1410+
// 6. Move of `a.b.c` then reinit of `a.b.c.d`, use of `a.b.c.d`
1411+
1412+
self.check_if_path_is_moved(context, desired_action, place_span, flow_state);
13781413

13791414
// A move of any shallow suffix of `place` also interferes
13801415
// with an attempt to use `place`. This is scenario 3 above.
13811416
//
13821417
// (Distinct from handling of scenarios 1+2+4 above because
13831418
// `place` does not interfere with suffixes of its prefixes,
13841419
// e.g. `a.b.c` does not interfere with `a.b.d`)
1420+
//
1421+
// This code covers scenario 1.
13851422

1386-
debug!("check_if_path_is_moved part2 place: {:?}", place);
1423+
debug!("check_if_path_or_subpath_is_moved place: {:?}", place);
13871424
if let Some(mpi) = self.move_path_for_place(place) {
13881425
if let Some(child_mpi) = maybe_uninits.has_any_child_of(mpi) {
13891426
self.report_use_of_moved_or_uninitialized(
@@ -1443,7 +1480,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
14431480
(place, span): (&Place<'tcx>, Span),
14441481
flow_state: &Flows<'cx, 'gcx, 'tcx>,
14451482
) {
1446-
// recur down place; dispatch to check_if_path_is_moved when necessary
1483+
debug!("check_if_assigned_path_is_moved place: {:?}", place);
1484+
// recur down place; dispatch to external checks when necessary
14471485
let mut place = place;
14481486
loop {
14491487
match *place {
@@ -1454,8 +1492,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
14541492
Place::Projection(ref proj) => {
14551493
let Projection { ref base, ref elem } = **proj;
14561494
match *elem {
1457-
ProjectionElem::Deref |
1458-
// assigning to *P requires `P` initialized.
14591495
ProjectionElem::Index(_/*operand*/) |
14601496
ProjectionElem::ConstantIndex { .. } |
14611497
// assigning to P[i] requires `P` initialized.
@@ -1465,6 +1501,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
14651501
// FIXME: is this true even if P is a adt with a dtor?
14661502
{ }
14671503

1504+
ProjectionElem::Deref => {
1505+
self.check_if_path_is_moved(
1506+
context, InitializationRequiringAction::Use,
1507+
(base, span), flow_state);
1508+
}
1509+
14681510
ProjectionElem::Subslice { .. } => {
14691511
panic!("we don't allow assignments to subslices, context: {:?}",
14701512
context);
@@ -1482,7 +1524,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
14821524
// check_loans.rs first maps
14831525
// `base` to its base_path.
14841526

1485-
self.check_if_path_is_moved(
1527+
self.check_if_path_or_subpath_is_moved(
14861528
context, InitializationRequiringAction::Assignment,
14871529
(base, span), flow_state);
14881530

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2018 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+
#![feature(nll)]
12+
13+
struct Node {
14+
elem: i32,
15+
next: Option<Box<Node>>,
16+
}
17+
18+
fn a() {
19+
let mut node = Node {
20+
elem: 5,
21+
next: None,
22+
};
23+
24+
let mut src = &mut node;
25+
{src};
26+
src.next = None; //~ ERROR use of moved value: `src` [E0382]
27+
}
28+
29+
fn b() {
30+
let mut src = &mut (22, 44);
31+
{src};
32+
src.0 = 66; //~ ERROR use of moved value: `src` [E0382]
33+
}
34+
35+
fn main() {
36+
a();
37+
b();
38+
}

src/test/run-pass/issue-48962.rs

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright 2018 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+
// Test that we are able to reinitilize box with moved referent
12+
#![feature(nll)]
13+
static mut ORDER: [usize; 3] = [0, 0, 0];
14+
static mut INDEX: usize = 0;
15+
16+
struct Dropee (usize);
17+
18+
impl Drop for Dropee {
19+
fn drop(&mut self) {
20+
unsafe {
21+
ORDER[INDEX] = self.0;
22+
INDEX = INDEX + 1;
23+
}
24+
}
25+
}
26+
27+
fn add_sentintel() {
28+
unsafe {
29+
ORDER[INDEX] = 2;
30+
INDEX = INDEX + 1;
31+
}
32+
}
33+
34+
fn main() {
35+
let mut x = Box::new(Dropee(1));
36+
*x; // move out from `*x`
37+
add_sentintel();
38+
*x = Dropee(3); // re-initialize `*x`
39+
{x}; // drop value
40+
unsafe {
41+
assert_eq!(ORDER, [1, 2, 3]);
42+
}
43+
}

0 commit comments

Comments
 (0)