summaryrefslogtreecommitdiffstats
path: root/tests/ui/rfcs/rfc-1857-stabilize-drop-order
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:57:31 +0000
commitdc0db358abe19481e475e10c32149b53370f1a1c (patch)
treeab8ce99c4b255ce46f99ef402c27916055b899ee /tests/ui/rfcs/rfc-1857-stabilize-drop-order
parentReleasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff)
downloadrustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz
rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tests/ui/rfcs/rfc-1857-stabilize-drop-order')
-rw-r--r--tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs224
1 files changed, 224 insertions, 0 deletions
diff --git a/tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs b/tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs
new file mode 100644
index 000000000..4c4816c2f
--- /dev/null
+++ b/tests/ui/rfcs/rfc-1857-stabilize-drop-order/drop-order.rs
@@ -0,0 +1,224 @@
+// run-pass
+// needs-unwind
+
+#![allow(dead_code, unreachable_code)]
+
+use std::cell::RefCell;
+use std::rc::Rc;
+use std::panic::{self, AssertUnwindSafe, UnwindSafe};
+
+// This struct is used to record the order in which elements are dropped
+struct PushOnDrop {
+ vec: Rc<RefCell<Vec<u32>>>,
+ val: u32
+}
+
+impl PushOnDrop {
+ fn new(val: u32, vec: Rc<RefCell<Vec<u32>>>) -> PushOnDrop {
+ PushOnDrop { vec, val }
+ }
+}
+
+impl Drop for PushOnDrop {
+ fn drop(&mut self) {
+ self.vec.borrow_mut().push(self.val)
+ }
+}
+
+impl UnwindSafe for PushOnDrop { }
+
+// Structs
+struct TestStruct {
+ x: PushOnDrop,
+ y: PushOnDrop,
+ z: PushOnDrop
+}
+
+// Tuple structs
+struct TestTupleStruct(PushOnDrop, PushOnDrop, PushOnDrop);
+
+// Enum variants
+enum TestEnum {
+ Tuple(PushOnDrop, PushOnDrop, PushOnDrop),
+ Struct { x: PushOnDrop, y: PushOnDrop, z: PushOnDrop }
+}
+
+fn test_drop_tuple() {
+ // Tuple fields are dropped in the same order they are declared
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let test_tuple = (PushOnDrop::new(1, dropped_fields.clone()),
+ PushOnDrop::new(2, dropped_fields.clone()));
+ drop(test_tuple);
+ assert_eq!(*dropped_fields.borrow(), &[1, 2]);
+
+ // Panic during construction means that fields are treated as local variables
+ // Therefore they are dropped in reverse order of initialization
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let cloned = AssertUnwindSafe(dropped_fields.clone());
+ panic::catch_unwind(|| {
+ (PushOnDrop::new(2, cloned.clone()),
+ PushOnDrop::new(1, cloned.clone()),
+ panic!("this panic is caught :D"));
+ }).err().unwrap();
+ assert_eq!(*dropped_fields.borrow(), &[1, 2]);
+}
+
+fn test_drop_struct() {
+ // Struct fields are dropped in the same order they are declared
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let test_struct = TestStruct {
+ x: PushOnDrop::new(1, dropped_fields.clone()),
+ y: PushOnDrop::new(2, dropped_fields.clone()),
+ z: PushOnDrop::new(3, dropped_fields.clone()),
+ };
+ drop(test_struct);
+ assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
+
+ // The same holds for tuple structs
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let test_tuple_struct = TestTupleStruct(PushOnDrop::new(1, dropped_fields.clone()),
+ PushOnDrop::new(2, dropped_fields.clone()),
+ PushOnDrop::new(3, dropped_fields.clone()));
+ drop(test_tuple_struct);
+ assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
+
+ // Panic during struct construction means that fields are treated as local variables
+ // Therefore they are dropped in reverse order of initialization
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let cloned = AssertUnwindSafe(dropped_fields.clone());
+ panic::catch_unwind(|| {
+ TestStruct {
+ x: PushOnDrop::new(2, cloned.clone()),
+ y: PushOnDrop::new(1, cloned.clone()),
+ z: panic!("this panic is caught :D")
+ };
+ }).err().unwrap();
+ assert_eq!(*dropped_fields.borrow(), &[1, 2]);
+
+ // Test with different initialization order
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let cloned = AssertUnwindSafe(dropped_fields.clone());
+ panic::catch_unwind(|| {
+ TestStruct {
+ y: PushOnDrop::new(2, cloned.clone()),
+ x: PushOnDrop::new(1, cloned.clone()),
+ z: panic!("this panic is caught :D")
+ };
+ }).err().unwrap();
+ assert_eq!(*dropped_fields.borrow(), &[1, 2]);
+
+ // The same holds for tuple structs
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let cloned = AssertUnwindSafe(dropped_fields.clone());
+ panic::catch_unwind(|| {
+ TestTupleStruct(PushOnDrop::new(2, cloned.clone()),
+ PushOnDrop::new(1, cloned.clone()),
+ panic!("this panic is caught :D"));
+ }).err().unwrap();
+ assert_eq!(*dropped_fields.borrow(), &[1, 2]);
+}
+
+fn test_drop_enum() {
+ // Enum variants are dropped in the same order they are declared
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let test_struct_enum = TestEnum::Struct {
+ x: PushOnDrop::new(1, dropped_fields.clone()),
+ y: PushOnDrop::new(2, dropped_fields.clone()),
+ z: PushOnDrop::new(3, dropped_fields.clone())
+ };
+ drop(test_struct_enum);
+ assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
+
+ // The same holds for tuple enum variants
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let test_tuple_enum = TestEnum::Tuple(PushOnDrop::new(1, dropped_fields.clone()),
+ PushOnDrop::new(2, dropped_fields.clone()),
+ PushOnDrop::new(3, dropped_fields.clone()));
+ drop(test_tuple_enum);
+ assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
+
+ // Panic during enum construction means that fields are treated as local variables
+ // Therefore they are dropped in reverse order of initialization
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let cloned = AssertUnwindSafe(dropped_fields.clone());
+ panic::catch_unwind(|| {
+ TestEnum::Struct {
+ x: PushOnDrop::new(2, cloned.clone()),
+ y: PushOnDrop::new(1, cloned.clone()),
+ z: panic!("this panic is caught :D")
+ };
+ }).err().unwrap();
+ assert_eq!(*dropped_fields.borrow(), &[1, 2]);
+
+ // Test with different initialization order
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let cloned = AssertUnwindSafe(dropped_fields.clone());
+ panic::catch_unwind(|| {
+ TestEnum::Struct {
+ y: PushOnDrop::new(2, cloned.clone()),
+ x: PushOnDrop::new(1, cloned.clone()),
+ z: panic!("this panic is caught :D")
+ };
+ }).err().unwrap();
+ assert_eq!(*dropped_fields.borrow(), &[1, 2]);
+
+ // The same holds for tuple enum variants
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let cloned = AssertUnwindSafe(dropped_fields.clone());
+ panic::catch_unwind(|| {
+ TestEnum::Tuple(PushOnDrop::new(2, cloned.clone()),
+ PushOnDrop::new(1, cloned.clone()),
+ panic!("this panic is caught :D"));
+ }).err().unwrap();
+ assert_eq!(*dropped_fields.borrow(), &[1, 2]);
+}
+
+fn test_drop_list() {
+ // Elements in a Vec are dropped in the same order they are pushed
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let xs = vec![PushOnDrop::new(1, dropped_fields.clone()),
+ PushOnDrop::new(2, dropped_fields.clone()),
+ PushOnDrop::new(3, dropped_fields.clone())];
+ drop(xs);
+ assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
+
+ // The same holds for arrays
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let xs = [PushOnDrop::new(1, dropped_fields.clone()),
+ PushOnDrop::new(2, dropped_fields.clone()),
+ PushOnDrop::new(3, dropped_fields.clone())];
+ drop(xs);
+ assert_eq!(*dropped_fields.borrow(), &[1, 2, 3]);
+
+ // Panic during vec construction means that fields are treated as local variables
+ // Therefore they are dropped in reverse order of initialization
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let cloned = AssertUnwindSafe(dropped_fields.clone());
+ panic::catch_unwind(|| {
+ vec![
+ PushOnDrop::new(2, cloned.clone()),
+ PushOnDrop::new(1, cloned.clone()),
+ panic!("this panic is caught :D")
+ ];
+ }).err().unwrap();
+ assert_eq!(*dropped_fields.borrow(), &[1, 2]);
+
+ // The same holds for arrays
+ let dropped_fields = Rc::new(RefCell::new(Vec::new()));
+ let cloned = AssertUnwindSafe(dropped_fields.clone());
+ panic::catch_unwind(|| {
+ [
+ PushOnDrop::new(2, cloned.clone()),
+ PushOnDrop::new(1, cloned.clone()),
+ panic!("this panic is caught :D")
+ ];
+ }).err().unwrap();
+ assert_eq!(*dropped_fields.borrow(), &[1, 2]);
+}
+
+fn main() {
+ test_drop_tuple();
+ test_drop_struct();
+ test_drop_enum();
+ test_drop_list();
+}