blob: 3b0c89f9679d712194a97e831aeb7e62939bb94d [file] [edit]
//@ compile-flags: -Copt-level=3
// Test that we can avoid generating an element dropping loop when `vec::IntoIter` is consumed.
#![crate_type = "lib"]
use std::vec;
struct Bomb;
impl Drop for Bomb {
#[inline]
fn drop(&mut self) {
panic!("dropped")
}
}
/// Test case originally from https://users.rust-lang.org/t/unnecessary-drop-in-place-emitted-for-a-fully-consumed-intoiter/135119
///
/// What we are looking for is that there should be no calls to `impl Drop for Bomb`
/// because every element is unconditionally forgotten.
//
// CHECK-LABEL: @vec_for_each_doesnt_drop
#[no_mangle]
pub fn vec_for_each_doesnt_drop(v: vec::Vec<(usize, Option<Bomb>)>) -> usize {
// CHECK-NOT: panic
// CHECK-NOT: drop_in_place
// CHECK-NOT: Bomb$u20$as$u20$core..ops..drop..Drop
let mut last = 0;
v.into_iter().for_each(|(x, bomb)| {
last = x;
std::mem::forget(bomb);
});
last
}
/// Test that does *not* get the above optimization we are expecting:
/// it uses a normal `for` loop which calls `Iterator::next()` and then drops the iterator,
/// and dropping the iterator drops remaining items.
///
/// This test exists to prove that the above CHECK-NOT is looking for the right things.
/// However, it might start failing if LLVM figures out that there are no remaining items.
//
// CHECK-LABEL: @vec_for_loop
#[no_mangle]
pub fn vec_for_loop(v: vec::Vec<(usize, Option<Bomb>)>) -> usize {
// CHECK: drop_in_place
let mut last = 0;
for (x, bomb) in v {
last = x;
std::mem::forget(bomb);
}
last
}
/// Test where there still should be drops because there are no forgets.
///
/// This test exists to prove that the above CHECK-NOT is looking for the right things
/// and does not say anything interesting about codegen itself.
//
// CHECK-LABEL: @vec_for_each_does_drop
#[no_mangle]
pub fn vec_for_each_does_drop(v: vec::Vec<(usize, Option<Bomb>)>) -> usize {
// CHECK: begin_panic
let mut last = 0;
v.into_iter().for_each(|(x, bomb)| {
last = x;
});
last
}