Modify MIR building to drop foo
in [foo; 0]
This commit is contained in:
parent
222c5724ec
commit
0f65bcd920
5 changed files with 210 additions and 5 deletions
|
@ -52,12 +52,21 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ExprKind::Repeat { value, count } => {
|
ExprKind::Repeat { value, count } => {
|
||||||
|
if Some(0) == count.try_eval_usize(this.tcx, this.param_env) {
|
||||||
|
this.build_zero_repeat(block, value, scope, source_info)
|
||||||
|
} else {
|
||||||
let value_operand = unpack!(
|
let value_operand = unpack!(
|
||||||
block =
|
block = this.as_operand(
|
||||||
this.as_operand(block, scope, &this.thir[value], None, NeedsTemporary::No)
|
block,
|
||||||
|
scope,
|
||||||
|
&this.thir[value],
|
||||||
|
None,
|
||||||
|
NeedsTemporary::No
|
||||||
|
)
|
||||||
);
|
);
|
||||||
block.and(Rvalue::Repeat(value_operand, count))
|
block.and(Rvalue::Repeat(value_operand, count))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ExprKind::Binary { op, lhs, rhs } => {
|
ExprKind::Binary { op, lhs, rhs } => {
|
||||||
let lhs = unpack!(
|
let lhs = unpack!(
|
||||||
block =
|
block =
|
||||||
|
@ -515,6 +524,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn build_zero_repeat(
|
||||||
|
&mut self,
|
||||||
|
mut block: BasicBlock,
|
||||||
|
value: ExprId,
|
||||||
|
scope: Option<region::Scope>,
|
||||||
|
outer_source_info: SourceInfo,
|
||||||
|
) -> BlockAnd<Rvalue<'tcx>> {
|
||||||
|
let this = self;
|
||||||
|
let value = &this.thir[value];
|
||||||
|
let elem_ty = value.ty;
|
||||||
|
if let Some(Category::Constant) = Category::of(&value.kind) {
|
||||||
|
// Repeating a const does nothing
|
||||||
|
} else {
|
||||||
|
// For a non-const, we may need to generate an appropriate `Drop`
|
||||||
|
let value_operand =
|
||||||
|
unpack!(block = this.as_operand(block, scope, value, None, NeedsTemporary::No));
|
||||||
|
if let Operand::Move(to_drop) = value_operand {
|
||||||
|
let success = this.cfg.start_new_block();
|
||||||
|
this.cfg.terminate(
|
||||||
|
block,
|
||||||
|
outer_source_info,
|
||||||
|
TerminatorKind::Drop { place: to_drop, target: success, unwind: None },
|
||||||
|
);
|
||||||
|
this.diverge_from(block);
|
||||||
|
block = success;
|
||||||
|
}
|
||||||
|
this.record_operands_moved(&[value_operand]);
|
||||||
|
}
|
||||||
|
block.and(Rvalue::Aggregate(Box::new(AggregateKind::Array(elem_ty)), Vec::new()))
|
||||||
|
}
|
||||||
|
|
||||||
fn limit_capture_mutability(
|
fn limit_capture_mutability(
|
||||||
&mut self,
|
&mut self,
|
||||||
upvar_span: Span,
|
upvar_span: Span,
|
||||||
|
|
|
@ -1033,6 +1033,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
self.cfg.block_data(start).terminator().kind,
|
self.cfg.block_data(start).terminator().kind,
|
||||||
TerminatorKind::Assert { .. }
|
TerminatorKind::Assert { .. }
|
||||||
| TerminatorKind::Call { .. }
|
| TerminatorKind::Call { .. }
|
||||||
|
| TerminatorKind::Drop { .. }
|
||||||
| TerminatorKind::DropAndReplace { .. }
|
| TerminatorKind::DropAndReplace { .. }
|
||||||
| TerminatorKind::FalseUnwind { .. }
|
| TerminatorKind::FalseUnwind { .. }
|
||||||
| TerminatorKind::InlineAsm { .. }
|
| TerminatorKind::InlineAsm { .. }
|
||||||
|
|
15
src/test/ui/drop/repeat-drop-2.rs
Normal file
15
src/test/ui/drop/repeat-drop-2.rs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
fn borrowck_catch() {
|
||||||
|
let foo = String::new();
|
||||||
|
let _bar = foo;
|
||||||
|
let _baz = [foo; 0]; //~ ERROR use of moved value: `foo` [E0382]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _: [String; 0] = [String::new(); 0];
|
||||||
|
//~^ ERROR destructors cannot be evaluated at compile-time [E0493]
|
||||||
|
|
||||||
|
fn must_be_init() {
|
||||||
|
let x: u8;
|
||||||
|
let _ = [x; 0]; //~ ERROR: use of possibly-uninitialized variable: `x`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
29
src/test/ui/drop/repeat-drop-2.stderr
Normal file
29
src/test/ui/drop/repeat-drop-2.stderr
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
error[E0382]: use of moved value: `foo`
|
||||||
|
--> $DIR/repeat-drop-2.rs:4:17
|
||||||
|
|
|
||||||
|
LL | let foo = String::new();
|
||||||
|
| --- move occurs because `foo` has type `String`, which does not implement the `Copy` trait
|
||||||
|
LL | let _bar = foo;
|
||||||
|
| --- value moved here
|
||||||
|
LL | let _baz = [foo; 0];
|
||||||
|
| ^^^ value used here after move
|
||||||
|
|
||||||
|
error[E0493]: destructors cannot be evaluated at compile-time
|
||||||
|
--> $DIR/repeat-drop-2.rs:7:25
|
||||||
|
|
|
||||||
|
LL | const _: [String; 0] = [String::new(); 0];
|
||||||
|
| -^^^^^^^^^^^^^----
|
||||||
|
| ||
|
||||||
|
| |constants cannot evaluate destructors
|
||||||
|
| value is dropped here
|
||||||
|
|
||||||
|
error[E0381]: use of possibly-uninitialized variable: `x`
|
||||||
|
--> $DIR/repeat-drop-2.rs:12:14
|
||||||
|
|
|
||||||
|
LL | let _ = [x; 0];
|
||||||
|
| ^ use of possibly-uninitialized `x`
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
Some errors have detailed explanations: E0381, E0382, E0493.
|
||||||
|
For more information about an error, try `rustc --explain E0381`.
|
120
src/test/ui/drop/repeat-drop.rs
Normal file
120
src/test/ui/drop/repeat-drop.rs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
// run-pass
|
||||||
|
// ignore-wasm32-bare no unwinding panic
|
||||||
|
// ignore-avr no unwinding panic
|
||||||
|
// ignore-nvptx64 no unwinding panic
|
||||||
|
|
||||||
|
static mut CHECK: usize = 0;
|
||||||
|
|
||||||
|
struct DropChecker(usize);
|
||||||
|
|
||||||
|
impl Drop for DropChecker {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
if CHECK != self.0 - 1 {
|
||||||
|
panic!("Found {}, should have found {}", CHECK, self.0 - 1);
|
||||||
|
}
|
||||||
|
CHECK = self.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! check_drops {
|
||||||
|
($l:literal) => {
|
||||||
|
unsafe { assert_eq!(CHECK, $l) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
struct DropPanic;
|
||||||
|
|
||||||
|
impl Drop for DropPanic {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_zero() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let foo = DropChecker(1);
|
||||||
|
let v: [DropChecker; 0] = [foo; 0];
|
||||||
|
check_drops!(1);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn value_one() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let foo = DropChecker(1);
|
||||||
|
let v: [DropChecker; 1] = [foo; 1];
|
||||||
|
check_drops!(0);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const DROP_CHECKER: DropChecker = DropChecker(1);
|
||||||
|
|
||||||
|
fn const_zero() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let v: [DropChecker; 0] = [DROP_CHECKER; 0];
|
||||||
|
check_drops!(0);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn const_one() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let v: [DropChecker; 1] = [DROP_CHECKER; 1];
|
||||||
|
check_drops!(0);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn const_generic_zero<const N: usize>() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let v: [DropChecker; N] = [DROP_CHECKER; N];
|
||||||
|
check_drops!(0);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn const_generic_one<const N: usize>() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let v: [DropChecker; N] = [DROP_CHECKER; N];
|
||||||
|
check_drops!(0);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure that things are allowed to promote as expected
|
||||||
|
|
||||||
|
fn allow_promote() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
let foo = DropChecker(1);
|
||||||
|
let v: &'static [DropChecker; 0] = &[foo; 0];
|
||||||
|
check_drops!(1);
|
||||||
|
std::mem::drop(v);
|
||||||
|
check_drops!(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that unwinding in the drop causes the right things to drop in the right order
|
||||||
|
fn on_unwind() {
|
||||||
|
unsafe { CHECK = 0 };
|
||||||
|
std::panic::catch_unwind(|| {
|
||||||
|
let panic = DropPanic;
|
||||||
|
let _local = DropChecker(2);
|
||||||
|
let _v = (DropChecker(1), [panic; 0]);
|
||||||
|
std::process::abort();
|
||||||
|
})
|
||||||
|
.unwrap_err();
|
||||||
|
check_drops!(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
value_zero();
|
||||||
|
value_one();
|
||||||
|
const_zero();
|
||||||
|
const_one();
|
||||||
|
const_generic_zero::<0>();
|
||||||
|
const_generic_one::<1>();
|
||||||
|
allow_promote();
|
||||||
|
on_unwind();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue