From bfbd732daebe5f7cd26e3244a6377f0e3ab34d0f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 15 May 2014 11:15:35 -0700 Subject: [PATCH 01/22] mk: Don't run benchmarks with `make check` The current suite of benchmarks for the standard distribution take a significant amount of time to run, but it's unclear whether we're gaining any benefit from running them. Some specific pain points: * No one is looking at the data generated by the benchmarks. We have no graphs or analysis of what's happening, so all the data is largely being cast into the void. * No benchmark has ever uncovered a bug, they have always run successfully. * Benchmarks not only take a significant amount of time to run, but also take a significant amount of time to compile. I don't think we should mitigate this for now because it's useful to ensure that they do indeed still compile. This commit disables --bench test runs by default as part of `make check`, flipping the NO_BENCH environment variable to a PLEASE_BENCH variable which will manually enable benchmarking. If and when a dedicated bot is set up for benchmarking, this flag can be enabled on that bot. --- Makefile.in | 2 +- mk/tests.mk | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Makefile.in b/Makefile.in index c0e1973e95e5..5d37c1da8fb3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -68,7 +68,7 @@ # # * `TESTNAME=...` - Specify the name of tests to run # * `CHECK_IGNORED=1` - Run normally-ignored tests -# * `NO_BENCH=1` - Don't run crate benchmarks (disable `--bench` flag) +# * `PLEASE_BENCH=1` - Run crate benchmarks (enable `--bench` flag) # # * `CFG_ENABLE_VALGRIND=1` - Run tests under valgrind # * `VALGRIND_COMPILE=1` - Run the compiler itself under valgrind diff --git a/mk/tests.mk b/mk/tests.mk index befd1a737f7e..8f20d55e3859 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -32,7 +32,7 @@ ifdef CHECK_IGNORED TESTARGS += --ignored endif -TEST_BENCH = --bench +TEST_BENCH = # Arguments to the cfail/rfail/rpass/bench tests ifdef CFG_VALGRIND @@ -40,8 +40,8 @@ ifdef CFG_VALGRIND TEST_BENCH = endif -ifdef NO_BENCH - TEST_BENCH = +ifdef PLEASE_BENCH + TEST_BENCH = --bench endif # Arguments to the perf tests From ef788d51dd17cac158752f120347a9eaa5d89d98 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 14 May 2014 17:49:14 -0700 Subject: [PATCH 02/22] std: Modify TempDir to not fail on drop. Closes #12628 After discussion with Alex, we think the proper policy is for dtors to not fail. This is consistent with C++. BufferedWriter already does this, so this patch modifies TempDir to not fail in the dtor, adding a `close` method for handling errors on destruction. --- src/libstd/io/buffered.rs | 21 ++++++++++++- src/libstd/io/tempfile.rs | 36 +++++++++++++++------ src/test/run-pass/tempfile.rs | 59 +++++++++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 10 deletions(-) diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index a8e7b324bd75..68cbdd2e0aa4 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -209,7 +209,7 @@ impl Writer for BufferedWriter { impl Drop for BufferedWriter { fn drop(&mut self) { if self.inner.is_some() { - // FIXME(#12628): should this error be ignored? + // dtors should not fail, so we ignore a failed flush let _ = self.flush_buf(); } } @@ -370,6 +370,7 @@ mod test { use io; use prelude::*; use super::*; + use super::super::{IoResult, EndOfFile}; use super::super::mem::{MemReader, MemWriter, BufReader}; use self::test::Bencher; use str::StrSlice; @@ -584,6 +585,24 @@ mod test { assert_eq!(it.next(), None); } + #[test] + #[should_fail] + fn dont_fail_in_drop_on_failed_flush() { + struct FailFlushWriter; + + impl Writer for FailFlushWriter { + fn write(&mut self, _buf: &[u8]) -> IoResult<()> { Ok(()) } + fn flush(&mut self) -> IoResult<()> { Err(io::standard_error(EndOfFile)) } + } + + let writer = FailFlushWriter; + let _writer = BufferedWriter::new(writer); + + // Trigger failure. If writer fails *again* due to the flush + // error then the process will abort. + fail!(); + } + #[bench] fn bench_buffered_reader(b: &mut Bencher) { b.iter(|| { diff --git a/src/libstd/io/tempfile.rs b/src/libstd/io/tempfile.rs index 8c28caa988a5..b4fb95c8af77 100644 --- a/src/libstd/io/tempfile.rs +++ b/src/libstd/io/tempfile.rs @@ -10,7 +10,7 @@ //! Temporary files and directories -use io::fs; +use io::{fs, IoResult}; use io; use iter::{Iterator, range}; use libc; @@ -18,13 +18,14 @@ use ops::Drop; use option::{Option, None, Some}; use os; use path::{Path, GenericPath}; -use result::{Ok, Err, ResultUnwrap}; +use result::{Ok, Err}; use sync::atomics; /// A wrapper for a path to temporary directory implementing automatic /// scope-based deletion. pub struct TempDir { - path: Option + path: Option, + disarmed: bool } impl TempDir { @@ -48,7 +49,7 @@ impl TempDir { let p = tmpdir.join(filename); match fs::mkdir(&p, io::UserRWX) { Err(..) => {} - Ok(()) => return Some(TempDir { path: Some(p) }) + Ok(()) => return Some(TempDir { path: Some(p), disarmed: false }) } } None @@ -75,15 +76,32 @@ impl TempDir { pub fn path<'a>(&'a self) -> &'a Path { self.path.get_ref() } + + /// Close and remove the temporary directory + /// + /// Although `TempDir` removes the directory on drop, in the destructor + /// any errors are ignored. To detect errors cleaning up the temporary + /// directory, call `close` instead. + pub fn close(mut self) -> IoResult<()> { + self.cleanup_dir() + } + + fn cleanup_dir(&mut self) -> IoResult<()> { + assert!(!self.disarmed); + self.disarmed = true; + match self.path { + Some(ref p) => { + fs::rmdir_recursive(p) + } + None => Ok(()) + } + } } impl Drop for TempDir { fn drop(&mut self) { - for path in self.path.iter() { - if path.exists() { - // FIXME: is failing the right thing to do? - fs::rmdir_recursive(path).unwrap(); - } + if !self.disarmed { + let _ = self.cleanup_dir(); } } } diff --git a/src/test/run-pass/tempfile.rs b/src/test/run-pass/tempfile.rs index 437d6faea385..387a454542ad 100644 --- a/src/test/run-pass/tempfile.rs +++ b/src/test/run-pass/tempfile.rs @@ -74,6 +74,50 @@ fn test_rm_tempdir() { assert!(!path.exists()); } +fn test_rm_tempdir_close() { + let (tx, rx) = channel(); + let f: proc():Send = proc() { + let tmp = TempDir::new("test_rm_tempdir").unwrap(); + tx.send(tmp.path().clone()); + tmp.close(); + fail!("fail to unwind past `tmp`"); + }; + task::try(f); + let path = rx.recv(); + assert!(!path.exists()); + + let tmp = TempDir::new("test_rm_tempdir").unwrap(); + let path = tmp.path().clone(); + let f: proc():Send = proc() { + let tmp = tmp; + tmp.close(); + fail!("fail to unwind past `tmp`"); + }; + task::try(f); + assert!(!path.exists()); + + let path; + { + let f = proc() { + TempDir::new("test_rm_tempdir").unwrap() + }; + let tmp = task::try(f).ok().expect("test_rm_tmdir"); + path = tmp.path().clone(); + assert!(path.exists()); + tmp.close(); + } + assert!(!path.exists()); + + let path; + { + let tmp = TempDir::new("test_rm_tempdir").unwrap(); + path = tmp.unwrap(); + } + assert!(path.exists()); + fs::rmdir_recursive(&path); + assert!(!path.exists()); +} + // Ideally these would be in std::os but then core would need // to depend on std fn recursive_mkdir_rel() { @@ -130,6 +174,19 @@ pub fn test_rmdir_recursive_ok() { assert!(!root.join("bar").join("blat").exists()); } +pub fn dont_double_fail() { + let r: Result<(), _> = task::try(proc() { + let tmpdir = TempDir::new("test").unwrap(); + // Remove the temporary directory so that TempDir sees + // an error on drop + fs::rmdir(tmpdir.path()); + // Trigger failure. If TempDir fails *again* due to the rmdir + // error then the process will abort. + fail!(); + }); + assert!(r.is_err()); +} + fn in_tmpdir(f: ||) { let tmpdir = TempDir::new("test").expect("can't make tmpdir"); assert!(os::change_dir(tmpdir.path())); @@ -140,8 +197,10 @@ fn in_tmpdir(f: ||) { pub fn main() { in_tmpdir(test_tempdir); in_tmpdir(test_rm_tempdir); + in_tmpdir(test_rm_tempdir_close); in_tmpdir(recursive_mkdir_rel); in_tmpdir(recursive_mkdir_dot); in_tmpdir(recursive_mkdir_rel_2); in_tmpdir(test_rmdir_recursive_ok); + in_tmpdir(dont_double_fail); } From 4bcc4d76a049a50474764383889e4ede9388da9f Mon Sep 17 00:00:00 2001 From: Corey Richardson Date: Wed, 14 May 2014 16:33:15 -0700 Subject: [PATCH 03/22] rustdoc: functions in ffi blocks are unsafe Fixes #14188 --- src/librustdoc/clean.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustdoc/clean.rs b/src/librustdoc/clean.rs index 4439f626b2ce..bd911f42db0f 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -1204,7 +1204,7 @@ impl Clean for ast::ForeignItem { ForeignFunctionItem(Function { decl: decl.clean(), generics: generics.clean(), - fn_style: ast::NormalFn, + fn_style: ast::UnsafeFn, }) } ast::ForeignItemStatic(ref ty, mutbl) => { From d547de998d33e5b688533f4159ea997c940d9431 Mon Sep 17 00:00:00 2001 From: Kevin Ballard Date: Wed, 14 May 2014 14:57:27 -0700 Subject: [PATCH 04/22] Make Vec.truncate() resilient against failure in Drop If a vector element fails in Drop, Vec needs to make sure it doesn't try to re-drop any elements it already dropped. --- src/libstd/vec.rs | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 528ab72762aa..57f8d78948fa 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -635,14 +635,14 @@ impl Vec { /// ``` pub fn truncate(&mut self, len: uint) { unsafe { - let mut i = len; // drop any extra elements - while i < self.len { - ptr::read(self.as_slice().unsafe_ref(i)); - i += 1; + while len < self.len { + // decrement len before the read(), so a failure on Drop doesn't + // re-drop the just-failed value. + self.len -= 1; + ptr::read(self.as_slice().unsafe_ref(self.len)); } } - self.len = len; } /// Work with `self` as a mutable slice. @@ -1862,4 +1862,39 @@ mod tests { assert_eq!(b[0].x, 42); assert_eq!(b[1].x, 84); } + + #[test] + fn test_vec_truncate_drop() { + static mut drops: uint = 0; + struct Elem(int); + impl Drop for Elem { + fn drop(&mut self) { + unsafe { drops += 1; } + } + } + + let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)]; + assert_eq!(unsafe { drops }, 0); + v.truncate(3); + assert_eq!(unsafe { drops }, 2); + v.truncate(0); + assert_eq!(unsafe { drops }, 5); + } + + #[test] + #[should_fail] + fn test_vec_truncate_fail() { + struct BadElem(int); + impl Drop for BadElem { + fn drop(&mut self) { + let BadElem(ref mut x) = *self; + if *x == 0xbadbeef { + fail!("BadElem failure: 0xbadbeef") + } + } + } + + let mut v = vec![BadElem(1), BadElem(2), BadElem(0xbadbeef), BadElem(4)]; + v.truncate(0); + } } From 912a9675c0b7f9e8c836983e525b180c48693925 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Wed, 14 May 2014 14:39:16 -0700 Subject: [PATCH 05/22] Make `from_bits` in `bitflags!` safe; add `from_bits_truncate` Previously, the `from_bits` function in the `std::bitflags::bitflags` macro was marked as unsafe, as it did not check that the bits being converted actually corresponded to flags. This patch changes the function to check against the full set of possible flags and return an `Option` which is `None` if a non-flag bit is set. It also adds a `from_bits_truncate` function which simply zeros any bits not corresponding to a flag. This addresses the concern raised in https://github.com/mozilla/rust/pull/13897 --- src/libnative/io/file_unix.rs | 4 +--- src/libnative/io/file_win32.rs | 4 +--- src/librustuv/file.rs | 4 +--- src/libstd/bitflags.rs | 37 +++++++++++++++++++++++++++------- 4 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/libnative/io/file_unix.rs b/src/libnative/io/file_unix.rs index c2b69483fa1e..046d2875d553 100644 --- a/src/libnative/io/file_unix.rs +++ b/src/libnative/io/file_unix.rs @@ -493,9 +493,7 @@ fn mkstat(stat: &libc::stat) -> io::FileStat { io::FileStat { size: stat.st_size as u64, kind: kind, - perm: unsafe { - io::FilePermission::from_bits(stat.st_mode as u32) & io::AllPermissions - }, + perm: io::FilePermission::from_bits_truncate(stat.st_mode as u32), created: mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64), modified: mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64), accessed: mktime(stat.st_atime as u64, stat.st_atime_nsec as u64), diff --git a/src/libnative/io/file_win32.rs b/src/libnative/io/file_win32.rs index d721e1d67f1b..3222c912dd08 100644 --- a/src/libnative/io/file_win32.rs +++ b/src/libnative/io/file_win32.rs @@ -492,9 +492,7 @@ fn mkstat(stat: &libc::stat) -> io::FileStat { io::FileStat { size: stat.st_size as u64, kind: kind, - perm: unsafe { - io::FilePermission::from_bits(stat.st_mode as u32) & io::AllPermissions - }, + perm: io::FilePermission::from_bits_truncate(stat.st_mode as u32), created: stat.st_ctime as u64, modified: stat.st_mtime as u64, accessed: stat.st_atime as u64, diff --git a/src/librustuv/file.rs b/src/librustuv/file.rs index 06271e61ce7a..12636a3c490a 100644 --- a/src/librustuv/file.rs +++ b/src/librustuv/file.rs @@ -285,9 +285,7 @@ impl FsRequest { FileStat { size: stat.st_size as u64, kind: kind, - perm: unsafe { - io::FilePermission::from_bits(stat.st_mode as u32) & io::AllPermissions - }, + perm: io::FilePermission::from_bits_truncate(stat.st_mode as u32), created: to_msec(stat.st_birthtim), modified: to_msec(stat.st_mtim), accessed: to_msec(stat.st_atim), diff --git a/src/libstd/bitflags.rs b/src/libstd/bitflags.rs index 32f9bc1173b2..163ccd22552d 100644 --- a/src/libstd/bitflags.rs +++ b/src/libstd/bitflags.rs @@ -136,10 +136,20 @@ macro_rules! bitflags( self.bits } - /// Convert from underlying bit representation. Unsafe because the - /// bits are not guaranteed to represent valid flags. - pub unsafe fn from_bits(bits: $T) -> $BitFlags { - $BitFlags { bits: bits } + /// Convert from underlying bit representation, unless that + /// representation contains bits that do not correspond to a flag. + pub fn from_bits(bits: $T) -> ::std::option::Option<$BitFlags> { + if (bits & !$BitFlags::all().bits()) != 0 { + ::std::option::None + } else { + ::std::option::Some($BitFlags { bits: bits }) + } + } + + /// Convert from underlying bit representation, dropping any bits + /// that do not correspond to flags. + pub fn from_bits_truncate(bits: $T) -> $BitFlags { + $BitFlags { bits: bits } & $BitFlags::all() } /// Returns `true` if no flags are currently stored. @@ -209,6 +219,7 @@ macro_rules! bitflags( #[cfg(test)] mod tests { + use option::{Some, None}; use ops::{BitOr, BitAnd, Sub, Not}; bitflags!( @@ -231,9 +242,21 @@ mod tests { #[test] fn test_from_bits() { - assert!(unsafe { Flags::from_bits(0x00000000) } == Flags::empty()); - assert!(unsafe { Flags::from_bits(0x00000001) } == FlagA); - assert!(unsafe { Flags::from_bits(0x00000111) } == FlagABC); + assert!(Flags::from_bits(0) == Some(Flags::empty())); + assert!(Flags::from_bits(0x1) == Some(FlagA)); + assert!(Flags::from_bits(0x10) == Some(FlagB)); + assert!(Flags::from_bits(0x11) == Some(FlagA | FlagB)); + assert!(Flags::from_bits(0x1000) == None); + } + + #[test] + fn test_from_bits_truncate() { + assert!(Flags::from_bits_truncate(0) == Flags::empty()); + assert!(Flags::from_bits_truncate(0x1) == FlagA); + assert!(Flags::from_bits_truncate(0x10) == FlagB); + assert!(Flags::from_bits_truncate(0x11) == (FlagA | FlagB)); + assert!(Flags::from_bits_truncate(0x1000) == Flags::empty()); + assert!(Flags::from_bits_truncate(0x1001) == FlagA); } #[test] From 8211539114df8b6e3a9b8b251fa57cb5a77d2f14 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 14 May 2014 14:24:41 -0700 Subject: [PATCH 06/22] Register new snapshots --- src/libcore/lib.rs | 3 -- src/libcore/owned.rs | 101 ------------------------------------------- src/libstd/lib.rs | 7 +-- src/snapshots.txt | 8 ++++ 4 files changed, 10 insertions(+), 109 deletions(-) delete mode 100644 src/libcore/owned.rs diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 4eab7e9d45d3..9e3a92981e53 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -116,9 +116,6 @@ pub mod slice; pub mod str; pub mod tuple; -#[cfg(stage0, not(test))] -pub mod owned; - // FIXME: this module should not exist. Once owned allocations are no longer a // language type, this module can move outside to the owned allocation // crate. diff --git a/src/libcore/owned.rs b/src/libcore/owned.rs deleted file mode 100644 index 3af12c5154c2..000000000000 --- a/src/libcore/owned.rs +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2012 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. - -//! Operations on unique pointer types - -use any::{Any, AnyRefExt}; -use clone::Clone; -use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering}; -use default::Default; -use intrinsics; -use mem; -use raw::TraitObject; -use result::{Ok, Err, Result}; - -/// A value that represents the global exchange heap. This is the default -/// place that the `box` keyword allocates into when no place is supplied. -/// -/// The following two examples are equivalent: -/// -/// let foo = box(HEAP) Bar::new(...); -/// let foo = box Bar::new(...); -#[lang="exchange_heap"] -pub static HEAP: () = (); - -/// A type that represents a uniquely-owned value. -#[lang="owned_box"] -pub struct Box(*T); - -impl Default for Box { - fn default() -> Box { box Default::default() } -} - -impl Clone for Box { - /// Return a copy of the owned box. - #[inline] - fn clone(&self) -> Box { box {(**self).clone()} } - - /// Perform copy-assignment from `source` by reusing the existing allocation. - #[inline] - fn clone_from(&mut self, source: &Box) { - (**self).clone_from(&(**source)); - } -} - -// box pointers -impl Eq for Box { - #[inline] - fn eq(&self, other: &Box) -> bool { *(*self) == *(*other) } - #[inline] - fn ne(&self, other: &Box) -> bool { *(*self) != *(*other) } -} -impl Ord for Box { - #[inline] - fn lt(&self, other: &Box) -> bool { *(*self) < *(*other) } - #[inline] - fn le(&self, other: &Box) -> bool { *(*self) <= *(*other) } - #[inline] - fn ge(&self, other: &Box) -> bool { *(*self) >= *(*other) } - #[inline] - fn gt(&self, other: &Box) -> bool { *(*self) > *(*other) } -} -impl TotalOrd for Box { - #[inline] - fn cmp(&self, other: &Box) -> Ordering { (**self).cmp(*other) } -} -impl TotalEq for Box {} - -/// Extension methods for an owning `Any` trait object -pub trait AnyOwnExt { - /// Returns the boxed value if it is of type `T`, or - /// `Err(Self)` if it isn't. - fn move(self) -> Result, Self>; -} - -impl AnyOwnExt for Box { - #[inline] - fn move(self) -> Result, Box> { - if self.is::() { - unsafe { - // Get the raw representation of the trait object - let to: TraitObject = - *mem::transmute::<&Box, &TraitObject>(&self); - - // Prevent destructor on self being run - intrinsics::forget(self); - - // Extract the data pointer - Ok(mem::transmute(to.data)) - } - } else { - Err(self) - } - } -} diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index a37f9a516fdb..87c4ef1046f1 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -133,16 +133,13 @@ extern crate core; #[cfg(test)] pub use ops = realstd::ops; #[cfg(test)] pub use cmp = realstd::cmp; #[cfg(test)] pub use ty = realstd::ty; -#[cfg(not(stage0), test)] pub use owned = realstd::owned; +#[cfg(test)] pub use owned = realstd::owned; #[cfg(not(test))] pub use cmp = core::cmp; #[cfg(not(test))] pub use kinds = core::kinds; #[cfg(not(test))] pub use ops = core::ops; #[cfg(not(test))] pub use ty = core::ty; -#[cfg(stage0, test)] pub use owned = realstd::owned; -#[cfg(stage0, not(test))] pub use owned = core::owned; - pub use core::any; pub use core::bool; pub use core::cell; @@ -209,7 +206,7 @@ pub mod ascii; pub mod rc; pub mod gc; -#[cfg(not(stage0), not(test))] +#[cfg(not(test))] pub mod owned; /* Common traits */ diff --git a/src/snapshots.txt b/src/snapshots.txt index e88ae02c1c65..4c62d519d781 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,11 @@ +S 2014-05-15 6a2b3d1 + freebsd-x86_64 afc98b59cb819025fecdb9d145ca4463f857a477 + linux-i386 d6f7a404412ea34db3d19814ca21fe6fa662b02f + linux-x86_64 3dfb54406a7ea75565a7ea3071daad885cb91775 + macos-i386 bebb937551d601ad908c9e4eaa196cc7a977c503 + macos-x86_64 08346ed401ad2891c7d2ba0aac0960f6e77bb78b + winnt-i386 ad8e5b8292a00f60f1f7dc2e35bd18abeb5b858d + S 2014-05-11 72fc4a5 freebsd-x86_64 82db6355b0b7c8023c8845a74e2f224da2831b50 linux-i386 91901299d5f86f5b67377d940073908a1f0e4e82 From e043644cea119ea701a293a01b6d4c5c0f13f450 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 14 May 2014 15:54:19 -0400 Subject: [PATCH 07/22] use sched_yield on linux and freebsd pthread_yield is non-standard, while sched_yield is POSIX The Linux documentation recommends using the standard function. This is the only feature we're currently using that's present in glibc but not in musl. --- src/libstd/rt/thread.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs index 4f0d7d35ce89..e25fa4734d5c 100644 --- a/src/libstd/rt/thread.rs +++ b/src/libstd/rt/thread.rs @@ -273,13 +273,8 @@ mod imp { assert_eq!(pthread_detach(native), 0); } - #[cfg(target_os = "macos")] - #[cfg(target_os = "android")] pub unsafe fn yield_now() { assert_eq!(sched_yield(), 0); } - #[cfg(not(target_os = "macos"), not(target_os = "android"))] - pub unsafe fn yield_now() { assert_eq!(pthread_yield(), 0); } - // glibc >= 2.15 has a __pthread_get_minstack() function that returns // PTHREAD_STACK_MIN plus however many bytes are needed for thread-local // storage. We need that information to avoid blowing up when a small stack @@ -326,12 +321,7 @@ mod imp { fn pthread_attr_setdetachstate(attr: *mut libc::pthread_attr_t, state: libc::c_int) -> libc::c_int; fn pthread_detach(thread: libc::pthread_t) -> libc::c_int; - - #[cfg(target_os = "macos")] - #[cfg(target_os = "android")] fn sched_yield() -> libc::c_int; - #[cfg(not(target_os = "macos"), not(target_os = "android"))] - fn pthread_yield() -> libc::c_int; } } From a7bee7b05d59467bc6304b32eb14e617c2efbfc9 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 14 May 2014 11:24:12 -0700 Subject: [PATCH 08/22] Add a crate for missing stubs from libcore The core library in theory has 0 dependencies, but in practice it has some in order for it to be efficient. These dependencies are in the form of the basic memory operations provided by libc traditionally, such as memset, memcmp, etc. These functions are trivial to implement and themselves have 0 dependencies. This commit adds a new crate, librlibc, which will serve the purpose of providing these dependencies. The crate is never linked to by default, but is available to be linked to by downstream consumers. Normally these functions are provided by the system libc, but in other freestanding contexts a libc may not be available. In these cases, librlibc will suffice for enabling execution with libcore. cc #10116 --- mk/crates.mk | 4 +- src/doc/rust.md | 2 + src/libcore/lib.rs | 3 + src/librlibc/lib.rs | 99 +++++++++++++++++++++++++++++++ src/librustc/back/link.rs | 21 ++++--- src/librustc/driver/driver.rs | 1 + src/librustc/lib/llvm.rs | 6 +- src/librustc/middle/lint.rs | 1 + src/librustc/middle/trans/base.rs | 2 + src/rustllvm/PassWrapper.cpp | 18 ++++-- 10 files changed, 141 insertions(+), 16 deletions(-) create mode 100644 src/librlibc/lib.rs diff --git a/mk/crates.mk b/mk/crates.mk index 0b923cca7a2b..b43accf61048 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -51,12 +51,13 @@ TARGET_CRATES := libc std green rustuv native flate arena glob term semver \ uuid serialize sync getopts collections num test time rand \ - workcache url log regex graphviz core + workcache url log regex graphviz core rlibc HOST_CRATES := syntax rustc rustdoc fourcc hexfloat regex_macros fmt_macros CRATES := $(TARGET_CRATES) $(HOST_CRATES) TOOLS := compiletest rustdoc rustc DEPS_core := +DEPS_rlibc := DEPS_std := core libc native:rustrt native:compiler-rt native:backtrace native:jemalloc DEPS_green := std rand native:context_switch DEPS_rustuv := std native:uv native:uv_support @@ -98,6 +99,7 @@ TOOL_SOURCE_rustdoc := $(S)src/driver/driver.rs TOOL_SOURCE_rustc := $(S)src/driver/driver.rs ONLY_RLIB_core := 1 +ONLY_RLIB_rlibc := 1 ################################################################################ # You should not need to edit below this line diff --git a/src/doc/rust.md b/src/doc/rust.md index f242a89784ce..838ddca042df 100644 --- a/src/doc/rust.md +++ b/src/doc/rust.md @@ -1799,6 +1799,8 @@ type int8_t = i8; - `no_start` - disable linking to the `native` crate, which specifies the "start" language item. - `no_std` - disable linking to the `std` crate. +- `no_builtins` - disable optimizing certain code patterns to invocations of + library functions that are assumed to exist ### Module-only attributes diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 9e3a92981e53..4102c72d8b64 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -18,6 +18,9 @@ //! * `memcpy`, `memcmp`, `memset` - These are core memory routines which are //! often generated by LLVM. Additionally, this library can make explicit //! calls to these funcitons. Their signatures are the same as found in C. +//! These functions are often provided by the system libc, but can also be +//! provided by `librlibc` which is distributed with the standard rust +//! distribution. //! //! * `rust_begin_unwind` - This function takes three arguments, a //! `&fmt::Arguments`, a `&str`, and a `uint. These three arguments dictate diff --git a/src/librlibc/lib.rs b/src/librlibc/lib.rs new file mode 100644 index 000000000000..904fbe9be9b2 --- /dev/null +++ b/src/librlibc/lib.rs @@ -0,0 +1,99 @@ +// Copyright 2014 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. + +//! A bare-metal library supplying functions rustc may lower code to +//! +//! This library is not intended for general use, and is superseded by a system +//! libc if one is available. In a freestanding context, however, common +//! functions such as memset, memcpy, etc are not implemented. This library +//! provides an implementation of these functions which are either required by +//! libcore or called by rustc implicitly. +//! +//! This library is never included by default, and must be manually included if +//! necessary. It is an error to include this library when also linking with +//! the system libc library. + +#![crate_id = "rlibc#0.11.0-pre"] +#![license = "MIT/ASL2"] +#![crate_type = "rlib"] +#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "http://www.rust-lang.org/favicon.ico", + html_root_url = "http://static.rust-lang.org/doc/master")] + +#![no_std] +#![experimental] + +// This library is definining the builtin functions, so it would be a shame for +// LLVM to optimize these function calls to themselves! +#![no_builtins] + +#[cfg(test)] extern crate std; +#[cfg(test)] extern crate native; + +// Require the offset intrinsics for LLVM to properly optimize the +// implementations below. If pointer arithmetic is done through integers the +// optimizations start to break down. +extern "rust-intrinsic" { + fn offset(dst: *T, offset: int) -> *T; +} + +#[no_mangle] +pub unsafe extern "C" fn memcpy(dest: *mut u8, src: *u8, n: uint) -> *mut u8 { + let mut i = 0; + while i < n { + *(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int); + i += 1; + } + return dest; +} + +#[no_mangle] +pub unsafe extern "C" fn memmove(dest: *mut u8, src: *u8, n: uint) -> *mut u8 { + if src < dest as *u8 { // copy from end + let mut i = n; + while i != 0 { + i -= 1; + *(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int); + } + } else { // copy from beginning + let mut i = 0; + while i < n { + *(offset(dest as *u8, i as int) as *mut u8) = *offset(src, i as int); + i += 1; + } + } + return dest; +} + +#[no_mangle] +pub unsafe extern "C" fn memset(s: *mut u8, c: i32, n: uint) -> *mut u8 { + let mut i = 0; + while i < n { + *(offset(s as *u8, i as int) as *mut u8) = c as u8; + i += 1; + } + return s; +} + +#[no_mangle] +pub unsafe extern "C" fn memcmp(s1: *u8, s2: *u8, n: uint) -> i32 { + let mut i = 0; + while i < n { + let a = *offset(s1, i as int); + let b = *offset(s2, i as int); + if a != b { + return (a - b) as i32 + } + i += 1; + } + return 0; +} + +#[test] fn work_on_windows() { } // FIXME #10872 needed for a happy windows diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 4d70ecb888fd..429a8f5be5eb 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -212,7 +212,8 @@ pub mod write { if !sess.opts.cg.no_prepopulate_passes { llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod); llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod); - populate_llvm_passes(fpm, mpm, llmod, opt_level); + populate_llvm_passes(fpm, mpm, llmod, opt_level, + trans.no_builtins); } for pass in sess.opts.cg.passes.iter() { @@ -264,11 +265,11 @@ pub mod write { // escape the closure itself, and the manager should only be // used once. fn with_codegen(tm: TargetMachineRef, llmod: ModuleRef, - f: |PassManagerRef|) { + no_builtins: bool, f: |PassManagerRef|) { unsafe { let cpm = llvm::LLVMCreatePassManager(); llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod); - llvm::LLVMRustAddLibraryInfo(cpm, llmod); + llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); f(cpm); llvm::LLVMDisposePassManager(cpm); } @@ -286,7 +287,7 @@ pub mod write { } OutputTypeLlvmAssembly => { path.with_c_str(|output| { - with_codegen(tm, llmod, |cpm| { + with_codegen(tm, llmod, trans.no_builtins, |cpm| { llvm::LLVMRustPrintModule(cpm, llmod, output); }) }) @@ -303,7 +304,7 @@ pub mod write { needs_metadata = true; output.temp_path(OutputTypeAssembly) }; - with_codegen(tm, llmod, |cpm| { + with_codegen(tm, llmod, trans.no_builtins, |cpm| { WriteOutputFile(sess, tm, cpm, llmod, &path, lib::llvm::AssemblyFile); }); @@ -321,7 +322,7 @@ pub mod write { time(sess.time_passes(), "codegen passes", (), |()| { match object_file { Some(ref path) => { - with_codegen(tm, llmod, |cpm| { + with_codegen(tm, llmod, trans.no_builtins, |cpm| { WriteOutputFile(sess, tm, cpm, llmod, path, lib::llvm::ObjectFile); }); @@ -329,7 +330,8 @@ pub mod write { None => {} } if needs_metadata { - with_codegen(tm, trans.metadata_module, |cpm| { + with_codegen(tm, trans.metadata_module, + trans.no_builtins, |cpm| { let out = output.temp_path(OutputTypeObject) .with_extension("metadata.o"); WriteOutputFile(sess, tm, cpm, @@ -437,7 +439,8 @@ pub mod write { unsafe fn populate_llvm_passes(fpm: lib::llvm::PassManagerRef, mpm: lib::llvm::PassManagerRef, llmod: ModuleRef, - opt: lib::llvm::CodeGenOptLevel) { + opt: lib::llvm::CodeGenOptLevel, + no_builtins: bool) { // Create the PassManagerBuilder for LLVM. We configure it with // reasonable defaults and prepare it to actually populate the pass // manager. @@ -461,7 +464,7 @@ pub mod write { } } llvm::LLVMPassManagerBuilderSetOptLevel(builder, opt as c_uint); - llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod); + llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, no_builtins); // Use the builder to populate the function/module pass managers. llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(builder, fpm); diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 51bdf9ef9edd..0b731e18f557 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -356,6 +356,7 @@ pub struct CrateTranslation { pub metadata: Vec, pub reachable: Vec, pub crate_formats: dependency_format::Dependencies, + pub no_builtins: bool, } /// Run the translation phase to LLVM, after which the AST and analysis can diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 0c874bd776ed..711081f46d66 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -1755,8 +1755,10 @@ pub mod llvm { PM: PassManagerRef, M: ModuleRef); pub fn LLVMRustAddBuilderLibraryInfo(PMB: PassManagerBuilderRef, - M: ModuleRef); - pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef); + M: ModuleRef, + DisableSimplifyLibCalls: bool); + pub fn LLVMRustAddLibraryInfo(PM: PassManagerRef, M: ModuleRef, + DisableSimplifyLibCalls: bool); pub fn LLVMRustRunFunctionPassManager(PM: PassManagerRef, M: ModuleRef); pub fn LLVMRustWriteOutputFile(T: TargetMachineRef, PM: PassManagerRef, diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 062a7418287e..1c24d609551a 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -1050,6 +1050,7 @@ fn check_raw_ptr_deriving(cx: &mut Context, item: &ast::Item) { static crate_attrs: &'static [&'static str] = &[ "crate_type", "feature", "no_start", "no_main", "no_std", "crate_id", "desc", "comment", "license", "copyright", // not used in rustc now + "no_builtins", ]; diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 17aa0664d479..92e3b95abadc 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2226,6 +2226,7 @@ pub fn trans_crate(krate: ast::Crate, let metadata_module = ccx.metadata_llmod; let formats = ccx.tcx.dependency_formats.borrow().clone(); + let no_builtins = attr::contains_name(krate.attrs.as_slice(), "no_builtins"); (ccx.tcx, CrateTranslation { context: llcx, @@ -2235,5 +2236,6 @@ pub fn trans_crate(krate: ast::Crate, metadata: metadata, reachable: reachable, crate_formats: formats, + no_builtins: no_builtins, }) } diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 1031f3c1570e..64776421fa14 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -128,17 +128,27 @@ LLVMRustAddAnalysisPasses(LLVMTargetMachineRef TM, // Unfortunately, the LLVM C API doesn't provide a way to set the `LibraryInfo` // field of a PassManagerBuilder, we expose our own method of doing so. extern "C" void -LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB, LLVMModuleRef M) { +LLVMRustAddBuilderLibraryInfo(LLVMPassManagerBuilderRef PMB, + LLVMModuleRef M, + bool DisableSimplifyLibCalls) { Triple TargetTriple(unwrap(M)->getTargetTriple()); - unwrap(PMB)->LibraryInfo = new TargetLibraryInfo(TargetTriple); + TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple); + if (DisableSimplifyLibCalls) + TLI->disableAllFunctions(); + unwrap(PMB)->LibraryInfo = TLI; } // Unfortunately, the LLVM C API doesn't provide a way to create the // TargetLibraryInfo pass, so we use this method to do so. extern "C" void -LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, LLVMModuleRef M) { +LLVMRustAddLibraryInfo(LLVMPassManagerRef PMB, + LLVMModuleRef M, + bool DisableSimplifyLibCalls) { Triple TargetTriple(unwrap(M)->getTargetTriple()); - unwrap(PMB)->add(new TargetLibraryInfo(TargetTriple)); + TargetLibraryInfo *TLI = new TargetLibraryInfo(TargetTriple); + if (DisableSimplifyLibCalls) + TLI->disableAllFunctions(); + unwrap(PMB)->add(TLI); } // Unfortunately, the LLVM C API doesn't provide an easy way of iterating over From 03f48534b3ac38bc3792019cdd2b8a24eaebee50 Mon Sep 17 00:00:00 2001 From: Kevin Butler Date: Tue, 13 May 2014 21:15:11 +0100 Subject: [PATCH 09/22] shootout-mandlebrot: calculate two bits of the result per inner loop, +10-15% --- src/test/bench/shootout-mandelbrot.rs | 76 +++++++++++++++++++-------- 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index e17324ee5964..5302bd1dd631 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -7,6 +7,7 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(macro_rules)] // ignore-pretty very bad with line comments @@ -18,27 +19,56 @@ use sync::Future; static ITER: int = 50; static LIMIT: f64 = 2.0; -fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec) { - for chunk_init_r in vec_init_r.chunks(8) { - let mut cur_byte = 0xff; - let mut cur_bitmask = 0x80; - for &init_r in chunk_init_r.iter() { - let mut cur_r = init_r; - let mut cur_i = init_i; - for _ in range(0, ITER) { - let r = cur_r; - let i = cur_i; - cur_r = r * r - i * i + init_r; - cur_i = 2.0 * r * i + init_i; +macro_rules! core_loop( + ($pow:expr ~ $mask:expr: $ctx:ident, $b:ident) => ( + { + let r = $ctx.r; + let i = $ctx.i; - if r * r + i * i > LIMIT * LIMIT { - cur_byte &= !cur_bitmask; - break; - } + $ctx.r = r * r - i * i + $ctx.init_r; + $ctx.i = 2.0 * r * i + $ctx.init_i; + + if r * r + i * i > LIMIT * LIMIT { + $b |= $pow; + if $b == $mask { break; } } - cur_bitmask >>= 1; } - res.push(cur_byte); + ); +) + +#[inline(always)] +fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec) { + struct Context { r: f64, i: f64, init_i: f64, init_r: f64 } + impl Context { + #[inline(always)] + fn new(i: f64, r: f64) -> Context { + Context { r: r, i: i, init_r: r, init_i: i } + } + } + + let mut cur_byte; + let mut i; + let mut bit_1; + let mut bit_2; + let mut b; + for chunk_init_r in vec_init_r.chunks(8) { + cur_byte = 0xff; + i = 0; + + while i < 8 { + bit_1 = Context::new(init_i, chunk_init_r[i]); + bit_2 = Context::new(init_i, chunk_init_r[i + 1]); + + b = 0; + for _ in range(0, ITER) { + core_loop!(2 ~ 3: bit_1, b); + core_loop!(1 ~ 3: bit_2, b); + } + + cur_byte = (cur_byte << 2) + b; + i += 2; + } + res.push(cur_byte^-1); } } @@ -46,13 +76,15 @@ fn mandelbrot(w: uint, mut out: W) -> io::IoResult<()> { // Ensure w and h are multiples of 8. let w = (w + 7) / 8 * 8; let h = w; - let chunk_size = h / 8; + let inverse_w_doubled = 2.0 / w as f64; + let inverse_h_doubled = 2.0 / h as f64; + let chunk_size = h / 16; - let data: Vec>> = range(0u, 8).map(|i| Future::spawn(proc () { - let vec_init_r = Vec::from_fn(w, |x| 2.0 * (x as f64) / (w as f64) - 1.5); + let data: Vec>> = range(0u, 16).map(|i| Future::spawn(proc () { + let vec_init_r = Vec::from_fn(w, |x| (x as f64) * inverse_w_doubled - 1.5); let mut res: Vec = Vec::with_capacity((chunk_size * w) / 8); for y in range(i * chunk_size, (i + 1) * chunk_size) { - let init_i = 2.0 * (y as f64) / (h as f64) - 1.0; + let init_i = (y as f64) * inverse_h_doubled - 1.0; write_line(init_i, vec_init_r.as_slice(), &mut res); } res From b9e4fcbf04b21c39b5e704a1f24adbfe179f8814 Mon Sep 17 00:00:00 2001 From: Kevin Butler Date: Wed, 14 May 2014 19:08:06 +0100 Subject: [PATCH 10/22] shootout-mandelbrot: Precalc initial values & use SIMD in the main loop. +80-100% --- src/test/bench/shootout-mandelbrot.rs | 194 +++++++++++++++++--------- 1 file changed, 129 insertions(+), 65 deletions(-) diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index 5302bd1dd631..debd12874da1 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -8,87 +8,103 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(macro_rules)] +#![feature(simd)] +#![allow(experimental)] // ignore-pretty very bad with line comments extern crate sync; use std::io; +use std::os; +use std::unstable::simd::f64x2; use sync::Future; +use sync::Arc; static ITER: int = 50; static LIMIT: f64 = 2.0; - -macro_rules! core_loop( - ($pow:expr ~ $mask:expr: $ctx:ident, $b:ident) => ( - { - let r = $ctx.r; - let i = $ctx.i; - - $ctx.r = r * r - i * i + $ctx.init_r; - $ctx.i = 2.0 * r * i + $ctx.init_i; - - if r * r + i * i > LIMIT * LIMIT { - $b |= $pow; - if $b == $mask { break; } - } - } - ); -) +static WORKERS: uint = 16; #[inline(always)] -fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec) { - struct Context { r: f64, i: f64, init_i: f64, init_r: f64 } - impl Context { - #[inline(always)] - fn new(i: f64, r: f64) -> Context { - Context { r: r, i: i, init_r: r, init_i: i } - } - } - - let mut cur_byte; - let mut i; - let mut bit_1; - let mut bit_2; - let mut b; - for chunk_init_r in vec_init_r.chunks(8) { - cur_byte = 0xff; - i = 0; - - while i < 8 { - bit_1 = Context::new(init_i, chunk_init_r[i]); - bit_2 = Context::new(init_i, chunk_init_r[i + 1]); - - b = 0; - for _ in range(0, ITER) { - core_loop!(2 ~ 3: bit_1, b); - core_loop!(1 ~ 3: bit_2, b); - } - - cur_byte = (cur_byte << 2) + b; - i += 2; - } - res.push(cur_byte^-1); - } -} - fn mandelbrot(w: uint, mut out: W) -> io::IoResult<()> { + assert!(WORKERS % 2 == 0); + // Ensure w and h are multiples of 8. let w = (w + 7) / 8 * 8; let h = w; + + let chunk_size = h / WORKERS; + + // Account for remainders in workload division, e.g. 1000 / 16 = 62.5 + let first_chunk_size = if h % WORKERS != 0 { + chunk_size + h % WORKERS + } else { + chunk_size + }; + + // precalc values let inverse_w_doubled = 2.0 / w as f64; let inverse_h_doubled = 2.0 / h as f64; - let chunk_size = h / 16; + let v_inverses = f64x2(inverse_w_doubled, inverse_h_doubled); + let v_consts = f64x2(1.5, 1.0); - let data: Vec>> = range(0u, 16).map(|i| Future::spawn(proc () { - let vec_init_r = Vec::from_fn(w, |x| (x as f64) * inverse_w_doubled - 1.5); - let mut res: Vec = Vec::with_capacity((chunk_size * w) / 8); - for y in range(i * chunk_size, (i + 1) * chunk_size) { - let init_i = (y as f64) * inverse_h_doubled - 1.0; - write_line(init_i, vec_init_r.as_slice(), &mut res); - } - res - })).collect(); + // A lot of this code assumes this (so do other lang benchmarks) + assert!(w == h); + let mut precalc_r = Vec::with_capacity(w); + let mut precalc_i = Vec::with_capacity(h); + + let precalc_futures = Vec::from_fn(WORKERS, |i| { + Future::spawn(proc () { + let mut rs = Vec::with_capacity(w / WORKERS); + let mut is = Vec::with_capacity(w / WORKERS); + + let start = i * chunk_size; + let end = if i == 0 { + first_chunk_size + } else { + (i + 1) * chunk_size + }; + + // This assumes w == h + for x in range(start, end) { + let xf = x as f64; + let xy = f64x2(xf, xf); + + let f64x2(r, i) = xy * v_inverses - v_consts; + rs.push(r); + is.push(i); + } + + (rs, is) + }) + }); + + for res in precalc_futures.move_iter() { + let (rs, is) = res.unwrap(); + precalc_r.push_all_move(rs); + precalc_i.push_all_move(is); + } + + assert_eq!(precalc_r.len(), w); + assert_eq!(precalc_i.len(), h); + + let arc_init_r = Arc::new(precalc_r); + let arc_init_i = Arc::new(precalc_i); + + let data = Vec::from_fn(WORKERS, |i| { + let vec_init_r = arc_init_r.clone(); + let vec_init_i = arc_init_i.clone(); + + Future::spawn(proc () { + let mut res: Vec = Vec::with_capacity((chunk_size * w) / 8); + let init_r_slice = vec_init_r.as_slice(); + for &init_i in vec_init_i.slice(i * chunk_size, (i + 1) * chunk_size).iter() { + write_line(init_i, init_r_slice, &mut res); + } + + res + }) + }); try!(writeln!(&mut out as &mut Writer, "P4\n{} {}", w, h)); for res in data.move_iter() { @@ -97,15 +113,63 @@ fn mandelbrot(w: uint, mut out: W) -> io::IoResult<()> { out.flush() } +fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec) { + let v_init_i : f64x2 = f64x2(init_i, init_i); + let v_2 : f64x2 = f64x2(2.0, 2.0); + static LIMIT_SQUARED: f64 = LIMIT * LIMIT; + + for chunk_init_r in vec_init_r.chunks(8) { + let mut cur_byte = 0xff; + let mut i = 0; + + while i < 8 { + let v_init_r = f64x2(chunk_init_r[i], chunk_init_r[i + 1]); + let mut cur_r = v_init_r; + let mut cur_i = v_init_i; + let mut r_sq = v_init_r * v_init_r; + let mut i_sq = v_init_i * v_init_i; + + let mut b = 0; + for _ in range(0, ITER) { + let r = cur_r; + let i = cur_i; + + cur_i = v_2 * r * i + v_init_i; + cur_r = r_sq - i_sq + v_init_r; + + let f64x2(bit1, bit2) = r_sq + i_sq; + + if bit1 > LIMIT_SQUARED { + b |= 2; + if b == 3 { break; } + } + + if bit2 > LIMIT_SQUARED { + b |= 1; + if b == 3 { break; } + } + + r_sq = cur_r * cur_r; + i_sq = cur_i * cur_i; + } + + cur_byte = (cur_byte << 2) + b; + i += 2; + } + + res.push(cur_byte^-1); + } +} + fn main() { - let args = std::os::args(); + let args = os::args(); let args = args.as_slice(); let res = if args.len() < 2 { println!("Test mode: do not dump the image because it's not utf8, \ which interferes with the test runner."); - mandelbrot(1000, std::io::util::NullWriter) + mandelbrot(1000, io::util::NullWriter) } else { - mandelbrot(from_str(args[1]).unwrap(), std::io::stdout()) + mandelbrot(from_str(args[1]).unwrap(), io::stdout()) }; res.unwrap(); } From 39b271f4a309b850c947f5c4e61c978a3cfbcd1e Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 May 2014 15:50:54 +0200 Subject: [PATCH 11/22] Add `EntryPat` and `NodePat` variants to ast_map. Add `EntryPat` and `NodePat` variants to ast_map, so that lookups for id 1 in `let S{val: _x /* pat 2 */} /* pat 1 */ = ...` will actually resolve to the pattern `S{ ... }`, rather than "unknown node", in a function like `node_id_to_str`. --- src/librustc/middle/trans/monomorphize.rs | 1 + src/libsyntax/ast_map.rs | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index bc3a0c0073f2..861caa62515b 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -309,6 +309,7 @@ pub fn monomorphic_fn(ccx: &CrateContext, ast_map::NodeStmt(..) | ast_map::NodeArg(..) | ast_map::NodeBlock(..) | + ast_map::NodePat(..) | ast_map::NodeLocal(..) => { ccx.sess().bug(format!("can't monomorphize a {:?}", map_node)) } diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 333f876e479b..6a7b913dce40 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -103,6 +103,7 @@ pub enum Node { NodeStmt(@Stmt), NodeArg(@Pat), NodeLocal(@Pat), + NodePat(@Pat), NodeBlock(P), /// NodeStructCtor represents a tuple struct. @@ -127,6 +128,7 @@ enum MapEntry { EntryStmt(NodeId, @Stmt), EntryArg(NodeId, @Pat), EntryLocal(NodeId, @Pat), + EntryPat(NodeId, @Pat), EntryBlock(NodeId, P), EntryStructCtor(NodeId, @StructDef), EntryLifetime(NodeId, @Lifetime), @@ -154,6 +156,7 @@ impl MapEntry { EntryStmt(id, _) => id, EntryArg(id, _) => id, EntryLocal(id, _) => id, + EntryPat(id, _) => id, EntryBlock(id, _) => id, EntryStructCtor(id, _) => id, EntryLifetime(id, _) => id, @@ -172,6 +175,7 @@ impl MapEntry { EntryStmt(_, p) => NodeStmt(p), EntryArg(_, p) => NodeArg(p), EntryLocal(_, p) => NodeLocal(p), + EntryPat(_, p) => NodePat(p), EntryBlock(_, p) => NodeBlock(p), EntryStructCtor(_, p) => NodeStructCtor(p), EntryLifetime(_, p) => NodeLifetime(p), @@ -399,6 +403,7 @@ impl Map { Some(NodeExpr(expr)) => expr.span, Some(NodeStmt(stmt)) => stmt.span, Some(NodeArg(pat)) | Some(NodeLocal(pat)) => pat.span, + Some(NodePat(pat)) => pat.span, Some(NodeBlock(block)) => block.span, Some(NodeStructCtor(_)) => self.expect_item(self.get_parent(id)).span, _ => fail!("node_span: could not find span for id {}", id), @@ -513,7 +518,9 @@ impl<'a, F: FoldOps> Folder for Ctx<'a, F> { // Note: this is at least *potentially* a pattern... self.insert(pat.id, EntryLocal(self.parent, pat)); } - _ => {} + _ => { + self.insert(pat.id, EntryPat(self.parent, pat)); + } } pat @@ -704,6 +711,9 @@ fn node_id_to_str(map: &Map, id: NodeId) -> StrBuf { (format!("local {} (id={})", pprust::pat_to_str(pat), id)).to_strbuf() } + Some(NodePat(pat)) => { + (format!("pat {} (id={})", pprust::pat_to_str(pat), id)).to_strbuf() + } Some(NodeBlock(block)) => { (format!("block {} (id={})", pprust::block_to_str(block), id)).to_strbuf() From 7f88cfde18942fc93c3f5952e51c03171446778c Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 8 May 2014 19:11:43 +0200 Subject: [PATCH 12/22] Add `IntoMaybeOwned` impl for `StrBuf` to ease conversion to `MaybeOwned`. --- src/libstd/str.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libstd/str.rs b/src/libstd/str.rs index fa4cf8e4427d..aee5fe9ff968 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -564,6 +564,11 @@ impl<'a> IntoMaybeOwned<'a> for ~str { fn into_maybe_owned(self) -> MaybeOwned<'a> { Owned(self) } } +impl<'a> IntoMaybeOwned<'a> for StrBuf { + #[inline] + fn into_maybe_owned(self) -> MaybeOwned<'a> { Owned(self.into_owned()) } +} + impl<'a> IntoMaybeOwned<'a> for &'a str { #[inline] fn into_maybe_owned(self) -> MaybeOwned<'a> { Slice(self) } From dbaf300a91750b6f63cc607f8f19405cf3d6671f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 6 May 2014 09:34:29 +0200 Subject: [PATCH 13/22] rustc::middle::graph API revisions. Refine lifetimes in signature for graph node/edge iteration methods. Added `pub` `node_id` and `edge_id` methods that correspond to NodeIndex and EdgeIndex `get` methods (note that the inner index is already `pub` in the struct definitions). (I decided that `get()`, used internally, just looks too generic and that client code is clearer with more explicit method names.) --- src/librustc/middle/graph.rs | 44 ++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index 2705f9bf9bf4..5773d0bafa1d 100644 --- a/src/librustc/middle/graph.rs +++ b/src/librustc/middle/graph.rs @@ -70,10 +70,14 @@ pub static Incoming: Direction = Direction { repr: 1 }; impl NodeIndex { fn get(&self) -> uint { let NodeIndex(v) = *self; v } + /// Returns unique id (unique with respect to the graph holding associated node). + pub fn node_id(&self) -> uint { self.get() } } impl EdgeIndex { fn get(&self) -> uint { let EdgeIndex(v) = *self; v } + /// Returns unique id (unique with respect to the graph holding associated edge). + pub fn edge_id(&self) -> uint { self.get() } } impl Graph { @@ -201,39 +205,39 @@ impl Graph { /////////////////////////////////////////////////////////////////////////// // Iterating over nodes, edges - pub fn each_node(&self, f: |NodeIndex, &Node| -> bool) -> bool { + pub fn each_node<'a>(&'a self, f: |NodeIndex, &'a Node| -> bool) -> bool { //! Iterates over all edges defined in the graph. self.nodes.iter().enumerate().advance(|(i, node)| f(NodeIndex(i), node)) } - pub fn each_edge(&self, f: |EdgeIndex, &Edge| -> bool) -> bool { + pub fn each_edge<'a>(&'a self, f: |EdgeIndex, &'a Edge| -> bool) -> bool { //! Iterates over all edges defined in the graph self.edges.iter().enumerate().advance(|(i, edge)| f(EdgeIndex(i), edge)) } - pub fn each_outgoing_edge(&self, - source: NodeIndex, - f: |EdgeIndex, &Edge| -> bool) - -> bool { + pub fn each_outgoing_edge<'a>(&'a self, + source: NodeIndex, + f: |EdgeIndex, &'a Edge| -> bool) + -> bool { //! Iterates over all outgoing edges from the node `from` self.each_adjacent_edge(source, Outgoing, f) } - pub fn each_incoming_edge(&self, - target: NodeIndex, - f: |EdgeIndex, &Edge| -> bool) - -> bool { + pub fn each_incoming_edge<'a>(&'a self, + target: NodeIndex, + f: |EdgeIndex, &'a Edge| -> bool) + -> bool { //! Iterates over all incoming edges to the node `target` self.each_adjacent_edge(target, Incoming, f) } - pub fn each_adjacent_edge(&self, - node: NodeIndex, - dir: Direction, - f: |EdgeIndex, &Edge| -> bool) - -> bool { + pub fn each_adjacent_edge<'a>(&'a self, + node: NodeIndex, + dir: Direction, + f: |EdgeIndex, &'a Edge| -> bool) + -> bool { //! Iterates over all edges adjacent to the node `node` //! in the direction `dir` (either `Outgoing` or `Incoming) @@ -257,11 +261,11 @@ impl Graph { // variables or other bitsets. This method facilitates such a // computation. - pub fn iterate_until_fixed_point(&self, - op: |iter_index: uint, - edge_index: EdgeIndex, - edge: &Edge| - -> bool) { + pub fn iterate_until_fixed_point<'a>(&'a self, + op: |iter_index: uint, + edge_index: EdgeIndex, + edge: &'a Edge| + -> bool) { let mut iteration = 0; let mut changed = true; while changed { From 65b65fe4480eef5ed1cd755db00217913706ea21 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 9 May 2014 00:07:57 +0200 Subject: [PATCH 14/22] Bugfixes for rustc::middle::cfg::construct. 1. Only insert non-dummy nodes into the exit map. 2. Revise handling of `break` and `continue` forms so that they are not treated as if control falls through to the next node (since it does not, it just jumps to the end or start of the loop body). 3. Fixed support for return expression in flow graph construction. --- src/librustc/middle/cfg/construct.rs | 60 +++++++++++++++++++++------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index d631340fc4e3..40c43c1f42cd 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -21,7 +21,8 @@ struct CFGBuilder<'a> { method_map: typeck::MethodMap, exit_map: NodeMap, graph: CFGGraph, - loop_scopes: Vec , + fn_exit: CFGIndex, + loop_scopes: Vec, } struct LoopScope { @@ -33,20 +34,35 @@ struct LoopScope { pub fn construct(tcx: &ty::ctxt, method_map: typeck::MethodMap, blk: &ast::Block) -> CFG { + let mut graph = graph::Graph::new(); + let entry = add_initial_dummy_node(&mut graph); + + // `fn_exit` is target of return exprs, which lies somewhere + // outside input `blk`. (Distinguishing `fn_exit` and `block_exit` + // also resolves chicken-and-egg problem that arises if you try to + // have return exprs jump to `block_exit` during construction.) + let fn_exit = add_initial_dummy_node(&mut graph); + let block_exit; + let mut cfg_builder = CFGBuilder { exit_map: NodeMap::new(), - graph: graph::Graph::new(), + graph: graph, + fn_exit: fn_exit, tcx: tcx, method_map: method_map, loop_scopes: Vec::new() }; - let entry = cfg_builder.add_node(0, []); - let exit = cfg_builder.block(blk, entry); + block_exit = cfg_builder.block(blk, entry); + cfg_builder.add_contained_edge(block_exit, fn_exit); let CFGBuilder {exit_map, graph, ..} = cfg_builder; CFG {exit_map: exit_map, graph: graph, entry: entry, - exit: exit} + exit: fn_exit} +} + +fn add_initial_dummy_node(g: &mut CFGGraph) -> CFGIndex { + g.add_node(CFGNodeData { id: ast::DUMMY_NODE_ID }) } impl<'a> CFGBuilder<'a> { @@ -327,24 +343,25 @@ impl<'a> CFGBuilder<'a> { ast::ExprRet(v) => { let v_exit = self.opt_expr(v, pred); - let loop_scope = *self.loop_scopes.get(0); - self.add_exiting_edge(expr, v_exit, - loop_scope, loop_scope.break_index); - self.add_node(expr.id, []) + let b = self.add_node(expr.id, [v_exit]); + self.add_returning_edge(expr, b); + self.add_node(ast::DUMMY_NODE_ID, []) } ast::ExprBreak(label) => { let loop_scope = self.find_scope(expr, label); - self.add_exiting_edge(expr, pred, + let b = self.add_node(expr.id, [pred]); + self.add_exiting_edge(expr, b, loop_scope, loop_scope.break_index); - self.add_node(expr.id, []) + self.add_node(ast::DUMMY_NODE_ID, []) } ast::ExprAgain(label) => { let loop_scope = self.find_scope(expr, label); - self.add_exiting_edge(expr, pred, + let a = self.add_node(expr.id, [pred]); + self.add_exiting_edge(expr, a, loop_scope, loop_scope.continue_index); - self.add_node(expr.id, []) + self.add_node(ast::DUMMY_NODE_ID, []) } ast::ExprVec(ref elems) => { @@ -453,13 +470,16 @@ impl<'a> CFGBuilder<'a> { } fn add_dummy_node(&mut self, preds: &[CFGIndex]) -> CFGIndex { - self.add_node(0, preds) + self.add_node(ast::DUMMY_NODE_ID, preds) } fn add_node(&mut self, id: ast::NodeId, preds: &[CFGIndex]) -> CFGIndex { assert!(!self.exit_map.contains_key(&id)); let node = self.graph.add_node(CFGNodeData {id: id}); - self.exit_map.insert(id, node); + if id != ast::DUMMY_NODE_ID { + assert!(!self.exit_map.contains_key(&id)); + self.exit_map.insert(id, node); + } for &pred in preds.iter() { self.add_contained_edge(pred, node); } @@ -488,6 +508,16 @@ impl<'a> CFGBuilder<'a> { self.graph.add_edge(from_index, to_index, data); } + fn add_returning_edge(&mut self, + _from_expr: @ast::Expr, + from_index: CFGIndex) { + let mut data = CFGEdgeData {exiting_scopes: vec!() }; + for &LoopScope { loop_id: id, .. } in self.loop_scopes.iter().rev() { + data.exiting_scopes.push(id); + } + self.graph.add_edge(from_index, self.fn_exit, data); + } + fn find_scope(&self, expr: @ast::Expr, label: Option) -> LoopScope { From aaf398f26a5eabbc89f28abcb79b4778be9e74a6 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 17 Apr 2014 21:00:08 +0200 Subject: [PATCH 15/22] Graphviz based flow graph pretty-printing. Passing `--pretty flowgraph=` makes rustc print a control flow graph. In pratice, you will also need to pass the additional option: `-o ` to emit output to a `.dot` file for graphviz. (You can only print the flow-graph for a particular block in the AST.) ---- An interesting implementation detail is the way the code puts both the node index (`cfg::CFGIndex`) and a reference to the payload (`cfg::CFGNode`) into the single `Node` type that is used for labelling and walking the graph. I had once mistakenly thought that I only wanted the `cfg::CFGNode`, but for labelling, you really want the cfg index too, rather than e.g. trying to use the `ast::NodeId` as the label (which breaks down e.g. due to `ast::DUMMY_NODE_ID`). ---- As a drive-by fix, I had to fix `rustc::middle::cfg::construct` interface to reflect changes that have happened on the master branch while I was getting this integrated into the compiler. (The next commit actually adds tests of the `--pretty flowgraph` functionality, so that should ensure that the `rustc::middle::cfg` code does not go stale again.) --- mk/crates.mk | 3 +- src/librustc/driver/config.rs | 13 +-- src/librustc/driver/driver.rs | 49 ++++++++++- src/librustc/driver/mod.rs | 32 +++++--- src/librustc/lib.rs | 2 +- src/librustc/middle/cfg/construct.rs | 5 +- src/librustc/middle/cfg/graphviz.rs | 116 +++++++++++++++++++++++++++ src/librustc/middle/cfg/mod.rs | 17 ++-- 8 files changed, 203 insertions(+), 34 deletions(-) create mode 100644 src/librustc/middle/cfg/graphviz.rs diff --git a/mk/crates.mk b/mk/crates.mk index b43accf61048..943cd528fcdc 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -59,12 +59,13 @@ TOOLS := compiletest rustdoc rustc DEPS_core := DEPS_rlibc := DEPS_std := core libc native:rustrt native:compiler-rt native:backtrace native:jemalloc +DEPS_graphviz := std DEPS_green := std rand native:context_switch DEPS_rustuv := std native:uv native:uv_support DEPS_native := std DEPS_syntax := std term serialize collections log fmt_macros DEPS_rustc := syntax native:rustllvm flate arena serialize sync getopts \ - collections time log + collections time log graphviz DEPS_rustdoc := rustc native:hoedown serialize sync getopts collections \ test time DEPS_flate := std native:miniz diff --git a/src/librustc/driver/config.rs b/src/librustc/driver/config.rs index b60468e85bbf..cd9e50157f2e 100644 --- a/src/librustc/driver/config.rs +++ b/src/librustc/driver/config.rs @@ -516,12 +516,13 @@ pub fn optgroups() -> Vec { optopt( "", "out-dir", "Write output to compiler-chosen filename in ", "DIR"), optflag("", "parse-only", "Parse only; do not compile, assemble, or link"), optflagopt("", "pretty", - "Pretty-print the input instead of compiling; - valid types are: normal (un-annotated source), - expanded (crates expanded), - typed (crates expanded, with type annotations), - or identified (fully parenthesized, - AST nodes and blocks with IDs)", "TYPE"), + "Pretty-print the input instead of compiling; + valid types are: `normal` (un-annotated source), + `expanded` (crates expanded), + `typed` (crates expanded, with type annotations), + `expanded,identified` (fully parenthesized, AST nodes with IDs), or + `flowgraph=` (graphviz formatted flowgraph for node)", + "TYPE"), optflagopt("", "dep-info", "Output dependency info to after compiling, \ in a format suitable for use by Makefiles", "FILENAME"), diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 0b731e18f557..5f9fd7124a9e 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -11,12 +11,15 @@ use back::link; use driver::session::Session; -use driver::config; +use driver::{config, PpMode}; +use driver::PpmFlowGraph; // FIXME (#14221). use front; use lib::llvm::{ContextRef, ModuleRef}; use metadata::common::LinkMeta; use metadata::creader; use metadata::creader::Loader; +use middle::cfg; +use middle::cfg::graphviz::LabelledCFG; use middle::{trans, freevars, kind, ty, typeck, lint, reachable}; use middle::dependency_format; use middle; @@ -24,6 +27,8 @@ use util::common::time; use util::ppaux; use util::nodemap::{NodeSet}; +use dot = graphviz; + use serialize::{json, Encodable}; use std::io; @@ -582,14 +587,14 @@ impl pprust::PpAnn for TypedAnnotation { pub fn pretty_print_input(sess: Session, cfg: ast::CrateConfig, input: &Input, - ppm: ::driver::PpMode, + ppm: PpMode, ofile: Option) { let krate = phase_1_parse_input(&sess, cfg, input); let id = link::find_crate_id(krate.attrs.as_slice(), input.filestem().as_slice()); let (krate, ast_map, is_expanded) = match ppm { - PpmExpanded | PpmExpandedIdentified | PpmTyped => { + PpmExpanded | PpmExpandedIdentified | PpmTyped | PpmFlowGraph(_) => { let loader = &mut Loader::new(&sess); let (krate, ast_map) = phase_2_configure_and_expand(&sess, loader, @@ -644,6 +649,18 @@ pub fn pretty_print_input(sess: Session, &annotation, is_expanded) } + PpmFlowGraph(nodeid) => { + let ast_map = ast_map.expect("--pretty flowgraph missing ast_map"); + let node = ast_map.find(nodeid).unwrap_or_else(|| { + fail!("--pretty flowgraph=id couldn't find id: {}", id) + }); + let block = match node { + syntax::ast_map::NodeBlock(block) => block, + _ => fail!("--pretty=flowgraph needs block, got {:?}", node) + }; + let analysis = phase_3_run_analysis_passes(sess, &krate, ast_map); + print_flowgraph(analysis, block, out) + } _ => { pprust::print_crate(sess.codemap(), sess.diagnostic(), @@ -658,6 +675,32 @@ pub fn pretty_print_input(sess: Session, } +fn print_flowgraph(analysis: CrateAnalysis, + block: ast::P, + mut out: W) -> io::IoResult<()> { + let ty_cx = &analysis.ty_cx; + let cfg = cfg::CFG::new(ty_cx, block); + let lcfg = LabelledCFG { ast_map: &ty_cx.map, + cfg: &cfg, + name: format!("block{}", block.id).to_strbuf(), }; + debug!("cfg: {:?}", cfg); + let r = dot::render(&lcfg, &mut out); + return expand_err_details(r); + + fn expand_err_details(r: io::IoResult<()>) -> io::IoResult<()> { + r.map_err(|ioerr| { + let orig_detail = ioerr.detail.clone(); + let m = "graphviz::render failed"; + io::IoError { + detail: Some(match orig_detail { + None => m.into_owned(), Some(d) => format!("{}: {}", m, d) + }), + ..ioerr + } + }) + } +} + pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec { // If we're generating a test executable, then ignore all other output diff --git a/src/librustc/driver/mod.rs b/src/librustc/driver/mod.rs index b92075444234..5a1e27a52560 100644 --- a/src/librustc/driver/mod.rs +++ b/src/librustc/driver/mod.rs @@ -285,20 +285,32 @@ pub enum PpMode { PpmExpanded, PpmTyped, PpmIdentified, - PpmExpandedIdentified + PpmExpandedIdentified, + PpmFlowGraph(ast::NodeId), } pub fn parse_pretty(sess: &Session, name: &str) -> PpMode { - match name { - "normal" => PpmNormal, - "expanded" => PpmExpanded, - "typed" => PpmTyped, - "expanded,identified" => PpmExpandedIdentified, - "identified" => PpmIdentified, + let mut split = name.splitn('=', 1); + let first = split.next().unwrap(); + let opt_second = split.next(); + match (opt_second, first) { + (None, "normal") => PpmNormal, + (None, "expanded") => PpmExpanded, + (None, "typed") => PpmTyped, + (None, "expanded,identified") => PpmExpandedIdentified, + (None, "identified") => PpmIdentified, + (Some(s), "flowgraph") => { + match from_str(s) { + Some(id) => PpmFlowGraph(id), + None => sess.fatal(format!("`pretty flowgraph=` needs \ + an integer ; got {}", s)) + } + } _ => { - sess.fatal("argument to `pretty` must be one of `normal`, \ - `expanded`, `typed`, `identified`, \ - or `expanded,identified`"); + sess.fatal(format!( + "argument to `pretty` must be one of `normal`, \ + `expanded`, `flowgraph=`, `typed`, `identified`, \ + or `expanded,identified`; got {}", name)); } } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index d3b5fb1ca470..18c59a955b52 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -33,6 +33,7 @@ This API is completely unstable and subject to change. extern crate flate; extern crate arena; +extern crate graphviz; extern crate syntax; extern crate serialize; extern crate sync; @@ -122,4 +123,3 @@ pub mod lib { pub fn main() { std::os::set_exit_status(driver::main_args(std::os::args().as_slice())); } - diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 40c43c1f42cd..c9c397d3d612 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -18,7 +18,6 @@ use util::nodemap::NodeMap; struct CFGBuilder<'a> { tcx: &'a ty::ctxt, - method_map: typeck::MethodMap, exit_map: NodeMap, graph: CFGGraph, fn_exit: CFGIndex, @@ -32,7 +31,6 @@ struct LoopScope { } pub fn construct(tcx: &ty::ctxt, - method_map: typeck::MethodMap, blk: &ast::Block) -> CFG { let mut graph = graph::Graph::new(); let entry = add_initial_dummy_node(&mut graph); @@ -49,7 +47,6 @@ pub fn construct(tcx: &ty::ctxt, graph: graph, fn_exit: fn_exit, tcx: tcx, - method_map: method_map, loop_scopes: Vec::new() }; block_exit = cfg_builder.block(blk, entry); @@ -551,6 +548,6 @@ impl<'a> CFGBuilder<'a> { fn is_method_call(&self, expr: &ast::Expr) -> bool { let method_call = typeck::MethodCall::expr(expr.id); - self.method_map.borrow().contains_key(&method_call) + self.tcx.method_map.borrow().contains_key(&method_call) } } diff --git a/src/librustc/middle/cfg/graphviz.rs b/src/librustc/middle/cfg/graphviz.rs new file mode 100644 index 000000000000..b8baeefd3d02 --- /dev/null +++ b/src/librustc/middle/cfg/graphviz.rs @@ -0,0 +1,116 @@ +// Copyright 2014 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. + +/// This module provides linkage between rustc::middle::graph and +/// libgraphviz traits. + +/// For clarity, rename the graphviz crate locally to dot. +use dot = graphviz; + +use syntax::ast; +use syntax::ast_map; + +use middle::cfg; + +pub type Node<'a> = (cfg::CFGIndex, &'a cfg::CFGNode); +pub type Edge<'a> = &'a cfg::CFGEdge; + +pub struct LabelledCFG<'a>{ + pub ast_map: &'a ast_map::Map, + pub cfg: &'a cfg::CFG, + pub name: StrBuf, +} + +fn replace_newline_with_backslash_l(s: StrBuf) -> StrBuf { + // Replacing newlines with \\l causes each line to be left-aligned, + // improving presentation of (long) pretty-printed expressions. + if s.as_slice().contains("\n") { + let mut s = s.replace("\n", "\\l"); + // Apparently left-alignment applies to the line that precedes + // \l, not the line that follows; so, add \l at end of string + // if not already present, ensuring last line gets left-aligned + // as well. + let mut last_two : Vec<_> = s.chars().rev().take(2).collect(); + last_two.reverse(); + if last_two.as_slice() != ['\\', 'l'] { + s = s.append("\\l"); + } + s.to_strbuf() + } else { + s + } +} + +impl<'a> dot::Labeller<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a> { + fn graph_id(&'a self) -> dot::Id<'a> { dot::Id::new(self.name.as_slice()) } + + fn node_id(&'a self, &(i,_): &Node<'a>) -> dot::Id<'a> { + dot::Id::new(format!("N{:u}", i.node_id())) + } + + fn node_label(&'a self, &(i, n): &Node<'a>) -> dot::LabelText<'a> { + if i == self.cfg.entry { + dot::LabelStr("entry".into_maybe_owned()) + } else if i == self.cfg.exit { + dot::LabelStr("exit".into_maybe_owned()) + } else if n.data.id == ast::DUMMY_NODE_ID { + dot::LabelStr("(dummy_node)".into_maybe_owned()) + } else { + let s = self.ast_map.node_to_str(n.data.id); + // left-aligns the lines + let s = replace_newline_with_backslash_l(s); + dot::EscStr(s.into_maybe_owned()) + } + } + + fn edge_label(&self, e: &Edge<'a>) -> dot::LabelText<'a> { + let mut label = StrBuf::new(); + let mut put_one = false; + for (i, &node_id) in e.data.exiting_scopes.iter().enumerate() { + if put_one { + label = label.append(",\\l"); + } else { + put_one = true; + } + let s = self.ast_map.node_to_str(node_id); + // left-aligns the lines + let s = replace_newline_with_backslash_l(s); + label = label.append(format!("exiting scope_{} {}", i, s.as_slice())); + } + dot::EscStr(label.into_maybe_owned()) + } +} + +impl<'a> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for &'a cfg::CFG { + fn nodes(&self) -> dot::Nodes<'a, Node<'a>> { + let mut v = Vec::new(); + self.graph.each_node(|i, nd| { v.push((i, nd)); true }); + dot::maybe_owned_vec::Growable(v) + } + fn edges(&self) -> dot::Edges<'a, Edge<'a>> { + self.graph.all_edges().iter().collect() + } + fn source(&self, edge: &Edge<'a>) -> Node<'a> { + let i = edge.source(); + (i, self.graph.node(i)) + } + fn target(&self, edge: &Edge<'a>) -> Node<'a> { + let i = edge.target(); + (i, self.graph.node(i)) + } +} + +impl<'a> dot::GraphWalk<'a, Node<'a>, Edge<'a>> for LabelledCFG<'a> +{ + fn nodes(&self) -> dot::Nodes<'a, Node<'a>> { self.cfg.nodes() } + fn edges(&self) -> dot::Edges<'a, Edge<'a>> { self.cfg.edges() } + fn source(&self, edge: &Edge<'a>) -> Node<'a> { self.cfg.source(edge) } + fn target(&self, edge: &Edge<'a>) -> Node<'a> { self.cfg.target(edge) } +} diff --git a/src/librustc/middle/cfg/mod.rs b/src/librustc/middle/cfg/mod.rs index 97ea996bb7e4..f0b912fb87bb 100644 --- a/src/librustc/middle/cfg/mod.rs +++ b/src/librustc/middle/cfg/mod.rs @@ -19,25 +19,25 @@ Uses `Graph` as the underlying representation. use middle::graph; use middle::ty; -use middle::typeck; use syntax::ast; use util::nodemap::NodeMap; mod construct; +pub mod graphviz; pub struct CFG { - exit_map: NodeMap, - graph: CFGGraph, - entry: CFGIndex, - exit: CFGIndex, + pub exit_map: NodeMap, + pub graph: CFGGraph, + pub entry: CFGIndex, + pub exit: CFGIndex, } pub struct CFGNodeData { - id: ast::NodeId + pub id: ast::NodeId } pub struct CFGEdgeData { - exiting_scopes: Vec + pub exiting_scopes: Vec } pub type CFGIndex = graph::NodeIndex; @@ -55,8 +55,7 @@ pub struct CFGIndices { impl CFG { pub fn new(tcx: &ty::ctxt, - method_map: typeck::MethodMap, blk: &ast::Block) -> CFG { - construct::construct(tcx, method_map, blk) + construct::construct(tcx, blk) } } From 3aad0e249cebaf2123cd875b737c088ae2c48728 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 5 May 2014 17:00:14 +0200 Subject: [PATCH 16/22] Unit tests for flowgraph pretty printing. Each test works by rendering the flowgraph for the last identified block we see in expanded pretty-printed output, and comparing it (via `diff`) against a checked in "foo.dot-expected.dot" file. Each test post-processes the output to remove NodeIds ` (id=NUM)` so that the expected output is somewhat stable (or at least independent of how we assign NodeIds) and easier for a human to interpret when looking at the expected output file itself. ---- Test writing style notes: I usually tried to write the tests in a way that would avoid duplicate labels in the output rendered flow graph, when possible. The tests that have string literals "unreachable" in the program text are deliberately written that way to remind the reader that the unreachable nodes in the resulting graph are not an error in the control flow computation, but rather a natural consequence of its construction. --- src/test/run-make/graphviz-flowgraph/Makefile | 37 +++++++++ .../graphviz-flowgraph/f00.dot-expected.dot | 7 ++ src/test/run-make/graphviz-flowgraph/f00.rs | 13 +++ .../graphviz-flowgraph/f01.dot-expected.dot | 9 +++ src/test/run-make/graphviz-flowgraph/f01.rs | 13 +++ .../graphviz-flowgraph/f02.dot-expected.dot | 9 +++ src/test/run-make/graphviz-flowgraph/f02.rs | 13 +++ .../graphviz-flowgraph/f03.dot-expected.dot | 13 +++ src/test/run-make/graphviz-flowgraph/f03.rs | 13 +++ .../graphviz-flowgraph/f04.dot-expected.dot | 11 +++ src/test/run-make/graphviz-flowgraph/f04.rs | 13 +++ .../graphviz-flowgraph/f05.dot-expected.dot | 19 +++++ src/test/run-make/graphviz-flowgraph/f05.rs | 13 +++ .../graphviz-flowgraph/f06.dot-expected.dot | 15 ++++ src/test/run-make/graphviz-flowgraph/f06.rs | 14 ++++ .../graphviz-flowgraph/f07.dot-expected.dot | 33 ++++++++ src/test/run-make/graphviz-flowgraph/f07.rs | 15 ++++ .../graphviz-flowgraph/f08.dot-expected.dot | 30 +++++++ src/test/run-make/graphviz-flowgraph/f08.rs | 16 ++++ .../graphviz-flowgraph/f09.dot-expected.dot | 44 ++++++++++ src/test/run-make/graphviz-flowgraph/f09.rs | 18 +++++ .../graphviz-flowgraph/f10.dot-expected.dot | 30 +++++++ src/test/run-make/graphviz-flowgraph/f10.rs | 16 ++++ .../graphviz-flowgraph/f11.dot-expected.dot | 25 ++++++ src/test/run-make/graphviz-flowgraph/f11.rs | 18 +++++ .../graphviz-flowgraph/f12.dot-expected.dot | 40 +++++++++ src/test/run-make/graphviz-flowgraph/f12.rs | 18 +++++ .../graphviz-flowgraph/f13.dot-expected.dot | 44 ++++++++++ src/test/run-make/graphviz-flowgraph/f13.rs | 18 +++++ .../graphviz-flowgraph/f14.dot-expected.dot | 28 +++++++ src/test/run-make/graphviz-flowgraph/f14.rs | 18 +++++ .../graphviz-flowgraph/f15.dot-expected.dot | 79 ++++++++++++++++++ src/test/run-make/graphviz-flowgraph/f15.rs | 30 +++++++ .../graphviz-flowgraph/f16.dot-expected.dot | 81 +++++++++++++++++++ src/test/run-make/graphviz-flowgraph/f16.rs | 31 +++++++ .../graphviz-flowgraph/f17.dot-expected.dot | 17 ++++ src/test/run-make/graphviz-flowgraph/f17.rs | 13 +++ .../graphviz-flowgraph/f18.dot-expected.dot | 17 ++++ src/test/run-make/graphviz-flowgraph/f18.rs | 14 ++++ .../graphviz-flowgraph/f19.dot-expected.dot | 19 +++++ src/test/run-make/graphviz-flowgraph/f19.rs | 16 ++++ .../graphviz-flowgraph/f20.dot-expected.dot | 23 ++++++ src/test/run-make/graphviz-flowgraph/f20.rs | 14 ++++ .../graphviz-flowgraph/f21.dot-expected.dot | 75 +++++++++++++++++ src/test/run-make/graphviz-flowgraph/f21.rs | 30 +++++++ .../graphviz-flowgraph/f22.dot-expected.dot | 77 ++++++++++++++++++ src/test/run-make/graphviz-flowgraph/f22.rs | 31 +++++++ 47 files changed, 1190 insertions(+) create mode 100644 src/test/run-make/graphviz-flowgraph/Makefile create mode 100644 src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f00.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f01.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f02.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f03.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f04.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f05.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f06.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f07.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f08.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f09.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f10.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f11.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f12.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f13.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f14.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f15.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f16.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f17.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f18.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f19.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f20.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f21.rs create mode 100644 src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot create mode 100644 src/test/run-make/graphviz-flowgraph/f22.rs diff --git a/src/test/run-make/graphviz-flowgraph/Makefile b/src/test/run-make/graphviz-flowgraph/Makefile new file mode 100644 index 000000000000..fedcc89cd429 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/Makefile @@ -0,0 +1,37 @@ +-include ../tools.mk + +FILES=f00.rs f01.rs f02.rs f03.rs f04.rs f05.rs f06.rs f07.rs \ + f08.rs f09.rs f10.rs f11.rs f12.rs f13.rs f14.rs f15.rs \ + f16.rs f17.rs f18.rs f19.rs f20.rs f21.rs f22.rs + + +# all: $(patsubst %.rs,$(TMPDIR)/%.dot,$(FILES)) $(patsubst %.rs,$(TMPDIR)/%.pp,$(FILES)) +all: $(patsubst %.rs,$(TMPDIR)/%.check,$(FILES)) + + +RUSTC_LIB=$(RUSTC) --crate-type=lib + +define FIND_LAST_BLOCK +LASTBLOCKNUM_$(1) := $(shell $(RUSTC_LIB) --pretty=expanded,identified $(1) \ + | grep block + | tail -1 + | sed -e 's@.*/\* block \([0-9]*\) \*/.*@\1@') +endef + +ifeq ($(findstring rustc,$(RUSTC)),) +$(error Must set RUSTC) +endif + +$(TMPDIR)/%.pp: %.rs + $(RUSTC_LIB) --pretty=expanded,identified $< -o $@ + +$(TMPDIR)/%.dot: %.rs + $(eval $(call FIND_LAST_BLOCK,$<)) + $(RUSTC_LIB) --pretty flowgraph=$(LASTBLOCKNUM_$<) $< -o $@.tmp + cat $@.tmp | sed -e 's@ (id=[0-9]*)@@g' \ + -e 's@\[label=""\]@@' \ + -e 's@digraph [a-zA-Z0-9_]* @digraph block @' \ + > $@ + +$(TMPDIR)/%.check: %.rs $(TMPDIR)/%.dot + diff -u $(patsubst %.rs,$(TMPDIR)/%.dot,$<) $(patsubst %.rs,%.dot-expected.dot,$<) diff --git a/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot new file mode 100644 index 000000000000..f699771ef24c --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f00.dot-expected.dot @@ -0,0 +1,7 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="block { }"]; + N0 -> N2; + N2 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f00.rs b/src/test/run-make/graphviz-flowgraph/f00.rs new file mode 100644 index 000000000000..4e7fc7ea9b08 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f00.rs @@ -0,0 +1,13 @@ +// Copyright 2014 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. + +pub fn empty_0() { + +} diff --git a/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot new file mode 100644 index 000000000000..9d8411cfc58d --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f01.dot-expected.dot @@ -0,0 +1,9 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 1"]; + N3[label="block { 1; }"]; + N0 -> N2; + N2 -> N3; + N3 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f01.rs b/src/test/run-make/graphviz-flowgraph/f01.rs new file mode 100644 index 000000000000..231aab69e50d --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f01.rs @@ -0,0 +1,13 @@ +// Copyright 2014 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. + +pub fn lit_1() { + 1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot new file mode 100644 index 000000000000..ada3f091808b --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f02.dot-expected.dot @@ -0,0 +1,9 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="local _x"]; + N3[label="block { let _x: int; }"]; + N0 -> N2; + N2 -> N3; + N3 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f02.rs b/src/test/run-make/graphviz-flowgraph/f02.rs new file mode 100644 index 000000000000..3cdd73a49e18 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f02.rs @@ -0,0 +1,13 @@ +// Copyright 2014 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. + +pub fn decl_x_2() { + let _x : int; +} diff --git a/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot new file mode 100644 index 000000000000..aff430459e87 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f03.dot-expected.dot @@ -0,0 +1,13 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 3"]; + N3[label="expr 33"]; + N4[label="expr 3 + 33"]; + N5[label="block { 3 + 33; }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f03.rs b/src/test/run-make/graphviz-flowgraph/f03.rs new file mode 100644 index 000000000000..8b172c0a1051 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f03.rs @@ -0,0 +1,13 @@ +// Copyright 2014 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. + +pub fn expr_add_3() { + 3 + 33; +} diff --git a/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot new file mode 100644 index 000000000000..adcc582c7338 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f04.dot-expected.dot @@ -0,0 +1,11 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 4"]; + N3[label="local _x"]; + N4[label="block { let _x = 4; }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f04.rs b/src/test/run-make/graphviz-flowgraph/f04.rs new file mode 100644 index 000000000000..2a0ac8ac9e57 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f04.rs @@ -0,0 +1,13 @@ +// Copyright 2014 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. + +pub fn pat_id_4() { + let _x = 4; +} diff --git a/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot new file mode 100644 index 000000000000..2d52c14da624 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f05.dot-expected.dot @@ -0,0 +1,19 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 5"]; + N3[label="expr 55"]; + N4[label="expr (5, 55)"]; + N5[label="local _x"]; + N6[label="local _y"]; + N7[label="pat (_x, _y)"]; + N8[label="block { let (_x, _y) = (5, 55); }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N8; + N8 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f05.rs b/src/test/run-make/graphviz-flowgraph/f05.rs new file mode 100644 index 000000000000..616d822bed07 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f05.rs @@ -0,0 +1,13 @@ +// Copyright 2014 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. + +pub fn pat_tup_5() { + let (_x, _y) = (5, 55); +} diff --git a/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot new file mode 100644 index 000000000000..61b40d68dd1b --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f06.dot-expected.dot @@ -0,0 +1,15 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 6"]; + N3[label="expr S6{val: 6,}"]; + N4[label="local _x"]; + N5[label="pat S6{val: _x}"]; + N6[label="block { let S6{val: _x} = S6{val: 6,}; }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f06.rs b/src/test/run-make/graphviz-flowgraph/f06.rs new file mode 100644 index 000000000000..c914409629cb --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f06.rs @@ -0,0 +1,14 @@ +// Copyright 2014 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. + +struct S6 { val: int } +pub fn pat_struct_6() { + let S6 { val: _x } = S6{ val: 6 }; +} diff --git a/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot new file mode 100644 index 000000000000..c99af1791495 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f07.dot-expected.dot @@ -0,0 +1,33 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 7"]; + N3[label="expr 77"]; + N4[label="expr 777"]; + N5[label="expr 7777"]; + N6[label="expr [7, 77, 777, 7777]"]; + N7[label="expr match [7, 77, 777, 7777] { [x, y, ..] => x + y }"]; + N8[label="local x"]; + N9[label="local y"]; + N10[label="pat .."]; + N11[label="pat [x, y, ..]"]; + N12[label="expr x"]; + N13[label="expr y"]; + N14[label="expr x + y"]; + N15[label="block { match [7, 77, 777, 7777] { [x, y, ..] => x + y }; }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N8; + N8 -> N9; + N9 -> N10; + N10 -> N11; + N11 -> N12; + N12 -> N13; + N13 -> N14; + N14 -> N7; + N7 -> N15; + N15 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f07.rs b/src/test/run-make/graphviz-flowgraph/f07.rs new file mode 100644 index 000000000000..39f71d309fdf --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f07.rs @@ -0,0 +1,15 @@ +// Copyright 2014 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. + +pub fn pat_vec_7() { + match [7, 77, 777, 7777] { + [x, y, ..] => x + y + }; +} diff --git a/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot new file mode 100644 index 000000000000..61a708cd9ccd --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f08.dot-expected.dot @@ -0,0 +1,30 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 8"]; + N3[label="local x"]; + N4[label="local _y"]; + N5[label="expr x"]; + N6[label="expr 88"]; + N7[label="expr x > 88"]; + N8[label="expr 888"]; + N9[label="expr _y"]; + N10[label="expr _y = 888"]; + N11[label="block { _y = 888; }"]; + N12[label="expr if x > 88 { _y = 888; }"]; + N13[label="block { let x = 8; let _y; if x > 88 { _y = 888; } }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N8; + N8 -> N9; + N9 -> N10; + N10 -> N11; + N7 -> N12; + N11 -> N12; + N12 -> N13; + N13 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f08.rs b/src/test/run-make/graphviz-flowgraph/f08.rs new file mode 100644 index 000000000000..6ba7b03d54da --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f08.rs @@ -0,0 +1,16 @@ +// Copyright 2014 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. + +pub fn expr_if_onearm_8() { + let x = 8; let _y; + if x > 88 { + _y = 888; + } +} diff --git a/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot new file mode 100644 index 000000000000..892b9fcd841f --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f09.dot-expected.dot @@ -0,0 +1,44 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 91"]; + N3[label="local x"]; + N4[label="local _y"]; + N5[label="expr x"]; + N6[label="expr 92"]; + N7[label="expr x > 92"]; + N8[label="expr 93"]; + N9[label="expr _y"]; + N10[label="expr _y = 93"]; + N11[label="block { _y = 93; }"]; + N12[label="expr 94"]; + N13[label="expr 95"]; + N14[label="expr 94 + 95"]; + N15[label="expr _y"]; + N16[label="expr _y = 94 + 95"]; + N17[label="block { _y = 94 + 95; }"]; + N18[label="expr { _y = 94 + 95; }"]; + N19[label="expr if x > 92 { _y = 93; } else { _y = 94 + 95; }"]; + N20[label="block { let x = 91; let _y; if x > 92 { _y = 93; } else { _y = 94 + 95; } }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N8; + N8 -> N9; + N9 -> N10; + N10 -> N11; + N7 -> N12; + N12 -> N13; + N13 -> N14; + N14 -> N15; + N15 -> N16; + N16 -> N17; + N17 -> N18; + N11 -> N19; + N18 -> N19; + N19 -> N20; + N20 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f09.rs b/src/test/run-make/graphviz-flowgraph/f09.rs new file mode 100644 index 000000000000..a78ccb8a9374 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f09.rs @@ -0,0 +1,18 @@ +// Copyright 2014 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. + +pub fn expr_if_twoarm_9() { + let x = 91; let _y; + if x > 92 { + _y = 93; + } else { + _y = 94+95; + } +} diff --git a/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot new file mode 100644 index 000000000000..2cef122104ed --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f10.dot-expected.dot @@ -0,0 +1,30 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 10"]; + N3[label="local mut x"]; + N4[label="(dummy_node)"]; + N5[label="expr x"]; + N6[label="expr 0"]; + N7[label="expr x > 0"]; + N8[label="expr while x > 0 { x -= 1; }"]; + N9[label="expr 1"]; + N10[label="expr x"]; + N11[label="expr x -= 1"]; + N12[label="block { x -= 1; }"]; + N13[label="block { let mut x = 10; while x > 0 { x -= 1; } }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N8; + N7 -> N9; + N9 -> N10; + N10 -> N11; + N11 -> N12; + N12 -> N4; + N8 -> N13; + N13 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f10.rs b/src/test/run-make/graphviz-flowgraph/f10.rs new file mode 100644 index 000000000000..0ca7cc5ee86b --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f10.rs @@ -0,0 +1,16 @@ +// Copyright 2014 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. + +pub fn expr_while_10() { + let mut x = 10; + while x > 0 { + x -= 1; + } +} diff --git a/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot new file mode 100644 index 000000000000..59d65e5b8b7f --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f11.dot-expected.dot @@ -0,0 +1,25 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 11"]; + N3[label="local mut _x"]; + N4[label="(dummy_node)"]; + N5[label="expr loop { _x -= 1; }"]; + N6[label="expr 1"]; + N7[label="expr _x"]; + N8[label="expr _x -= 1"]; + N9[label="block { _x -= 1; }"]; + N10[label="expr \"unreachable\""]; + N11[label="block { let mut _x = 11; loop { _x -= 1; } \"unreachable\"; }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N6; + N6 -> N7; + N7 -> N8; + N8 -> N9; + N9 -> N4; + N5 -> N10; + N10 -> N11; + N11 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f11.rs b/src/test/run-make/graphviz-flowgraph/f11.rs new file mode 100644 index 000000000000..d0f3452119e1 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f11.rs @@ -0,0 +1,18 @@ +// Copyright 2014 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(unreachable_code)] +pub fn expr_loop_11() { + let mut _x = 11; + loop { + _x -= 1; + } + "unreachable"; +} diff --git a/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot new file mode 100644 index 000000000000..9c0f25d5bece --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f12.dot-expected.dot @@ -0,0 +1,40 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 12"]; + N3[label="local mut x"]; + N4[label="(dummy_node)"]; + N5[label="expr loop { x -= 1; if x == 2 { break ; \"unreachable\"; } }"]; + N6[label="expr 1"]; + N7[label="expr x"]; + N8[label="expr x -= 1"]; + N9[label="expr x"]; + N10[label="expr 2"]; + N11[label="expr x == 2"]; + N12[label="expr break"]; + N13[label="(dummy_node)"]; + N14[label="expr \"unreachable\""]; + N15[label="block { break ; \"unreachable\"; }"]; + N16[label="expr if x == 2 { break ; \"unreachable\"; }"]; + N17[label="block { x -= 1; if x == 2 { break ; \"unreachable\"; } }"]; + N18[label="block { let mut x = 12; loop { x -= 1; if x == 2 { break ; \"unreachable\"; } } }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N6; + N6 -> N7; + N7 -> N8; + N8 -> N9; + N9 -> N10; + N10 -> N11; + N11 -> N12; + N12 -> N5[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\"; },\lexiting scope_3 expr if x == 2 { break ; \"unreachable\"; },\lexiting scope_4 block { x -= 1; if x == 2 { break ; \"unreachable\"; } }"]; + N13 -> N14; + N14 -> N15; + N11 -> N16; + N15 -> N16; + N16 -> N17; + N17 -> N4; + N5 -> N18; + N18 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f12.rs b/src/test/run-make/graphviz-flowgraph/f12.rs new file mode 100644 index 000000000000..90b146340b6f --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f12.rs @@ -0,0 +1,18 @@ +// Copyright 2014 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(unreachable_code)] +pub fn expr_loop_12() { + let mut x = 12; + loop { + x -= 1; + if x == 2 { break; "unreachable"; } + } +} diff --git a/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot new file mode 100644 index 000000000000..2be43dcaa7b6 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f13.dot-expected.dot @@ -0,0 +1,44 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr E13b"]; + N3[label="expr 13"]; + N4[label="expr E13b(13)"]; + N5[label="local x"]; + N6[label="local _y"]; + N7[label="expr x"]; + N8[label="expr match x { E13a => _y = 1, E13b(v) => _y = v + 1 }"]; + N9[label="local E13a"]; + N10[label="expr 1"]; + N11[label="expr _y"]; + N12[label="expr _y = 1"]; + N13[label="local v"]; + N14[label="pat E13b(v)"]; + N15[label="expr v"]; + N16[label="expr 1"]; + N17[label="expr v + 1"]; + N18[label="expr _y"]; + N19[label="expr _y = v + 1"]; + N20[label="block {\l let x = E13b(13);\l let _y;\l match x { E13a => _y = 1, E13b(v) => _y = v + 1 }\l}\l"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N9; + N9 -> N10; + N10 -> N11; + N11 -> N12; + N12 -> N8; + N7 -> N13; + N13 -> N14; + N14 -> N15; + N15 -> N16; + N16 -> N17; + N17 -> N18; + N18 -> N19; + N19 -> N8; + N8 -> N20; + N20 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f13.rs b/src/test/run-make/graphviz-flowgraph/f13.rs new file mode 100644 index 000000000000..0817a3210ce4 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f13.rs @@ -0,0 +1,18 @@ +// Copyright 2014 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. + +enum E13 { E13a, E13b(int) } +pub fn expr_match_13() { + let x = E13b(13); let _y; + match x { + E13a => _y = 1, + E13b(v) => _y = v + 1, + } +} diff --git a/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot new file mode 100644 index 000000000000..0fa4e9b44de3 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f14.dot-expected.dot @@ -0,0 +1,28 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 14"]; + N3[label="local x"]; + N4[label="expr x"]; + N5[label="expr 1"]; + N6[label="expr x > 1"]; + N7[label="expr return"]; + N8[label="(dummy_node)"]; + N9[label="expr \"unreachable\""]; + N10[label="block { return; \"unreachable\"; }"]; + N11[label="expr if x > 1 { return; \"unreachable\"; }"]; + N12[label="block { let x = 14; if x > 1 { return; \"unreachable\"; } }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N1; + N8 -> N9; + N9 -> N10; + N6 -> N11; + N10 -> N11; + N11 -> N12; + N12 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f14.rs b/src/test/run-make/graphviz-flowgraph/f14.rs new file mode 100644 index 000000000000..98ff095c8317 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f14.rs @@ -0,0 +1,18 @@ +// Copyright 2014 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(unreachable_code)] +pub fn expr_ret_14() { + let x = 14; + if x > 1 { + return; + "unreachable"; + } +} diff --git a/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot new file mode 100644 index 000000000000..f0278fba311e --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f15.dot-expected.dot @@ -0,0 +1,79 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 15"]; + N3[label="local mut x"]; + N4[label="expr 151"]; + N5[label="local mut y"]; + N6[label="(dummy_node)"]; + N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\" }\l if y >= 2 { break ; \"unreachable\" }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l"]; + N8[label="(dummy_node)"]; + N9[label="expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\" }\l if y >= 2 { break ; \"unreachable\" }\l y -= 3;\l }\l"]; + N10[label="expr x"]; + N11[label="expr 1"]; + N12[label="expr x == 1"]; + N13[label="expr break \'outer"]; + N14[label="(dummy_node)"]; + N15[label="expr \"unreachable\""]; + N16[label="block { break \'outer ; \"unreachable\" }"]; + N17[label="expr if x == 1 { break \'outer ; \"unreachable\" }"]; + N18[label="expr y"]; + N19[label="expr 2"]; + N20[label="expr y >= 2"]; + N21[label="expr break"]; + N22[label="(dummy_node)"]; + N23[label="expr \"unreachable\""]; + N24[label="block { break ; \"unreachable\" }"]; + N25[label="expr if y >= 2 { break ; \"unreachable\" }"]; + N26[label="expr 3"]; + N27[label="expr y"]; + N28[label="expr y -= 3"]; + N29[label="block {\l if x == 1 { break \'outer ; \"unreachable\" }\l if y >= 2 { break ; \"unreachable\" }\l y -= 3;\l}\l"]; + N30[label="expr 4"]; + N31[label="expr y"]; + N32[label="expr y -= 4"]; + N33[label="expr 5"]; + N34[label="expr x"]; + N35[label="expr x -= 5"]; + N36[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\" }\l if y >= 2 { break ; \"unreachable\" }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l}\l"]; + N37[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\" }\l if y >= 2 { break ; \"unreachable\" }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l }\l}\l"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N8; + N8 -> N10; + N10 -> N11; + N11 -> N12; + N12 -> N13; + N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\" },\lexiting scope_3 expr if x == 1 { break \'outer ; \"unreachable\" },\lexiting scope_4 stmt if x == 1 { break \'outer ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1 { break \'outer ; \"unreachable\" }\l if y >= 2 { break ; \"unreachable\" }\l y -= 3;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\" }\l if y >= 2 { break ; \"unreachable\" }\l y -= 3;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\" }\l if y >= 2 { break ; \"unreachable\" }\l y -= 3;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\" }\l if y >= 2 { break ; \"unreachable\" }\l y -= 3;\l }\l y -= 4;\l x -= 5;\l}\l"]; + N14 -> N15; + N15 -> N16; + N12 -> N17; + N16 -> N17; + N17 -> N18; + N18 -> N19; + N19 -> N20; + N20 -> N21; + N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\" },\lexiting scope_3 expr if y >= 2 { break ; \"unreachable\" },\lexiting scope_4 stmt if y >= 2 { break ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1 { break \'outer ; \"unreachable\" }\l if y >= 2 { break ; \"unreachable\" }\l y -= 3;\l}\l"]; + N22 -> N23; + N23 -> N24; + N20 -> N25; + N24 -> N25; + N25 -> N26; + N26 -> N27; + N27 -> N28; + N28 -> N29; + N29 -> N8; + N9 -> N30; + N30 -> N31; + N31 -> N32; + N32 -> N33; + N33 -> N34; + N34 -> N35; + N35 -> N36; + N36 -> N6; + N7 -> N37; + N37 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f15.rs b/src/test/run-make/graphviz-flowgraph/f15.rs new file mode 100644 index 000000000000..44c038d643ba --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f15.rs @@ -0,0 +1,30 @@ +// Copyright 2014 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(unreachable_code)] +pub fn expr_break_label_15() { + let mut x = 15; + let mut y = 151; + 'outer: loop { + 'inner: loop { + if x == 1 { + break 'outer; + "unreachable" + } + if y >= 2 { + break; + "unreachable" + } + y -= 3; + } + y -= 4; + x -= 5; + } +} diff --git a/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot new file mode 100644 index 000000000000..3f999ae37814 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f16.dot-expected.dot @@ -0,0 +1,81 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 16"]; + N3[label="local mut x"]; + N4[label="expr 16"]; + N5[label="local mut y"]; + N6[label="(dummy_node)"]; + N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\" }\l if y >= 1 { break ; \"unreachable\" }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l"]; + N8[label="(dummy_node)"]; + N9[label="expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\" }\l if y >= 1 { break ; \"unreachable\" }\l y -= 1;\l }\l"]; + N10[label="expr x"]; + N11[label="expr 1"]; + N12[label="expr x == 1"]; + N13[label="expr continue \'outer"]; + N14[label="(dummy_node)"]; + N15[label="expr \"unreachable\""]; + N16[label="block { continue \'outer ; \"unreachable\" }"]; + N17[label="expr if x == 1 { continue \'outer ; \"unreachable\" }"]; + N18[label="expr y"]; + N19[label="expr 1"]; + N20[label="expr y >= 1"]; + N21[label="expr break"]; + N22[label="(dummy_node)"]; + N23[label="expr \"unreachable\""]; + N24[label="block { break ; \"unreachable\" }"]; + N25[label="expr if y >= 1 { break ; \"unreachable\" }"]; + N26[label="expr 1"]; + N27[label="expr y"]; + N28[label="expr y -= 1"]; + N29[label="block {\l if x == 1 { continue \'outer ; \"unreachable\" }\l if y >= 1 { break ; \"unreachable\" }\l y -= 1;\l}\l"]; + N30[label="expr 1"]; + N31[label="expr y"]; + N32[label="expr y -= 1"]; + N33[label="expr 1"]; + N34[label="expr x"]; + N35[label="expr x -= 1"]; + N36[label="block {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\" }\l if y >= 1 { break ; \"unreachable\" }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l}\l"]; + N37[label="expr \"unreachable\""]; + N38[label="block {\l let mut x = 16;\l let mut y = 16;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\" }\l if y >= 1 { break ; \"unreachable\" }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l }\l \"unreachable\";\l}\l"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N8; + N8 -> N10; + N10 -> N11; + N11 -> N12; + N12 -> N13; + N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\" },\lexiting scope_3 expr if x == 1 { continue \'outer ; \"unreachable\" },\lexiting scope_4 stmt if x == 1 { continue \'outer ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1 { continue \'outer ; \"unreachable\" }\l if y >= 1 { break ; \"unreachable\" }\l y -= 1;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\" }\l if y >= 1 { break ; \"unreachable\" }\l y -= 1;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\" }\l if y >= 1 { break ; \"unreachable\" }\l y -= 1;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\" }\l if y >= 1 { break ; \"unreachable\" }\l y -= 1;\l }\l y -= 1;\l x -= 1;\l}\l"]; + N14 -> N15; + N15 -> N16; + N12 -> N17; + N16 -> N17; + N17 -> N18; + N18 -> N19; + N19 -> N20; + N20 -> N21; + N21 -> N9[label="exiting scope_0 expr break,\lexiting scope_1 stmt break ;,\lexiting scope_2 block { break ; \"unreachable\" },\lexiting scope_3 expr if y >= 1 { break ; \"unreachable\" },\lexiting scope_4 stmt if y >= 1 { break ; \"unreachable\" },\lexiting scope_5 block {\l if x == 1 { continue \'outer ; \"unreachable\" }\l if y >= 1 { break ; \"unreachable\" }\l y -= 1;\l}\l"]; + N22 -> N23; + N23 -> N24; + N20 -> N25; + N24 -> N25; + N25 -> N26; + N26 -> N27; + N27 -> N28; + N28 -> N29; + N29 -> N8; + N9 -> N30; + N30 -> N31; + N31 -> N32; + N32 -> N33; + N33 -> N34; + N34 -> N35; + N35 -> N36; + N36 -> N6; + N7 -> N37; + N37 -> N38; + N38 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f16.rs b/src/test/run-make/graphviz-flowgraph/f16.rs new file mode 100644 index 000000000000..f4f23a65c935 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f16.rs @@ -0,0 +1,31 @@ +// Copyright 2014 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(unreachable_code)] +pub fn expr_continue_label_16() { + let mut x = 16; + let mut y = 16; + 'outer: loop { + 'inner: loop { + if x == 1 { + continue 'outer; + "unreachable" + } + if y >= 1 { + break; + "unreachable" + } + y -= 1; + } + y -= 1; + x -= 1; + } + "unreachable"; +} diff --git a/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot new file mode 100644 index 000000000000..e9bccdab81be --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f17.dot-expected.dot @@ -0,0 +1,17 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 1"]; + N3[label="expr 7"]; + N4[label="expr 17"]; + N5[label="expr [1, 7, 17]"]; + N6[label="local _v"]; + N7[label="block { let _v = [1, 7, 17]; }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f17.rs b/src/test/run-make/graphviz-flowgraph/f17.rs new file mode 100644 index 000000000000..23f5bb8a1eb1 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f17.rs @@ -0,0 +1,13 @@ +// Copyright 2014 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. + +pub fn expr_vec_17() { + let _v = [1, 7, 17]; +} diff --git a/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot new file mode 100644 index 000000000000..6345b4effaf1 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f18.dot-expected.dot @@ -0,0 +1,17 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr inner"]; + N3[label="expr inner"]; + N4[label="expr 18"]; + N5[label="expr inner(18)"]; + N6[label="expr inner(inner(18))"]; + N7[label="block {\l fn inner(x: int) -> int { x + x }\l inner(inner(18));\l}\l"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f18.rs b/src/test/run-make/graphviz-flowgraph/f18.rs new file mode 100644 index 000000000000..0ace542b8f5d --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f18.rs @@ -0,0 +1,14 @@ +// Copyright 2014 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. + +pub fn expr_call_18() { + fn inner(x:int) -> int { x + x } + inner(inner(18)); +} diff --git a/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot new file mode 100644 index 000000000000..5fad18536e59 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f19.dot-expected.dot @@ -0,0 +1,19 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 19"]; + N3[label="expr S19{x: 19,}"]; + N4[label="local s"]; + N5[label="expr s"]; + N6[label="expr s.inner()"]; + N7[label="expr s.inner().inner()"]; + N8[label="block {\l struct S19 {\l x: int,\l }\l impl S19 {\l fn inner(self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N8; + N8 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f19.rs b/src/test/run-make/graphviz-flowgraph/f19.rs new file mode 100644 index 000000000000..092f6890a152 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f19.rs @@ -0,0 +1,16 @@ +// Copyright 2014 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. + +pub fn expr_method_call_19() { + struct S19 { x: int } + impl S19 { fn inner(self) -> S19 { S19 { x: self.x + self.x } } } + let s = S19 { x: 19 }; + s.inner().inner(); +} diff --git a/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot new file mode 100644 index 000000000000..593ad6f91ea5 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f20.dot-expected.dot @@ -0,0 +1,23 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 2"]; + N3[label="expr 0"]; + N4[label="expr 20"]; + N5[label="expr [2, 0, 20]"]; + N6[label="local v"]; + N7[label="expr v"]; + N8[label="expr 20"]; + N9[label="expr v[20]"]; + N10[label="block { let v = [2, 0, 20]; v[20]; }"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N7; + N7 -> N8; + N8 -> N9; + N9 -> N10; + N10 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f20.rs b/src/test/run-make/graphviz-flowgraph/f20.rs new file mode 100644 index 000000000000..d7349932355b --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f20.rs @@ -0,0 +1,14 @@ +// Copyright 2014 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. + +pub fn expr_index_20() { + let v = [2, 0, 20]; + v[20]; +} diff --git a/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot new file mode 100644 index 000000000000..0798c4a01c05 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f21.dot-expected.dot @@ -0,0 +1,75 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 15"]; + N3[label="local mut x"]; + N4[label="expr 151"]; + N5[label="local mut y"]; + N6[label="(dummy_node)"]; + N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l"]; + N8[label="(dummy_node)"]; + N9[label="expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l"]; + N10[label="expr x"]; + N11[label="expr 1"]; + N12[label="expr x == 1"]; + N13[label="expr break \'outer"]; + N14[label="(dummy_node)"]; + N15[label="expr \"unreachable\""]; + N16[label="block { break \'outer ; \"unreachable\"; }"]; + N17[label="expr if x == 1 { break \'outer ; \"unreachable\"; }"]; + N18[label="expr y"]; + N19[label="expr 2"]; + N20[label="expr y >= 2"]; + N21[label="expr return"]; + N22[label="(dummy_node)"]; + N23[label="expr \"unreachable\""]; + N24[label="block { return; \"unreachable\"; }"]; + N25[label="expr if y >= 2 { return; \"unreachable\"; }"]; + N26[label="expr 3"]; + N27[label="expr y"]; + N28[label="expr y -= 3"]; + N29[label="expr 5"]; + N30[label="expr x"]; + N31[label="expr x -= 5"]; + N32[label="block {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l}\l"]; + N33[label="expr \"unreachable\""]; + N34[label="block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l}\l"]; + N35[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l}\l"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N8; + N8 -> N10; + N10 -> N11; + N11 -> N12; + N12 -> N13; + N13 -> N7[label="exiting scope_0 expr break \'outer,\lexiting scope_1 stmt break \'outer ;,\lexiting scope_2 block { break \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1 { break \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1 { break \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l}\l"]; + N14 -> N15; + N15 -> N16; + N12 -> N17; + N16 -> N17; + N17 -> N18; + N18 -> N19; + N19 -> N20; + N20 -> N21; + N21 -> N1[label="exiting scope_0 expr \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l,\lexiting scope_1 expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { break \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l y -= 3;\l x -= 5;\l }\l \"unreachable\";\l }\l"]; + N22 -> N23; + N23 -> N24; + N20 -> N25; + N24 -> N25; + N25 -> N26; + N26 -> N27; + N27 -> N28; + N28 -> N29; + N29 -> N30; + N30 -> N31; + N31 -> N32; + N32 -> N8; + N9 -> N33; + N33 -> N34; + N34 -> N6; + N7 -> N35; + N35 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f21.rs b/src/test/run-make/graphviz-flowgraph/f21.rs new file mode 100644 index 000000000000..70083ed8312c --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f21.rs @@ -0,0 +1,30 @@ +// Copyright 2014 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(unreachable_code)] +pub fn expr_break_label_21() { + let mut x = 15; + let mut y = 151; + 'outer: loop { + 'inner: loop { + if x == 1 { + break 'outer; + "unreachable"; + } + if y >= 2 { + return; + "unreachable"; + } + y -= 3; + x -= 5; + } + "unreachable"; + } +} diff --git a/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot new file mode 100644 index 000000000000..9ad731bc756b --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f22.dot-expected.dot @@ -0,0 +1,77 @@ +digraph block { + N0[label="entry"]; + N1[label="exit"]; + N2[label="expr 15"]; + N3[label="local mut x"]; + N4[label="expr 151"]; + N5[label="local mut y"]; + N6[label="(dummy_node)"]; + N7[label="expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l"]; + N8[label="(dummy_node)"]; + N9[label="expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l"]; + N10[label="expr x"]; + N11[label="expr 1"]; + N12[label="expr x == 1"]; + N13[label="expr continue \'outer"]; + N14[label="(dummy_node)"]; + N15[label="expr \"unreachable\""]; + N16[label="block { continue \'outer ; \"unreachable\"; }"]; + N17[label="expr if x == 1 { continue \'outer ; \"unreachable\"; }"]; + N18[label="expr y"]; + N19[label="expr 2"]; + N20[label="expr y >= 2"]; + N21[label="expr return"]; + N22[label="(dummy_node)"]; + N23[label="expr \"unreachable\""]; + N24[label="block { return; \"unreachable\"; }"]; + N25[label="expr if y >= 2 { return; \"unreachable\"; }"]; + N26[label="expr 1"]; + N27[label="expr x"]; + N28[label="expr x -= 1"]; + N29[label="expr 3"]; + N30[label="expr y"]; + N31[label="expr y -= 3"]; + N32[label="block {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l}\l"]; + N33[label="expr \"unreachable\""]; + N34[label="block {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l}\l"]; + N35[label="expr \"unreachable\""]; + N36[label="block {\l let mut x = 15;\l let mut y = 151;\l \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l \"unreachable\";\l}\l"]; + N0 -> N2; + N2 -> N3; + N3 -> N4; + N4 -> N5; + N5 -> N6; + N6 -> N8; + N8 -> N10; + N10 -> N11; + N11 -> N12; + N12 -> N13; + N13 -> N6[label="exiting scope_0 expr continue \'outer,\lexiting scope_1 stmt continue \'outer ;,\lexiting scope_2 block { continue \'outer ; \"unreachable\"; },\lexiting scope_3 expr if x == 1 { continue \'outer ; \"unreachable\"; },\lexiting scope_4 stmt if x == 1 { continue \'outer ; \"unreachable\"; },\lexiting scope_5 block {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l}\l,\lexiting scope_6 expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l,\lexiting scope_7 stmt \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l,\lexiting scope_8 block {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l}\l"]; + N14 -> N15; + N15 -> N16; + N12 -> N17; + N16 -> N17; + N17 -> N18; + N18 -> N19; + N19 -> N20; + N20 -> N21; + N21 -> N1[label="exiting scope_0 expr \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l,\lexiting scope_1 expr \'outer:\l loop {\l \'inner:\l loop {\l if x == 1 { continue \'outer ; \"unreachable\"; }\l if y >= 2 { return; \"unreachable\"; }\l x -= 1;\l y -= 3;\l }\l \"unreachable\";\l }\l"]; + N22 -> N23; + N23 -> N24; + N20 -> N25; + N24 -> N25; + N25 -> N26; + N26 -> N27; + N27 -> N28; + N28 -> N29; + N29 -> N30; + N30 -> N31; + N31 -> N32; + N32 -> N8; + N9 -> N33; + N33 -> N34; + N34 -> N6; + N7 -> N35; + N35 -> N36; + N36 -> N1; +} diff --git a/src/test/run-make/graphviz-flowgraph/f22.rs b/src/test/run-make/graphviz-flowgraph/f22.rs new file mode 100644 index 000000000000..b35aac9ec422 --- /dev/null +++ b/src/test/run-make/graphviz-flowgraph/f22.rs @@ -0,0 +1,31 @@ +// Copyright 2014 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(unreachable_code)] +pub fn expr_break_label_21() { + let mut x = 15; + let mut y = 151; + 'outer: loop { + 'inner: loop { + if x == 1 { + continue 'outer; + "unreachable"; + } + if y >= 2 { + return; + "unreachable"; + } + x -= 1; + y -= 3; + } + "unreachable"; + } + "unreachable"; +} From b05af1f6a83ad6eacc02493f71fb4116b120837e Mon Sep 17 00:00:00 2001 From: Richo Healey Date: Wed, 14 May 2014 10:45:51 -0700 Subject: [PATCH 17/22] Render not_found with an absolute path to the rust stylesheet --- mk/docs.mk | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/mk/docs.mk b/mk/docs.mk index 40c2440c0c07..4d00223fca88 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -30,7 +30,7 @@ DOCS := index intro tutorial guide-ffi guide-macros guide-lifetimes \ guide-tasks guide-container guide-pointers guide-testing \ guide-runtime complement-bugreport complement-cheatsheet \ complement-lang-faq complement-project-faq rust rustdoc \ - guide-unsafe not_found + guide-unsafe PDF_DOCS := tutorial rust @@ -42,10 +42,11 @@ L10N_LANGS := ja # Generally no need to edit below here. # The options are passed to the documentation generators. -RUSTDOC_HTML_OPTS = --markdown-css rust.css \ - --markdown-before-content=doc/version_info.html \ +RUSTDOC_HTML_OPTS_NO_CSS = --markdown-before-content=doc/version_info.html \ --markdown-in-header=doc/favicon.inc --markdown-after-content=doc/footer.inc +RUSTDOC_HTML_OPTS = $(RUSTDOC_HTML_OPTS_NO_CSS) --markdown-css rust.css + PANDOC_BASE_OPTS := --standalone --toc --number-sections PANDOC_TEX_OPTS = $(PANDOC_BASE_OPTS) --include-before-body=doc/version.tex \ --from=markdown --include-before-body=doc/footer.tex --to=latex @@ -152,6 +153,11 @@ doc/footer.tex: $(D)/footer.inc | doc/ @$(call E, pandoc: $@) $(CFG_PANDOC) --from=html --to=latex $< --output=$@ +# HTML (rustdoc) +DOC_TARGETS += doc/not_found.html +doc/not_found.html: $(D)/not_found.md $(HTML_DEPS) | doc/ + $(RUSTDOC) $(RUSTDOC_HTML_OPTS_NO_CSS) --markdown-css http://static.rust-lang.org/doc/master/rust.css $< + define DEF_DOC # HTML (rustdoc) From 514fc308b0bcf903260f1e40fd0b18ba91539d35 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 14 May 2014 01:13:29 -0700 Subject: [PATCH 18/22] std: Remove run_in_bare_thread --- src/libgreen/sched.rs | 6 ++-- src/librustuv/lib.rs | 6 ++-- src/librustuv/uvio.rs | 6 ++-- src/libstd/rt/local.rs | 22 +++++++------- src/libstd/unstable/mod.rs | 31 -------------------- src/test/run-pass/foreign-call-no-runtime.rs | 6 ++-- 6 files changed, 23 insertions(+), 54 deletions(-) diff --git a/src/libgreen/sched.rs b/src/libgreen/sched.rs index 8c294fa2928f..5bc96dd6e8ee 100644 --- a/src/libgreen/sched.rs +++ b/src/libgreen/sched.rs @@ -1137,11 +1137,11 @@ mod test { fn test_schedule_home_states() { use sleeper_list::SleeperList; use super::{Shutdown, Scheduler, SchedHandle}; - use std::unstable::run_in_bare_thread; + use std::unstable::Thread; use std::rt::thread::Thread; use std::sync::deque::BufferPool; - run_in_bare_thread(proc() { + Thread::start(proc() { let sleepers = SleeperList::new(); let mut pool = BufferPool::new(); let (normal_worker, normal_stealer) = pool.deque(); @@ -1260,7 +1260,7 @@ mod test { normal_thread.join(); special_thread.join(); - }); + }).join(); } //#[test] diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index c9bff2e80bfe..96b66f616f6e 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -472,7 +472,7 @@ fn local_loop() -> &'static mut uvio::UvIoFactory { #[cfg(test)] mod test { use std::mem::transmute; - use std::unstable::run_in_bare_thread; + use std::rt::Thread; use super::{slice_to_uv_buf, Loop}; @@ -496,10 +496,10 @@ mod test { #[test] fn loop_smoke_test() { - run_in_bare_thread(proc() { + Thread::start(proc() { let mut loop_ = Loop::new(); loop_.run(); loop_.close(); - }); + }).join(); } } diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index 1b8175448fc9..88e05f815b27 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -27,7 +27,7 @@ use std::rt::rtio; use std::rt::rtio::{ProcessConfig, IoFactory, EventLoop}; use ai = std::io::net::addrinfo; -#[cfg(test)] use std::unstable::run_in_bare_thread; +#[cfg(test)] use std::rt::Thread; use super::{uv_error_to_io_error, Loop}; @@ -116,7 +116,7 @@ impl EventLoop for UvEventLoop { #[test] fn test_callback_run_once() { - run_in_bare_thread(proc() { + Thread::start(proc() { let mut event_loop = UvEventLoop::new(); let mut count = 0; let count_ptr: *mut int = &mut count; @@ -125,7 +125,7 @@ fn test_callback_run_once() { }); event_loop.run(); assert_eq!(count, 1); - }); + }).join(); } pub struct UvIoFactory { diff --git a/src/libstd/rt/local.rs b/src/libstd/rt/local.rs index 05d1f1764b59..9f0ed8044800 100644 --- a/src/libstd/rt/local.rs +++ b/src/libstd/rt/local.rs @@ -53,24 +53,24 @@ impl Local> for Task { #[cfg(test)] mod test { use option::{None, Option}; - use unstable::run_in_bare_thread; + use rt::thread::Thread; use super::*; use owned::Box; use rt::task::Task; #[test] fn thread_local_task_smoke_test() { - run_in_bare_thread(proc() { + Thread::start(proc() { let task = box Task::new(); Local::put(task); let task: Box = Local::take(); cleanup_task(task); - }); + }).join(); } #[test] fn thread_local_task_two_instances() { - run_in_bare_thread(proc() { + Thread::start(proc() { let task = box Task::new(); Local::put(task); let task: Box = Local::take(); @@ -79,12 +79,12 @@ mod test { Local::put(task); let task: Box = Local::take(); cleanup_task(task); - }); + }).join(); } #[test] fn borrow_smoke_test() { - run_in_bare_thread(proc() { + Thread::start(proc() { let task = box Task::new(); Local::put(task); @@ -93,12 +93,12 @@ mod test { } let task: Box = Local::take(); cleanup_task(task); - }); + }).join(); } #[test] fn borrow_with_return() { - run_in_bare_thread(proc() { + Thread::start(proc() { let task = box Task::new(); Local::put(task); @@ -108,12 +108,12 @@ mod test { let task: Box = Local::take(); cleanup_task(task); - }); + }).join(); } #[test] fn try_take() { - run_in_bare_thread(proc() { + Thread::start(proc() { let task = box Task::new(); Local::put(task); @@ -122,7 +122,7 @@ mod test { assert!(u.is_none()); cleanup_task(t); - }); + }).join(); } fn cleanup_task(mut t: Box) { diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index 8b07850263fe..f464f70772d9 100644 --- a/src/libstd/unstable/mod.rs +++ b/src/libstd/unstable/mod.rs @@ -11,7 +11,6 @@ #![doc(hidden)] use libc::uintptr_t; -use kinds::Send; pub use core::finally; @@ -21,36 +20,6 @@ pub mod simd; pub mod sync; pub mod mutex; -/** - -Start a new thread outside of the current runtime context and wait -for it to terminate. - -The executing thread has no access to a task pointer and will be using -a normal large stack. -*/ -pub fn run_in_bare_thread(f: proc():Send) { - use rt::thread::Thread; - Thread::start(f).join() -} - -#[test] -fn test_run_in_bare_thread() { - let i = 100; - run_in_bare_thread(proc() { - assert_eq!(i, 100); - }); -} - -#[test] -fn test_run_in_bare_thread_exchange() { - // Does the exchange heap work without the runtime? - let i = box 100; - run_in_bare_thread(proc() { - assert!(i == box 100); - }); -} - /// Dynamically inquire about whether we're running under V. /// You should usually not use this unless your test definitely /// can't run correctly un-altered. Valgrind is there to help diff --git a/src/test/run-pass/foreign-call-no-runtime.rs b/src/test/run-pass/foreign-call-no-runtime.rs index b56847b2da0d..989c09146b7d 100644 --- a/src/test/run-pass/foreign-call-no-runtime.rs +++ b/src/test/run-pass/foreign-call-no-runtime.rs @@ -11,7 +11,7 @@ extern crate libc; use std::mem; -use std::unstable::run_in_bare_thread; +use std::rt::thread::Thread; #[link(name = "rustrt")] extern { @@ -21,10 +21,10 @@ extern { pub fn main() { unsafe { - run_in_bare_thread(proc() { + Thread::start(proc() { let i = &100; rust_dbg_call(callback, mem::transmute(i)); - }); + }).join(); } } From 50331595fca761eba8b034a6e73143b01b330c04 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 14 May 2014 01:36:12 -0700 Subject: [PATCH 19/22] std: Delete unused file --- src/libstd/io/flate.rs | 52 ------------------------------------------ 1 file changed, 52 deletions(-) delete mode 100644 src/libstd/io/flate.rs diff --git a/src/libstd/io/flate.rs b/src/libstd/io/flate.rs deleted file mode 100644 index 0cf00b2c1a9a..000000000000 --- a/src/libstd/io/flate.rs +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2013 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. - -//! Some various other I/O types - -// FIXME(#3660): should move to libextra - -use prelude::*; -use super::*; - -/// A Writer decorator that compresses using the 'deflate' scheme -pub struct DeflateWriter { - priv inner_writer: W -} - -impl DeflateWriter { - pub fn new(inner_writer: W) -> DeflateWriter { - DeflateWriter { - inner_writer: inner_writer - } - } -} - -impl Writer for DeflateWriter { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -/// A Reader decorator that decompresses using the 'deflate' scheme -pub struct InflateReader { - priv inner_reader: R -} - -impl InflateReader { - pub fn new(inner_reader: R) -> InflateReader { - InflateReader { - inner_reader: inner_reader - } - } -} - -impl Reader for InflateReader { - fn read(&mut self, _buf: &mut [u8]) -> Option { fail!() } -} From a0594ebb8baa0544ed0f818c494be20b3c9957a5 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 12 May 2014 21:02:27 -0700 Subject: [PATCH 20/22] core: Remove the unit module --- src/libcore/cmp.rs | 18 ++++++++++++++++- src/libcore/default.rs | 5 +++++ src/libcore/lib.rs | 1 - src/libcore/unit.rs | 45 ------------------------------------------ 4 files changed, 22 insertions(+), 47 deletions(-) delete mode 100644 src/libcore/unit.rs diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 52df7e71727e..bf02f053336b 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -192,7 +192,23 @@ pub fn max(v1: T, v2: T) -> T { // Implementation of Eq/TotalEq for some primitive types #[cfg(not(test))] mod impls { - use cmp::{Ord, TotalOrd, Eq, TotalEq, Ordering}; + use cmp::{Ord, TotalOrd, Eq, TotalEq, Ordering, Equal}; + + impl Eq for () { + #[inline] + fn eq(&self, _other: &()) -> bool { true } + #[inline] + fn ne(&self, _other: &()) -> bool { false } + } + impl TotalEq for () {} + impl Ord for () { + #[inline] + fn lt(&self, _other: &()) -> bool { false } + } + impl TotalOrd for () { + #[inline] + fn cmp(&self, _other: &()) -> Ordering { Equal } + } // & pointers impl<'a, T: Eq> Eq for &'a T { diff --git a/src/libcore/default.rs b/src/libcore/default.rs index af65fcc5a779..50ddfcc52f7b 100644 --- a/src/libcore/default.rs +++ b/src/libcore/default.rs @@ -16,6 +16,11 @@ pub trait Default { fn default() -> Self; } +impl Default for () { + #[inline] + fn default() -> () { () } +} + impl Default for @T { fn default() -> @T { @Default::default() } } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 4102c72d8b64..22719dc9f2d7 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -103,7 +103,6 @@ pub mod container; /* Core types and methods on primitives */ mod unicode; -mod unit; pub mod any; pub mod atomics; pub mod bool; diff --git a/src/libcore/unit.rs b/src/libcore/unit.rs deleted file mode 100644 index f55cb2d22360..000000000000 --- a/src/libcore/unit.rs +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2012-2013 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. - -//! Functions for the unit type. - -#[cfg(not(test))] -use default::Default; -#[cfg(not(test))] -use cmp::{Eq, Equal, Ord, Ordering, TotalEq, TotalOrd}; - -#[cfg(not(test))] -impl Eq for () { - #[inline] - fn eq(&self, _other: &()) -> bool { true } - #[inline] - fn ne(&self, _other: &()) -> bool { false } -} - -#[cfg(not(test))] -impl Ord for () { - #[inline] - fn lt(&self, _other: &()) -> bool { false } -} - -#[cfg(not(test))] -impl TotalOrd for () { - #[inline] - fn cmp(&self, _other: &()) -> Ordering { Equal } -} - -#[cfg(not(test))] -impl TotalEq for () {} - -#[cfg(not(test))] -impl Default for () { - #[inline] - fn default() -> () { () } -} From 9c35ac5666b62697bdd197028864fa66127a5415 Mon Sep 17 00:00:00 2001 From: Keegan McAllister Date: Tue, 13 May 2014 17:29:30 -0700 Subject: [PATCH 21/22] Implement cell::clone_ref Per discussion with @alexcrichton, this is a free function. --- src/libcore/cell.rs | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 0413b31e8b76..8b3494f31273 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -186,6 +186,25 @@ impl<'b, T> Deref for Ref<'b, T> { } } +/// Copy a `Ref`. +/// +/// The `RefCell` is already immutably borrowed, so this cannot fail. +/// +/// A `Clone` implementation would interfere with the widespread +/// use of `r.borrow().clone()` to clone the contents of a `RefCell`. +#[experimental] +pub fn clone_ref<'b, T>(orig: &Ref<'b, T>) -> Ref<'b, T> { + // Since this Ref exists, we know the borrow flag + // is not set to WRITING. + let borrow = orig.parent.borrow.get(); + debug_assert!(borrow != WRITING && borrow != UNUSED); + orig.parent.borrow.set(borrow + 1); + + Ref { + parent: orig.parent, + } +} + /// Wraps a mutable borrowed reference to a value in a `RefCell` box. pub struct RefMut<'b, T> { parent: &'b RefCell @@ -307,4 +326,19 @@ mod test { let _ = _b; let _b = x.borrow_mut(); } + + #[test] + fn clone_ref_updates_flag() { + let x = RefCell::new(0); + { + let b1 = x.borrow(); + assert!(x.try_borrow_mut().is_none()); + { + let _b2 = clone_ref(&b1); + assert!(x.try_borrow_mut().is_none()); + } + assert!(x.try_borrow_mut().is_none()); + } + assert!(x.try_borrow_mut().is_some()); + } } From 17df573a2e47d5815b5feb938626f9b6ec9ee4ee Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 15 May 2014 14:59:01 -0700 Subject: [PATCH 22/22] Test fixes from rollup Closes #14231 (mk: Don't run benchmarks with `make check`) Closes #14215 (std: Modify TempDir to not fail on drop. Closes #12628) Closes #14211 (rustdoc: functions in ffi blocks are unsafe) Closes #14210 (Make Vec.truncate() resilient against failure in Drop) Closes #14208 (Make `from_bits` in `bitflags!` safe; add `from_bits_truncate`) Closes #14206 (Register new snapshots) Closes #14205 (use sched_yield on linux and freebsd) Closes #14204 (Add a crate for missing stubs from libcore) Closes #14203 (shootout-mandelbrot: Either 10-20% or 80-100% improvement.) Closes #14202 (Add flow-graph visualization (via graphviz) to rustc) Closes #14201 (Render not_found with an absolute path to the rust stylesheet) Closes #14200 (std cleanup) Closes #14189 (Implement cell::clone_ref) --- src/libgreen/sched.rs | 1 - src/librustuv/lib.rs | 2 +- src/librustuv/uvio.rs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libgreen/sched.rs b/src/libgreen/sched.rs index 5bc96dd6e8ee..812e998ad9d9 100644 --- a/src/libgreen/sched.rs +++ b/src/libgreen/sched.rs @@ -1137,7 +1137,6 @@ mod test { fn test_schedule_home_states() { use sleeper_list::SleeperList; use super::{Shutdown, Scheduler, SchedHandle}; - use std::unstable::Thread; use std::rt::thread::Thread; use std::sync::deque::BufferPool; diff --git a/src/librustuv/lib.rs b/src/librustuv/lib.rs index 96b66f616f6e..53515ec58e58 100644 --- a/src/librustuv/lib.rs +++ b/src/librustuv/lib.rs @@ -472,7 +472,7 @@ fn local_loop() -> &'static mut uvio::UvIoFactory { #[cfg(test)] mod test { use std::mem::transmute; - use std::rt::Thread; + use std::rt::thread::Thread; use super::{slice_to_uv_buf, Loop}; diff --git a/src/librustuv/uvio.rs b/src/librustuv/uvio.rs index 88e05f815b27..71589e00fc00 100644 --- a/src/librustuv/uvio.rs +++ b/src/librustuv/uvio.rs @@ -27,7 +27,7 @@ use std::rt::rtio; use std::rt::rtio::{ProcessConfig, IoFactory, EventLoop}; use ai = std::io::net::addrinfo; -#[cfg(test)] use std::rt::Thread; +#[cfg(test)] use std::rt::thread::Thread; use super::{uv_error_to_io_error, Loop};