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 } => {
|
||||
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!(
|
||||
block =
|
||||
this.as_operand(block, scope, &this.thir[value], None, NeedsTemporary::No)
|
||||
block = this.as_operand(
|
||||
block,
|
||||
scope,
|
||||
&this.thir[value],
|
||||
None,
|
||||
NeedsTemporary::No
|
||||
)
|
||||
);
|
||||
block.and(Rvalue::Repeat(value_operand, count))
|
||||
}
|
||||
}
|
||||
ExprKind::Binary { op, lhs, rhs } => {
|
||||
let lhs = unpack!(
|
||||
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(
|
||||
&mut self,
|
||||
upvar_span: Span,
|
||||
|
|
|
@ -1033,6 +1033,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
self.cfg.block_data(start).terminator().kind,
|
||||
TerminatorKind::Assert { .. }
|
||||
| TerminatorKind::Call { .. }
|
||||
| TerminatorKind::Drop { .. }
|
||||
| TerminatorKind::DropAndReplace { .. }
|
||||
| TerminatorKind::FalseUnwind { .. }
|
||||
| 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