Skip to content

Commit 8344236

Browse files
committed
Auto merge of #27413 - pnkfelix:fix-issue-27401, r=nikomatsakis
Reinitialize the dropflag hint in occurrences of variable bindings. Such bindings can occur in loops, and thus the binding can be executed after a previous move cleared the flag, thus necessitating the flag be reset to `DTOR_NEEDED_HINT`. Fix #27401.
2 parents 0919f4a + c681d30 commit 8344236

File tree

3 files changed

+124
-9
lines changed

3 files changed

+124
-9
lines changed

src/librustc_trans/trans/_match.rs

+40-9
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,25 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
10231023
bcx
10241024
}
10251025

1026+
// Sets each dropflag hint (if any) for bindings to `dropflag_hint_val`.
1027+
fn set_lllocals_hints<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1028+
bindings_map: &BindingsMap<'tcx>,
1029+
drop_flag_hint_value: u8)
1030+
-> Block<'blk, 'tcx> {
1031+
let lllocals = bcx.fcx.lllocals.borrow();
1032+
for (&ident, &binding_info) in bindings_map {
1033+
let datum = lllocals.get(&binding_info.id).unwrap();
1034+
if let Some(hint) = datum.kind.dropflag_hint(bcx) {
1035+
let hint_value = drop_flag_hint_value as usize;
1036+
debug!("set_lllocals_hints store hint_value={} for hint={:?} ident={}",
1037+
hint_value, hint, ident);
1038+
Store(bcx, C_u8(bcx.fcx.ccx, hint_value), hint.to_value().value());
1039+
}
1040+
}
1041+
1042+
bcx
1043+
}
1044+
10261045
fn compile_guard<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
10271046
guard_expr: &ast::Expr,
10281047
data: &ArmData<'p, 'blk, 'tcx>,
@@ -1635,6 +1654,7 @@ fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>,
16351654
// insert bindings into the lllocals map and add cleanups
16361655
let cs = fcx.push_custom_cleanup_scope();
16371656
bcx = insert_lllocals(bcx, &arm_data.bindings_map, Some(cleanup::CustomScope(cs)));
1657+
bcx = set_lllocals_hints(bcx, &arm_data.bindings_map, adt::DTOR_NEEDED_HINT);
16381658
bcx = expr::trans_into(bcx, &*arm_data.arm.body, dest);
16391659
bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, cs);
16401660
arm_cxs.push(bcx);
@@ -1666,16 +1686,10 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
16661686
bcx = mk_binding_alloca(
16671687
bcx, p_id, path1.node.name, scope, (),
16681688
"_match::store_local::create_dummy_locals",
1689+
// Dummy-locals start out uninitialized, so set their
1690+
// drop-flag hints (if any) to "moved."
1691+
adt::DTOR_MOVED_HINT,
16691692
|(), bcx, Datum { val: llval, ty, kind }| {
1670-
// Dummy-locals start out uninitialized, so set their
1671-
// drop-flag hints (if any) to "moved."
1672-
if let Some(hint) = kind.dropflag_hint(bcx) {
1673-
let moved_hint = adt::DTOR_MOVED_HINT as usize;
1674-
debug!("store moved_hint={} for hint={:?}, uninitialized dummy",
1675-
moved_hint, hint);
1676-
Store(bcx, C_u8(bcx.fcx.ccx, moved_hint), hint.to_value().value());
1677-
}
1678-
16791693
if kind.drop_flag_info.must_zero() {
16801694
// if no drop-flag hint, or the hint requires
16811695
// we maintain the embedded drop-flag, then
@@ -1707,6 +1721,9 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
17071721
return mk_binding_alloca(
17081722
bcx, pat.id, ident.name, var_scope, (),
17091723
"_match::store_local",
1724+
// Issue #27401: `let x = expr;` means drop
1725+
// flag hint needs to be (re-)initialized.
1726+
adt::DTOR_NEEDED_HINT,
17101727
|(), bcx, Datum { val: v, .. }| expr::trans_into(bcx, &**init_expr,
17111728
expr::SaveIn(v)));
17121729
}
@@ -1735,6 +1752,7 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
17351752
cleanup_scope: cleanup::ScopeId,
17361753
arg: A,
17371754
caller_name: &'static str,
1755+
drop_flag_hint_value: u8,
17381756
populate: F)
17391757
-> Block<'blk, 'tcx> where
17401758
F: FnOnce(A, Block<'blk, 'tcx>, Datum<'tcx, Lvalue>) -> Block<'blk, 'tcx>,
@@ -1749,6 +1767,15 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
17491767
// Subtle: be sure that we *populate* the memory *before*
17501768
// we schedule the cleanup.
17511769
let bcx = populate(arg, bcx, datum);
1770+
1771+
// Set the drop-flag hint, if any, to the value provided by context
1772+
if let Some(hint) = datum.kind.dropflag_hint(bcx) {
1773+
let hint_value = drop_flag_hint_value as usize;
1774+
debug!("mk_binding_alloca store hint_value={} for hint={:?}, name={}",
1775+
hint_value, hint, name);
1776+
Store(bcx, C_u8(bcx.fcx.ccx, hint_value), hint.to_value().value());
1777+
}
1778+
17521779
bcx.fcx.schedule_lifetime_end(cleanup_scope, llval);
17531780
bcx.fcx.schedule_drop_mem(cleanup_scope, llval, var_ty, lvalue.dropflag_hint(bcx));
17541781

@@ -1799,6 +1826,10 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
17991826
bcx = mk_binding_alloca(
18001827
bcx, pat.id, path1.node.name, cleanup_scope, (),
18011828
"_match::bind_irrefutable_pat",
1829+
// Issue #27401: `match ... { PAT[x] => ... }`
1830+
// means drop flag hint for `x` needs to be
1831+
// (re-)initialized.
1832+
adt::DTOR_NEEDED_HINT,
18021833
|(), bcx, Datum { val: llval, ty, kind: _ }| {
18031834
match pat_binding_mode {
18041835
ast::BindByValue(_) => {
+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
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+
// The stack-local drop flag associated with binding `let a = ...;`
12+
// (that occurred in a loop) were failing to (re-)initialize the drop
13+
// flag after it had been set to "moved" during an earlier iteration
14+
// of the loop.
15+
//
16+
// This is a regression test to ensure we don't let that behavior
17+
// creep back in.
18+
//
19+
// See also issue-27401-match-bind.rs
20+
21+
struct A<'a>(&'a mut i32);
22+
23+
impl<'a> Drop for A<'a> {
24+
fn drop(&mut self) {
25+
*self.0 += 1;
26+
}
27+
}
28+
29+
fn main() {
30+
let mut cnt = 0;
31+
for i in 0..2 {
32+
let a = A(&mut cnt);
33+
if i == 1 {
34+
break
35+
}
36+
drop(a);
37+
}
38+
assert_eq!(cnt, 2);
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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+
// The stack-local drop flag for binding in match-arm `(_, a) => ...`
12+
// (that occurred in a loop) were failing to (re-)initialize the drop
13+
// flag after it had been set to "moved" during an earlier iteration
14+
// of the loop.
15+
//
16+
// This is a regression test to ensure we don't let that behavior
17+
// creep back in.
18+
//
19+
// See also issue-27401-let-init.rs
20+
21+
use std::cell::Cell;
22+
23+
struct A<'a>(&'a Cell<i32>);
24+
25+
impl<'a> Drop for A<'a> {
26+
fn drop(&mut self) {
27+
let old_val = self.0.get();
28+
self.0.set(old_val + 1);
29+
}
30+
}
31+
32+
fn main() {
33+
let cnt = Cell::new(0);
34+
for i in 0..2 {
35+
match (A(&cnt), A(&cnt)) {
36+
(_, aaah) => {
37+
if i == 1 {
38+
break
39+
}
40+
drop(aaah);
41+
}
42+
}
43+
}
44+
assert_eq!(cnt.get(), 4);
45+
}

0 commit comments

Comments
 (0)