Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions library/alloctests/testing/macros.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,33 @@
macro_rules! struct_with_counted_drop {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily something to do here, but could vecdeque just use these too?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what you mean here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, nevermind, I was thinking #142520 was for dequeue rather than linked list

($struct_name:ident$(($elt_ty:ty))?, $drop_counter:ident $(=> $drop_stmt:expr)?) => {
($struct_name:ident $(( $( $elt_ty:ty ),+ ))?, $drop_counter:ident $( => $drop_stmt:expr )? ) => {
thread_local! {static $drop_counter: ::core::cell::Cell<u32> = ::core::cell::Cell::new(0);}

struct $struct_name$(($elt_ty))?;
#[derive(Clone, Debug, PartialEq)]
struct $struct_name $(( $( $elt_ty ),+ ))?;

impl ::std::ops::Drop for $struct_name {
fn drop(&mut self) {
$drop_counter.set($drop_counter.get() + 1);

$($drop_stmt(self))?
}
}
};
($struct_name:ident $(( $( $elt_ty:ty ),+ ))?, $drop_counter:ident[ $drop_key:expr,$key_ty:ty ] $( => $drop_stmt:expr )? ) => {
thread_local! {
static $drop_counter: ::core::cell::RefCell<::std::collections::HashMap<$key_ty, u32>> =
::core::cell::RefCell::new(::std::collections::HashMap::new());
}

#[derive(Clone, Debug, PartialEq)]
struct $struct_name $(( $( $elt_ty ),+ ))?;

impl ::std::ops::Drop for $struct_name {
fn drop(&mut self) {
$drop_counter.with_borrow_mut(|counter| {
*counter.entry($drop_key(self)).or_default() += 1;
});

$($drop_stmt(self))?
}
}
Expand Down
2 changes: 2 additions & 0 deletions library/alloctests/tests/testing/mod.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
pub mod crash_test;
#[path = "../../testing/macros.rs"]
pub mod macros;
119 changes: 29 additions & 90 deletions library/alloctests/tests/vec.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#![allow(static_mut_refs)]

use core::alloc::{Allocator, Layout};
use core::num::NonZero;
use core::ptr::NonNull;
Expand All @@ -20,6 +17,8 @@ use std::rc::Rc;
use std::sync::atomic::{AtomicU32, Ordering};
use std::vec::{Drain, IntoIter};

use crate::testing::macros::struct_with_counted_drop;

struct DropCounter<'a> {
count: &'a mut u32,
}
Expand Down Expand Up @@ -548,32 +547,25 @@ fn test_cmp() {

#[test]
fn test_vec_truncate_drop() {
static mut DROPS: u32 = 0;
struct Elem(#[allow(dead_code)] i32);
impl Drop for Elem {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}
}
}
struct_with_counted_drop!(Elem(i32), DROPS);

let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
assert_eq!(unsafe { DROPS }, 0);

assert_eq!(DROPS.get(), 0);
v.truncate(3);
assert_eq!(unsafe { DROPS }, 2);
assert_eq!(DROPS.get(), 2);
v.truncate(0);
assert_eq!(unsafe { DROPS }, 5);
assert_eq!(DROPS.get(), 5);
}

#[test]
#[should_panic]
fn test_vec_truncate_fail() {
struct BadElem(i32);

impl Drop for BadElem {
fn drop(&mut self) {
let BadElem(ref mut x) = *self;
if *x == 0xbadbeef {
if let BadElem(0xbadbeef) = self {
panic!("BadElem panic: 0xbadbeef")
}
}
Expand Down Expand Up @@ -812,22 +804,7 @@ fn test_drain_end_overflow() {
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_drain_leak() {
static mut DROPS: i32 = 0;

#[derive(Debug, PartialEq)]
struct D(u32, bool);

impl Drop for D {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}

if self.1 {
panic!("panic in `drop`");
}
}
}
struct_with_counted_drop!(D(u32, bool), DROPS => |this: &D| if this.1 { panic!("panic in `drop`"); });

let mut v = vec![
D(0, false),
Expand All @@ -844,7 +821,7 @@ fn test_drain_leak() {
}))
.ok();

assert_eq!(unsafe { DROPS }, 4);
assert_eq!(DROPS.get(), 4);
assert_eq!(v, vec![D(0, false), D(1, false), D(6, false),]);
}

Expand Down Expand Up @@ -1057,27 +1034,13 @@ fn test_into_iter_clone() {
#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
fn test_into_iter_leak() {
static mut DROPS: i32 = 0;

struct D(bool);

impl Drop for D {
fn drop(&mut self) {
unsafe {
DROPS += 1;
}

if self.0 {
panic!("panic in `drop`");
}
}
}
struct_with_counted_drop!(D(bool), DROPS => |this: &D| if this.0 { panic!("panic in `drop`"); });

let v = vec![D(false), D(true), D(false)];

catch_unwind(move || drop(v.into_iter())).ok();

assert_eq!(unsafe { DROPS }, 3);
assert_eq!(DROPS.get(), 3);
}

#[test]
Expand Down Expand Up @@ -1274,55 +1237,31 @@ fn test_from_iter_specialization_panic_during_iteration_drops() {

#[test]
#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")]
// FIXME(static_mut_refs): Do not allow `static_mut_refs` lint
#[allow(static_mut_refs)]
fn test_from_iter_specialization_panic_during_drop_doesnt_leak() {
static mut DROP_COUNTER_OLD: [usize; 5] = [0; 5];
static mut DROP_COUNTER_NEW: [usize; 2] = [0; 2];

#[derive(Debug)]
struct Old(usize);

impl Drop for Old {
fn drop(&mut self) {
unsafe {
DROP_COUNTER_OLD[self.0] += 1;
}

if self.0 == 3 {
panic!();
}

println!("Dropped Old: {}", self.0);
}
}

#[derive(Debug)]
struct New(usize);

impl Drop for New {
fn drop(&mut self) {
unsafe {
DROP_COUNTER_NEW[self.0] += 1;
struct_with_counted_drop!(
Old(usize), DROP_COUNTER_OLD[|this: &Old| this.0, usize] =>
|this: &Old| {
if this.0 == 3 { panic!(); } println!("Dropped Old: {}", this.0)
}

println!("Dropped New: {}", self.0);
}
}
);
struct_with_counted_drop!(
New(usize), DROP_COUNTER_NEW[|this: &New| this.0, usize] =>
|this: &New| println!("Dropped New: {}", this.0)
);

let _ = std::panic::catch_unwind(AssertUnwindSafe(|| {
let v = vec![Old(0), Old(1), Old(2), Old(3), Old(4)];
let _ = v.into_iter().map(|x| New(x.0)).take(2).collect::<Vec<_>>();
}));

assert_eq!(unsafe { DROP_COUNTER_OLD[0] }, 1);
assert_eq!(unsafe { DROP_COUNTER_OLD[1] }, 1);
assert_eq!(unsafe { DROP_COUNTER_OLD[2] }, 1);
assert_eq!(unsafe { DROP_COUNTER_OLD[3] }, 1);
assert_eq!(unsafe { DROP_COUNTER_OLD[4] }, 1);
DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&0), Some(&1)));
DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&1), Some(&1)));
DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&2), Some(&1)));
DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&3), Some(&1)));
DROP_COUNTER_OLD.with_borrow(|c| assert_eq!(c.get(&4), Some(&1)));

assert_eq!(unsafe { DROP_COUNTER_NEW[0] }, 1);
assert_eq!(unsafe { DROP_COUNTER_NEW[1] }, 1);
DROP_COUNTER_NEW.with_borrow(|c| assert_eq!(c.get(&0), Some(&1)));
DROP_COUNTER_NEW.with_borrow(|c| assert_eq!(c.get(&1), Some(&1)));
}

// regression test for issue #85322. Peekable previously implemented InPlaceIterable,
Expand Down
Loading