Skip to content

Commit 413e0b2

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 e822a18 commit 413e0b2

File tree

1 file changed

+40
-9
lines changed

1 file changed

+40
-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;
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>,
@@ -1633,6 +1652,7 @@ fn trans_match_inner<'blk, 'tcx>(scope_cx: Block<'blk, 'tcx>,
16331652
// insert bindings into the lllocals map and add cleanups
16341653
let cs = fcx.push_custom_cleanup_scope();
16351654
bcx = insert_lllocals(bcx, &arm_data.bindings_map, Some(cleanup::CustomScope(cs)));
1655+
bcx = set_lllocals_hints(bcx, &arm_data.bindings_map, adt::DTOR_NEEDED_HINT);
16361656
bcx = expr::trans_into(bcx, &*arm_data.arm.body, dest);
16371657
bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, cs);
16381658
arm_cxs.push(bcx);
@@ -1664,16 +1684,10 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
16641684
bcx = mk_binding_alloca(
16651685
bcx, p_id, path1.node.name, scope, (),
16661686
"_match::store_local::create_dummy_locals",
1687+
// Dummy-locals start out uninitialized, so set their
1688+
// drop-flag hints (if any) to "moved."
1689+
adt::DTOR_MOVED_HINT,
16671690
|(), bcx, Datum { val: llval, ty, kind }| {
1668-
// Dummy-locals start out uninitialized, so set their
1669-
// drop-flag hints (if any) to "moved."
1670-
if let Some(hint) = kind.dropflag_hint(bcx) {
1671-
let moved_hint = adt::DTOR_MOVED_HINT;
1672-
debug!("store moved_hint={} for hint={:?}, uninitialized dummy",
1673-
moved_hint, hint);
1674-
Store(bcx, C_u8(bcx.fcx.ccx, moved_hint), hint.to_value().value());
1675-
}
1676-
16771691
if kind.drop_flag_info.must_zero() {
16781692
// if no drop-flag hint, or the hint requires
16791693
// we maintain the embedded drop-flag, then
@@ -1705,6 +1719,9 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
17051719
return mk_binding_alloca(
17061720
bcx, pat.id, ident.name, var_scope, (),
17071721
"_match::store_local",
1722+
// Issue #27401: `let x = expr;` means drop
1723+
// flag hint needs to be (re-)initialized.
1724+
adt::DTOR_NEEDED_HINT,
17081725
|(), bcx, Datum { val: v, .. }| expr::trans_into(bcx, &**init_expr,
17091726
expr::SaveIn(v)));
17101727
}
@@ -1733,6 +1750,7 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
17331750
cleanup_scope: cleanup::ScopeId,
17341751
arg: A,
17351752
caller_name: &'static str,
1753+
drop_flag_hint_value: u8,
17361754
populate: F)
17371755
-> Block<'blk, 'tcx> where
17381756
F: FnOnce(A, Block<'blk, 'tcx>, Datum<'tcx, Lvalue>) -> Block<'blk, 'tcx>,
@@ -1747,6 +1765,15 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
17471765
// Subtle: be sure that we *populate* the memory *before*
17481766
// we schedule the cleanup.
17491767
let bcx = populate(arg, bcx, datum);
1768+
1769+
// Set the drop-flag hint, if any, to the value provided by context
1770+
if let Some(hint) = datum.kind.dropflag_hint(bcx) {
1771+
let hint_value = drop_flag_hint_value;
1772+
debug!("mk_binding_alloca store hint_value={} for hint={:?}, name={}",
1773+
hint_value, hint, name);
1774+
Store(bcx, C_u8(bcx.fcx.ccx, hint_value), hint.to_value().value());
1775+
}
1776+
17501777
bcx.fcx.schedule_lifetime_end(cleanup_scope, llval);
17511778
bcx.fcx.schedule_drop_mem(cleanup_scope, llval, var_ty, lvalue.dropflag_hint(bcx));
17521779

@@ -1797,6 +1824,10 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
17971824
bcx = mk_binding_alloca(
17981825
bcx, pat.id, path1.node.name, cleanup_scope, (),
17991826
"_match::bind_irrefutable_pat",
1827+
// Issue #27401: `match ... { PAT[x] => ... }`
1828+
// means drop flag hint for `x` needs to be
1829+
// (re-)initialized.
1830+
adt::DTOR_NEEDED_HINT,
18001831
|(), bcx, Datum { val: llval, ty, kind: _ }| {
18011832
match pat_binding_mode {
18021833
ast::BindByValue(_) => {

0 commit comments

Comments
 (0)