diff options
| author | bors <bors@rust-lang.org> | 2014-05-15 15:56:54 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2014-05-15 15:56:54 -0700 |
| commit | 0481d628b826104085c5df267cf6089a89fcd17b (patch) | |
| tree | 5d488af95a17f26977bb0384d701bd560dbdcde8 /src | |
| parent | 182c96c9212a2b7e830fe5f9a6662e72f73775ec (diff) | |
| parent | 17df573a2e47d5815b5feb938626f9b6ec9ee4ee (diff) | |
| download | rust-0481d628b826104085c5df267cf6089a89fcd17b.tar.gz rust-0481d628b826104085c5df267cf6089a89fcd17b.zip | |
auto merge of #14234 : alexcrichton/rust/rollup, r=alexcrichton
Let's try this again!
Diffstat (limited to 'src')
91 files changed, 2014 insertions, 423 deletions
diff --git a/src/doc/rust.md b/src/doc/rust.md index f242a89784c..838ddca042d 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/cell.rs b/src/libcore/cell.rs index 0413b31e8b7..8b3494f3127 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -186,6 +186,25 @@ impl<'b, T> Deref<T> 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<T> @@ -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()); + } } diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index 52df7e71727..bf02f053336 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -192,7 +192,23 @@ pub fn max<T: TotalOrd>(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 af65fcc5a77..50ddfcc52f7 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<T: Default + 'static> Default for @T { fn default() -> @T { @Default::default() } } diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 4eab7e9d45d..22719dc9f2d 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 @@ -100,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; @@ -116,9 +118,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 3af12c5154c..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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>(*T); - -impl<T: Default> Default for Box<T> { - fn default() -> Box<T> { box Default::default() } -} - -impl<T: Clone> Clone for Box<T> { - /// Return a copy of the owned box. - #[inline] - fn clone(&self) -> Box<T> { box {(**self).clone()} } - - /// Perform copy-assignment from `source` by reusing the existing allocation. - #[inline] - fn clone_from(&mut self, source: &Box<T>) { - (**self).clone_from(&(**source)); - } -} - -// box pointers -impl<T:Eq> Eq for Box<T> { - #[inline] - fn eq(&self, other: &Box<T>) -> bool { *(*self) == *(*other) } - #[inline] - fn ne(&self, other: &Box<T>) -> bool { *(*self) != *(*other) } -} -impl<T:Ord> Ord for Box<T> { - #[inline] - fn lt(&self, other: &Box<T>) -> bool { *(*self) < *(*other) } - #[inline] - fn le(&self, other: &Box<T>) -> bool { *(*self) <= *(*other) } - #[inline] - fn ge(&self, other: &Box<T>) -> bool { *(*self) >= *(*other) } - #[inline] - fn gt(&self, other: &Box<T>) -> bool { *(*self) > *(*other) } -} -impl<T: TotalOrd> TotalOrd for Box<T> { - #[inline] - fn cmp(&self, other: &Box<T>) -> Ordering { (**self).cmp(*other) } -} -impl<T: TotalEq> TotalEq for Box<T> {} - -/// 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<T: 'static>(self) -> Result<Box<T>, Self>; -} - -impl AnyOwnExt for Box<Any> { - #[inline] - fn move<T: 'static>(self) -> Result<Box<T>, Box<Any>> { - if self.is::<T>() { - unsafe { - // Get the raw representation of the trait object - let to: TraitObject = - *mem::transmute::<&Box<Any>, &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/libcore/unit.rs b/src/libcore/unit.rs deleted file mode 100644 index f55cb2d2236..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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() -> () { () } -} diff --git a/src/libgreen/sched.rs b/src/libgreen/sched.rs index 8c294fa2928..812e998ad9d 100644 --- a/src/libgreen/sched.rs +++ b/src/libgreen/sched.rs @@ -1137,11 +1137,10 @@ 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::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 +1259,7 @@ mod test { normal_thread.join(); special_thread.join(); - }); + }).join(); } //#[test] diff --git a/src/libnative/io/file_unix.rs b/src/libnative/io/file_unix.rs index c2b69483fa1..046d2875d55 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 d721e1d67f1..3222c912dd0 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/librlibc/lib.rs b/src/librlibc/lib.rs new file mode 100644 index 00000000000..904fbe9be9b --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T>(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 4d70ecb888f..429a8f5be5e 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/config.rs b/src/librustc/driver/config.rs index e929c64e58a..da573a014d0 100644 --- a/src/librustc/driver/config.rs +++ b/src/librustc/driver/config.rs @@ -519,12 +519,13 @@ pub fn optgroups() -> Vec<getopts::OptGroup> { optopt( "", "out-dir", "Write output to compiler-chosen filename in <dir>", "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=<nodeid>` (graphviz formatted flowgraph for node)", + "TYPE"), optflagopt("", "dep-info", "Output dependency info to <filename> 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 51bdf9ef9ed..5f9fd7124a9 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; @@ -356,6 +361,7 @@ pub struct CrateTranslation { pub metadata: Vec<u8>, pub reachable: Vec<StrBuf>, pub crate_formats: dependency_format::Dependencies, + pub no_builtins: bool, } /// Run the translation phase to LLVM, after which the AST and analysis can @@ -581,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<Path>) { 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, @@ -643,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(), @@ -657,6 +675,32 @@ pub fn pretty_print_input(sess: Session, } +fn print_flowgraph<W:io::Writer>(analysis: CrateAnalysis, + block: ast::P<ast::Block>, + 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<config::CrateType> { // 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 b355d474bd5..f32a8ec7cd7 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=<nodeid>` needs \ + an integer <nodeid>; 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=<nodeid>`, `typed`, `identified`, \ + or `expanded,identified`; got {}", name)); } } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index d3b5fb1ca47..18c59a955b5 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/lib/llvm.rs b/src/librustc/lib/llvm.rs index 0c874bd776e..711081f46d6 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/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index d631340fc4e..c9c397d3d61 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -18,10 +18,10 @@ use util::nodemap::NodeMap; struct CFGBuilder<'a> { tcx: &'a ty::ctxt, - method_map: typeck::MethodMap, exit_map: NodeMap<CFGIndex>, graph: CFGGraph, - loop_scopes: Vec<LoopScope> , + fn_exit: CFGIndex, + loop_scopes: Vec<LoopScope>, } struct LoopScope { @@ -31,22 +31,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 +340,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 +467,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 +505,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<ast::Ident>) -> LoopScope { @@ -521,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 00000000000..b8baeefd3d0 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 97ea996bb7e..f0b912fb87b 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<CFGIndex>, - graph: CFGGraph, - entry: CFGIndex, - exit: CFGIndex, + pub exit_map: NodeMap<CFGIndex>, + 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<ast::NodeId> + pub exiting_scopes: Vec<ast::NodeId> } 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) } } diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs index 2705f9bf9bf..5773d0bafa1 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<N,E> Graph<N,E> { @@ -201,39 +205,39 @@ impl<N,E> Graph<N,E> { /////////////////////////////////////////////////////////////////////////// // Iterating over nodes, edges - pub fn each_node(&self, f: |NodeIndex, &Node<N>| -> bool) -> bool { + pub fn each_node<'a>(&'a self, f: |NodeIndex, &'a Node<N>| -> 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<E>| -> bool) -> bool { + pub fn each_edge<'a>(&'a self, f: |EdgeIndex, &'a Edge<E>| -> 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<E>| -> bool) - -> bool { + pub fn each_outgoing_edge<'a>(&'a self, + source: NodeIndex, + f: |EdgeIndex, &'a Edge<E>| -> 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<E>| -> bool) - -> bool { + pub fn each_incoming_edge<'a>(&'a self, + target: NodeIndex, + f: |EdgeIndex, &'a Edge<E>| -> 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<E>| -> bool) - -> bool { + pub fn each_adjacent_edge<'a>(&'a self, + node: NodeIndex, + dir: Direction, + f: |EdgeIndex, &'a Edge<E>| -> bool) + -> bool { //! Iterates over all edges adjacent to the node `node` //! in the direction `dir` (either `Outgoing` or `Incoming) @@ -257,11 +261,11 @@ impl<N,E> Graph<N,E> { // 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<E>| - -> bool) { + pub fn iterate_until_fixed_point<'a>(&'a self, + op: |iter_index: uint, + edge_index: EdgeIndex, + edge: &'a Edge<E>| + -> bool) { let mut iteration = 0; let mut changed = true; while changed { diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 062a7418287..1c24d609551 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 17aa0664d47..92e3b95abad 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/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index bc3a0c0073f..861caa62515 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/librustdoc/clean.rs b/src/librustdoc/clean.rs index 4439f626b2c..bd911f42db0 100644 --- a/src/librustdoc/clean.rs +++ b/src/librustdoc/clean.rs @@ -1204,7 +1204,7 @@ impl Clean<Item> for ast::ForeignItem { ForeignFunctionItem(Function { decl: decl.clean(), generics: generics.clean(), - fn_style: ast::NormalFn, + fn_style: ast::UnsafeFn, }) } ast::ForeignItemStatic(ref ty, mutbl) => { diff --git a/src/librustuv/file.rs b/src/librustuv/file.rs index 06271e61ce7..12636a3c490 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/librustuv/lib.rs b/src/librustuv/lib.rs index c9bff2e80bf..53515ec58e5 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::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 1b8175448fc..71589e00fc0 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::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/bitflags.rs b/src/libstd/bitflags.rs index 32f9bc1173b..163ccd22552 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] diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index a8e7b324bd7..68cbdd2e0aa 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -209,7 +209,7 @@ impl<W: Writer> Writer for BufferedWriter<W> { impl<W: Writer> Drop for BufferedWriter<W> { 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/flate.rs b/src/libstd/io/flate.rs deleted file mode 100644 index 0cf00b2c1a9..00000000000 --- 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 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<W> { - priv inner_writer: W -} - -impl<W: Writer> DeflateWriter<W> { - pub fn new(inner_writer: W) -> DeflateWriter<W> { - DeflateWriter { - inner_writer: inner_writer - } - } -} - -impl<W: Writer> Writer for DeflateWriter<W> { - fn write(&mut self, _buf: &[u8]) { fail!() } - - fn flush(&mut self) { fail!() } -} - -/// A Reader decorator that decompresses using the 'deflate' scheme -pub struct InflateReader<R> { - priv inner_reader: R -} - -impl<R: Reader> InflateReader<R> { - pub fn new(inner_reader: R) -> InflateReader<R> { - InflateReader { - inner_reader: inner_reader - } - } -} - -impl<R: Reader> Reader for InflateReader<R> { - fn read(&mut self, _buf: &mut [u8]) -> Option<uint> { fail!() } -} diff --git a/src/libstd/io/tempfile.rs b/src/libstd/io/tempfile.rs index 8c28caa988a..b4fb95c8af7 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> + path: Option<Path>, + 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/libstd/lib.rs b/src/libstd/lib.rs index a37f9a516fd..87c4ef1046f 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/libstd/rt/local.rs b/src/libstd/rt/local.rs index 05d1f1764b5..9f0ed804480 100644 --- a/src/libstd/rt/local.rs +++ b/src/libstd/rt/local.rs @@ -53,24 +53,24 @@ impl Local<local_ptr::Borrowed<Task>> 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<Task> = 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<Task> = Local::take(); @@ -79,12 +79,12 @@ mod test { Local::put(task); let task: Box<Task> = 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<Task> = 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<Task> = 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<Task>) { diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs index 4f0d7d35ce8..e25fa4734d5 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; } } diff --git a/src/libstd/str.rs b/src/libstd/str.rs index fa4cf8e4427..aee5fe9ff96 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) } diff --git a/src/libstd/unstable/mod.rs b/src/libstd/unstable/mod.rs index 8b07850263f..f464f70772d 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/libstd/vec.rs b/src/libstd/vec.rs index 528ab72762a..57f8d78948f 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -635,14 +635,14 @@ impl<T> Vec<T> { /// ``` 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); + } } diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index 333f876e479..6a7b913dce4 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<Block>), /// 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<Block>), 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() diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index 1031f3c1570..64776421fa1 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 diff --git a/src/snapshots.txt b/src/snapshots.txt index e88ae02c1c6..4c62d519d78 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 diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index e17324ee596..debd12874da 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -7,73 +7,169 @@ // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // 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; +static WORKERS: uint = 16; + +#[inline(always)] +fn mandelbrot<W: io::Writer>(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 v_inverses = f64x2(inverse_w_doubled, inverse_h_doubled); + let v_consts = f64x2(1.5, 1.0); + + // 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<u8> = 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() { + try!(out.write(res.unwrap().as_slice())); + } + out.flush() +} fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec<u8>) { + 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 cur_bitmask = 0x80; - for &init_r in chunk_init_r.iter() { - let mut cur_r = init_r; - let mut cur_i = init_i; + 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_r = r * r - i * i + init_r; - cur_i = 2.0 * r * i + init_i; - if r * r + i * i > LIMIT * LIMIT { - cur_byte &= !cur_bitmask; - break; + 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_bitmask >>= 1; - } - res.push(cur_byte); - } -} -fn mandelbrot<W: io::Writer>(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 data: Vec<Future<Vec<u8>>> = 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 mut res: Vec<u8> = 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; - write_line(init_i, vec_init_r.as_slice(), &mut res); + cur_byte = (cur_byte << 2) + b; + i += 2; } - res - })).collect(); - try!(writeln!(&mut out as &mut Writer, "P4\n{} {}", w, h)); - for res in data.move_iter() { - try!(out.write(res.unwrap().as_slice())); + res.push(cur_byte^-1); } - out.flush() } 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(); } diff --git a/src/test/run-make/graphviz-flowgraph/Makefile b/src/test/run-make/graphviz-flowgraph/Makefile new file mode 100644 index 00000000000..fedcc89cd42 --- /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 00000000000..f699771ef24 --- /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 00000000000..4e7fc7ea9b0 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..9d8411cfc58 --- /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 00000000000..231aab69e50 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..ada3f091808 --- /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 00000000000..3cdd73a49e1 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..aff430459e8 --- /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 00000000000..8b172c0a105 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..adcc582c733 --- /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 00000000000..2a0ac8ac9e5 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..2d52c14da62 --- /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 00000000000..616d822bed0 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..61b40d68dd1 --- /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 00000000000..c914409629c --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..c99af179149 --- /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 00000000000..39f71d309fd --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..61a708cd9cc --- /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 00000000000..6ba7b03d54d --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..892b9fcd841 --- /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 00000000000..a78ccb8a937 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..2cef122104e --- /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 00000000000..0ca7cc5ee86 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..59d65e5b8b7 --- /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 00000000000..d0f3452119e --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..9c0f25d5bec --- /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 00000000000..90b146340b6 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..2be43dcaa7b --- /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 00000000000..0817a3210ce --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..0fa4e9b44de --- /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 00000000000..98ff095c831 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..f0278fba311 --- /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 00000000000..44c038d643b --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..3f999ae3781 --- /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 00000000000..f4f23a65c93 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..e9bccdab81b --- /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 00000000000..23f5bb8a1eb --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..6345b4effaf --- /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 00000000000..0ace542b8f5 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..5fad18536e5 --- /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 00000000000..092f6890a15 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..593ad6f91ea --- /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 00000000000..d7349932355 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..0798c4a01c0 --- /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 00000000000..70083ed8312 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 00000000000..9ad731bc756 --- /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 00000000000..b35aac9ec42 --- /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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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"; +} diff --git a/src/test/run-pass/foreign-call-no-runtime.rs b/src/test/run-pass/foreign-call-no-runtime.rs index b56847b2da0..989c09146b7 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(); } } diff --git a/src/test/run-pass/tempfile.rs b/src/test/run-pass/tempfile.rs index 437d6faea38..387a454542a 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); } |
