Skip to content

Commit 173dc0f

Browse files
committed
Reinitialize the dropflag hint in binding occurrences.
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 rust-lang#27401.
1 parent 6edc994 commit 173dc0f

File tree

1 file changed

+40
-9
lines changed

1 file changed

+40
-9
lines changed

src/librustc_trans/trans/_match.rs

Lines changed: 40 additions & 9 deletions
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(_) => {

0 commit comments

Comments
 (0)