From f86e433b67292150faa9fd978cad487934d90c76 Mon Sep 17 00:00:00 2001 From: Adolfo OchagavĂ­a Date: Sat, 8 Jul 2017 21:32:29 +0200 Subject: Add regression tests to ensure stable drop order --- src/test/run-pass/rfc1857-drop-order.rs | 231 ++++++++++++++++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 src/test/run-pass/rfc1857-drop-order.rs (limited to 'src') diff --git a/src/test/run-pass/rfc1857-drop-order.rs b/src/test/run-pass/rfc1857-drop-order.rs new file mode 100644 index 00000000000..42f989538c8 --- /dev/null +++ b/src/test/run-pass/rfc1857-drop-order.rs @@ -0,0 +1,231 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![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>>, + val: u32 +} + +impl PushOnDrop { + fn new(val: u32, vec: Rc>>) -> 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 catched :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 catched :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 catched :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 catched :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 catched :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 catched :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 catched :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 catched :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 catched :D") + ]; + }).err().unwrap(); + assert_eq!(*dropped_fields.borrow(), &[1, 2]); +} + +fn main() { + test_drop_tuple(); + test_drop_struct(); + test_drop_enum(); + test_drop_list(); +} -- cgit 1.4.1-3-g733a5 From a01c91c8bc251f46b94c5124f31df6bc094fb0a1 Mon Sep 17 00:00:00 2001 From: Havvy Date: Tue, 27 Jun 2017 03:59:07 -0700 Subject: Document error coercion to false in path-ext methods + see also sections --- src/libstd/path.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'src') diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 42a54ed6d75..f0feb82cd01 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -2215,12 +2215,22 @@ impl Path { /// This function will traverse symbolic links to query information about the /// destination file. In case of broken symbolic links this will return `false`. /// + /// If you cannot access the directory containing the file, e.g. because of a + /// permission error, this will return `false`. + /// /// # Examples /// /// ```no_run /// use std::path::Path; /// assert_eq!(Path::new("does_not_exist.txt").exists(), false); /// ``` + /// + /// # See Also + /// + /// This is a convenience function that coerces errors to false. If you want to + /// check errors, call [fs::metadata]. + /// + /// [fs::metadata]: ../../std/fs/fn.metadata.html #[stable(feature = "path_ext", since = "1.5.0")] pub fn exists(&self) -> bool { fs::metadata(self).is_ok() @@ -2231,6 +2241,9 @@ impl Path { /// This function will traverse symbolic links to query information about the /// destination file. In case of broken symbolic links this will return `false`. /// + /// If you cannot access the directory containing the file, e.g. because of a + /// permission error, this will return `false`. + /// /// # Examples /// /// ```no_run @@ -2238,6 +2251,15 @@ impl Path { /// assert_eq!(Path::new("./is_a_directory/").is_file(), false); /// assert_eq!(Path::new("a_file.txt").is_file(), true); /// ``` + /// + /// # See Also + /// + /// This is a convenience function that coerces errors to false. If you want to + /// check errors, call [fs::metadata] and handle its Result. Then call + /// [fs::Metadata::is_file] if it was Ok. + /// + /// [fs::metadata]: ../../std/fs/fn.metadata.html + /// [fs::Metadata::is_file]: ../../std/fs/struct.Metadata.html#method.is_file #[stable(feature = "path_ext", since = "1.5.0")] pub fn is_file(&self) -> bool { fs::metadata(self).map(|m| m.is_file()).unwrap_or(false) @@ -2248,6 +2270,9 @@ impl Path { /// This function will traverse symbolic links to query information about the /// destination file. In case of broken symbolic links this will return `false`. /// + /// If you cannot access the directory containing the file, e.g. because of a + /// permission error, this will return `false`. + /// /// # Examples /// /// ```no_run @@ -2255,6 +2280,15 @@ impl Path { /// assert_eq!(Path::new("./is_a_directory/").is_dir(), true); /// assert_eq!(Path::new("a_file.txt").is_dir(), false); /// ``` + /// + /// # See Also + /// + /// This is a convenience function that coerces errors to false. If you want to + /// check errors, call [fs::metadata] and handle its Result. Then call + /// [fs::Metadata::is_dir] if it was Ok. + /// + /// [fs::metadata]: ../../std/fs/fn.metadata.html + /// [fs::Metadata::is_dir]: ../../std/fs/struct.Metadata.html#method.is_dir #[stable(feature = "path_ext", since = "1.5.0")] pub fn is_dir(&self) -> bool { fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false) -- cgit 1.4.1-3-g733a5 From bd9428a46b7290b8f87d830655b473099207ae0d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 12 Jul 2017 20:39:02 -0600 Subject: Update mod.rs --- src/libstd/sys/redox/mod.rs | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) (limited to 'src') diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs index 31c40ea58b1..bd5b40de9a0 100644 --- a/src/libstd/sys/redox/mod.rs +++ b/src/libstd/sys/redox/mod.rs @@ -40,23 +40,7 @@ pub mod time; #[cfg(not(test))] pub fn init() { - use alloc::oom; - - oom::set_oom_handler(oom_handler); - - // A nicer handler for out-of-memory situations than the default one. This - // one prints a message to stderr before aborting. It is critical that this - // code does not allocate any memory since we are in an OOM situation. Any - // errors are ignored while printing since there's nothing we can do about - // them and we are about to exit anyways. - fn oom_handler() -> ! { - use intrinsics; - let msg = "fatal runtime error: out of memory\n"; - unsafe { - let _ = syscall::write(2, msg.as_bytes()); - intrinsics::abort(); - } - } + } pub fn decode_error_kind(errno: i32) -> ErrorKind { -- cgit 1.4.1-3-g733a5 From 362dd8a98690adaf3a3f6b5b9f6edc697fbd3ed9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 12 Jul 2017 20:40:43 -0600 Subject: Update fs.rs --- src/libstd/sys/redox/fs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 87e50c40148..27ded432b95 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -384,8 +384,9 @@ pub fn unlink(p: &Path) -> io::Result<()> { } pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { - ::sys_common::util::dumb_print(format_args!("Rename\n")); - unimplemented!(); + copy(old, new)?; + unlink(old)?; + Ok(()) } pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { -- cgit 1.4.1-3-g733a5 From 21f2ace8cfaa6c6cd137cfa3b11222f4a06a0b87 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 12 Jul 2017 20:48:04 -0600 Subject: Update mod.rs --- src/libstd/sys/redox/mod.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs index bd5b40de9a0..7c728ebb1af 100644 --- a/src/libstd/sys/redox/mod.rs +++ b/src/libstd/sys/redox/mod.rs @@ -39,9 +39,7 @@ pub mod thread_local; pub mod time; #[cfg(not(test))] -pub fn init() { - -} +pub fn init() {} pub fn decode_error_kind(errno: i32) -> ErrorKind { match errno { -- cgit 1.4.1-3-g733a5 From 4259ae64755f3b72296b95a9eeabaf883321069b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 12 Jul 2017 22:16:35 -0600 Subject: Update fs.rs --- src/libstd/sys/redox/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 27ded432b95..918893097f8 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -383,7 +383,7 @@ pub fn unlink(p: &Path) -> io::Result<()> { Ok(()) } -pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { +pub fn rename(old: &Path, new: &Path) -> io::Result<()> { copy(old, new)?; unlink(old)?; Ok(()) -- cgit 1.4.1-3-g733a5