Skip to content

Commit 965b0bf

Browse files
committed
Issue 30530: initialize allocas for Datum::to_lvalue_datum_in_scope.
In particular, bring back the `zero` flag for `lvalue_scratch_datum`, which controls whether the alloca's created immediately at function start are uninitialized at that point or have their embedded drop-flags initialized to "dropped". Then made `to_lvalue_datum_in_scope` pass "dropped" as `zero` flag.
1 parent 3246eae commit 965b0bf

File tree

3 files changed

+70
-6
lines changed

3 files changed

+70
-6
lines changed

src/librustc_trans/trans/adt.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ use syntax::ast;
5555
use syntax::attr;
5656
use syntax::attr::IntType;
5757
use trans::_match;
58+
use trans::base::InitAlloca;
5859
use trans::build::*;
5960
use trans::cleanup;
6061
use trans::cleanup::CleanupMethods;
@@ -1279,6 +1280,7 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
12791280
let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
12801281
let scratch = unpack_datum!(bcx, datum::lvalue_scratch_datum(
12811282
bcx, tcx.dtor_type(), "drop_flag",
1283+
InitAlloca::Uninit("drop flag itself has no dtor"),
12821284
cleanup::CustomScope(custom_cleanup_scope), (), |_, bcx, _| bcx
12831285
));
12841286
bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {

src/librustc_trans/trans/base.rs

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,12 +1285,62 @@ fn memfill<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>, byte:
12851285
None);
12861286
}
12871287

1288-
pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, name: &str) -> ValueRef {
1288+
/// In general, when we create an scratch value in an alloca, the
1289+
/// creator may not know if the block (that initializes the scratch
1290+
/// with the desired value) actually dominates the cleanup associated
1291+
/// with the scratch value.
1292+
///
1293+
/// To deal with this, when we do an alloca (at the *start* of whole
1294+
/// function body), we optionally can also set the associated
1295+
/// dropped-flag state of the alloca to "dropped."
1296+
#[derive(Copy, Clone, Debug)]
1297+
pub enum InitAlloca {
1298+
/// Indicates that the state should have its associated drop flag
1299+
/// set to "dropped" at the point of allocation.
1300+
Dropped,
1301+
/// Indicates the value of the associated drop flag is irrelevant.
1302+
/// The embedded string literal is a programmer provided argument
1303+
/// for why. This is a safeguard forcing compiler devs to
1304+
/// document; it might be a good idea to also emit this as a
1305+
/// comment with the alloca itself when emitting LLVM output.ll.
1306+
Uninit(&'static str),
1307+
}
1308+
1309+
1310+
pub fn alloc_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1311+
t: Ty<'tcx>,
1312+
name: &str) -> ValueRef {
1313+
// pnkfelix: I do not know why alloc_ty meets the assumptions for
1314+
// passing Uninit, but it was never needed (even back when we had
1315+
// the original boolean `zero` flag on `lvalue_scratch_datum`).
1316+
alloc_ty_init(bcx, t, InitAlloca::Uninit("all alloc_ty are uninit"), name)
1317+
}
1318+
1319+
pub fn alloc_ty_init<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1320+
t: Ty<'tcx>,
1321+
init: InitAlloca,
1322+
name: &str) -> ValueRef {
12891323
let _icx = push_ctxt("alloc_ty");
12901324
let ccx = bcx.ccx();
12911325
let ty = type_of::type_of(ccx, t);
12921326
assert!(!t.has_param_types());
1293-
alloca(bcx, ty, name)
1327+
match init {
1328+
InitAlloca::Dropped => alloca_dropped(bcx, t, name),
1329+
InitAlloca::Uninit(_) => alloca(bcx, ty, name),
1330+
}
1331+
}
1332+
1333+
pub fn alloca_dropped<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ty: Ty<'tcx>, name: &str) -> ValueRef {
1334+
let _icx = push_ctxt("alloca_dropped");
1335+
let llty = type_of::type_of(cx.ccx(), ty);
1336+
if cx.unreachable.get() {
1337+
unsafe { return llvm::LLVMGetUndef(llty.ptr_to().to_ref()); }
1338+
}
1339+
let p = alloca(cx, llty, name);
1340+
let b = cx.fcx.ccx.builder();
1341+
b.position_before(cx.fcx.alloca_insert_pt.get().unwrap());
1342+
memfill(&b, p, ty, adt::DTOR_DONE);
1343+
p
12941344
}
12951345

