Skip to content

Commit 52c74e6

Browse files
committed
Auto merge of #21692 - pnkfelix:fsk-fix-coerce-match-20055, r=eddyb
trans: When coercing to `Box<Trait>` or `Box<[T]>`, leave datum in it's original L-/R-value state. This fixes a subtle issue where temporaries were being allocated (but not necessarily initialized) to the (parent) terminating scope of a match expression; in particular, the code to zero out the temporary emitted by `datum.store_to` is only attached to the particular match-arm for that temporary, but when going down other arms of the match expression, the temporary may falsely appear to have been initialized, depending on what the stack held at that location, and thus may have its destructor erroneously run at the end of the terminating scope. FIx #20055. (There may be a latent bug still remaining in `fn into_fat_ptr`, but I am so annoyed by the test/run-pass/coerce_match.rs failures that I want to land this now.)
2 parents 7ea93ab + d855202 commit 52c74e6

File tree

3 files changed

+102
-12
lines changed

3 files changed

+102
-12
lines changed

src/librustc_trans/trans/expr.rs

+16-12
Original file line numberDiff line numberDiff line change
@@ -420,9 +420,15 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
420420
let tcx = bcx.tcx();
421421

422422
let datum_ty = datum.ty;
423-
// Arrange cleanup
424-
let lval = unpack_datum!(bcx,
425-
datum.to_lvalue_datum(bcx, "unsize_unique_vec", expr.id));
423+
424+
debug!("unsize_unique_vec expr.id={} datum_ty={} len={}",
425+
expr.id, datum_ty.repr(tcx), len);
426+
427+
// We do not arrange cleanup ourselves; if we already are an
428+
// L-value, then cleanup will have already been scheduled (and
429+
// the `datum.store_to` call below will emit code to zero the
430+
// drop flag when moving out of the L-value). If we are an R-value,
431+
// then we do not need to schedule cleanup.
426432

427433
let ll_len = C_uint(bcx.ccx(), len);
428434
let unit_ty = ty::sequence_element_type(tcx, ty::type_content(datum_ty));
@@ -433,7 +439,7 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
433439
let base = PointerCast(bcx,
434440
base,
435441
type_of::type_of(bcx.ccx(), datum_ty).ptr_to());
436-
bcx = lval.store_to(bcx, base);
442+
bcx = datum.store_to(bcx, base);
437443

438444
Store(bcx, ll_len, get_len(bcx, scratch.val));
439445
DatumBlock::new(bcx, scratch.to_expr_datum())
@@ -455,22 +461,20 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
455461
};
456462
let result_ty = ty::mk_uniq(tcx, ty::unsize_ty(tcx, unboxed_ty, k, expr.span));
457463

458-
let lval = unpack_datum!(bcx,
459-
datum.to_lvalue_datum(bcx, "unsize_unique_expr", expr.id));
464+
// We do not arrange cleanup ourselves; if we already are an
465+
// L-value, then cleanup will have already been scheduled (and
466+
// the `datum.store_to` call below will emit code to zero the
467+
// drop flag when moving out of the L-value). If we are an R-value,
468+
// then we do not need to schedule cleanup.
460469

461470
let scratch = rvalue_scratch_datum(bcx, result_ty, "__uniq_fat_ptr");
462471
let llbox_ty = type_of::type_of(bcx.ccx(), datum_ty);
463472
let base = PointerCast(bcx, get_dataptr(bcx, scratch.val), llbox_ty.ptr_to());
464-
bcx = lval.store_to(bcx, base);
473+
bcx = datum.store_to(bcx, base);
465474

466475
let info = unsized_info(bcx, k, expr.id, unboxed_ty, |t| ty::mk_uniq(tcx, t));
467476
Store(bcx, info, get_len(bcx, scratch.val));
468477

469-
let scratch = unpack_datum!(bcx,
470-
scratch.to_expr_datum().to_lvalue_datum(bcx,
471-
"fresh_uniq_fat_ptr",
472-
expr.id));
473-
474478
DatumBlock::new(bcx, scratch.to_expr_datum())
475479
}
476480
}
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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+
// See Issues #20055 and #21695.
12+
13+
// We are checking here that the temporaries `Box<[i8, k]>`, for `k`
14+
// in 1, 2, 3, 4, that are induced by the match expression are
15+
// properly handled, in that only *one* will be initialized by
16+
// whichever arm is run, and subsequently dropped at the end of the
17+
// statement surrounding the `match`.
18+
19+
trait Boo { }
20+
21+
impl Boo for [i8; 1] { }
22+
impl Boo for [i8; 2] { }
23+
impl Boo for [i8; 3] { }
24+
impl Boo for [i8; 4] { }
25+
26+
pub fn foo(box_1: fn () -> Box<[i8; 1]>,
27+
box_2: fn () -> Box<[i8; 2]>,
28+
box_3: fn () -> Box<[i8; 3]>,
29+
box_4: fn () -> Box<[i8; 4]>,
30+
) {
31+
println!("Hello World 1");
32+
let _: Box<Boo> = match 3 {
33+
1 => box_1(),
34+
2 => box_2(),
35+
3 => box_3(),
36+
_ => box_4(),
37+
};
38+
println!("Hello World 2");
39+
}
40+
41+
pub fn main() {
42+
fn box_1() -> Box<[i8; 1]> { Box::new( [1i8; 1] ) }
43+
fn box_2() -> Box<[i8; 2]> { Box::new( [1i8; 2] ) }
44+
fn box_3() -> Box<[i8; 3]> { Box::new( [1i8; 3] ) }
45+
fn box_4() -> Box<[i8; 4]> { Box::new( [1i8; 4] ) }
46+
47+
foo(box_1, box_2, box_3, box_4);
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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+
// Issue #2005: Check that boxed fixed-size arrays are properly
12+
// accounted for (namely, only deallocated if they were actually
13+
// created) when they appear as temporaries in unused arms of a match
14+
// expression.
15+
16+
pub fn foo(box_1: fn () -> Box<[i8; 1]>,
17+
box_2: fn () -> Box<[i8; 20]>,
18+
box_3: fn () -> Box<[i8; 300]>,
19+
box_4: fn () -> Box<[i8; 4000]>,
20+
) {
21+
println!("Hello World 1");
22+
let _: Box<[i8]> = match 3 {
23+
1 => box_1(),
24+
2 => box_2(),
25+
3 => box_3(),
26+
_ => box_4(),
27+
};
28+
println!("Hello World 2");
29+
}
30+
31+
pub fn main() {
32+
fn box_1() -> Box<[i8; 1]> { Box::new( [1i8] ) }
33+
fn box_2() -> Box<[i8; 20]> { Box::new( [1i8; 20] ) }
34+
fn box_3() -> Box<[i8; 300]> { Box::new( [1i8; 300] ) }
35+
fn box_4() -> Box<[i8; 4000]> { Box::new( [1i8; 4000] ) }
36+
37+
foo(box_1, box_2, box_3, box_4);
38+
}

0 commit comments

Comments
 (0)