12961346
pub fn alloca(cx: Block, ty: Type, name: &str) -> ValueRef {
@@ -1650,6 +1700,7 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
16501700
// This alloca should be optimized away by LLVM's mem-to-reg pass in
16511701
// the event it's not truly needed.
16521702
let mut idx = fcx.arg_offset() as c_uint;
1703+
let uninit_reason = InitAlloca::Uninit("fn_arg populate dominates dtor");
16531704
for (i, &arg_ty) in arg_tys.iter().enumerate() {
16541705
let arg_datum = if !has_tupled_arg || i < arg_tys.len() - 1 {
16551706
if type_of::arg_is_indirect(bcx.ccx(), arg_ty) &&
@@ -1669,7 +1720,7 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
16691720
let data = get_param(fcx.llfn, idx);
16701721
let extra = get_param(fcx.llfn, idx + 1);
16711722
idx += 2;
1672-
unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "",
1723+
unpack_datum!(bcx, datum::lvalue_scratch_datum(bcx, arg_ty, "", uninit_reason,
16731724
arg_scope_id, (data, extra),
16741725
|(data, extra), bcx, dst| {
16751726
Store(bcx, data, expr::get_dataptr(bcx, dst));
@@ -1684,6 +1735,7 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
16841735
datum::lvalue_scratch_datum(bcx,
16851736
arg_ty,
16861737
"",
1738+
uninit_reason,
16871739
arg_scope_id,
16881740
tmp,
16891741
|tmp, bcx, dst| tmp.store_to(bcx, dst)))
@@ -1696,6 +1748,7 @@ pub fn create_datums_for_fn_args<'a, 'tcx>(mut bcx: Block<'a, 'tcx>,
16961748
datum::lvalue_scratch_datum(bcx,
16971749
arg_ty,
16981750
"tupled_args",
1751+
uninit_reason,
16991752
arg_scope_id,
17001753
(),
17011754
|(),

src/librustc_trans/trans/datum.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,20 +288,29 @@ pub fn immediate_rvalue_bcx<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
288288
return DatumBlock::new(bcx, immediate_rvalue(val, ty))
289289
}
290290

291-
292291
/// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
293292
/// it. The memory will be dropped upon exit from `scope`. The callback `populate` should
294293
/// initialize the memory.
294+
///
295+
/// The flag `zero` indicates how the temporary space itself should be
296+
/// initialized at the outset of the function; the only time that
297+
/// `InitAlloca::Uninit` is a valid value for `zero` is when the
298+
/// caller can prove that either (1.) the code injected by `populate`
299+
/// onto `bcx` always dominates the end of `scope`, or (2.) the data
300+
/// being allocated has no associated destructor.
295301
pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
296302
ty: Ty<'tcx>,
297303
name: &str,
304+
zero: InitAlloca,
298305
scope: cleanup::ScopeId,
299306
arg: A,
300307
populate: F)
301308
-> DatumBlock<'blk, 'tcx, Lvalue> where
302309
F: FnOnce(A, Block<'blk, 'tcx>, ValueRef) -> Block<'blk, 'tcx>,
303310
{
304-
let scratch = alloc_ty(bcx, ty, name);
311+
// Very subtle: potentially initialize the scratch memory at point where it is alloca'ed.
312+
// (See discussion at Issue 30530.)
313+
let scratch = alloc_ty_init(bcx, ty, zero, name);
305314

306315
// Subtle. Populate the scratch memory *before* scheduling cleanup.
307316
let bcx = populate(arg, bcx, scratch);
@@ -496,7 +505,7 @@ impl<'tcx> Datum<'tcx, Rvalue> {
496505

497506
ByValue => {
498507
lvalue_scratch_datum(
499-
bcx, self.ty, name, scope, self,
508+
bcx, self.ty, name, InitAlloca::Dropped, scope, self,
500509
|this, bcx, llval| {
501510
call_lifetime_start(bcx, llval);
502511
let bcx = this.store_to(bcx, llval);

0 commit comments

Comments
 (0)