From e47ee779cd412ad629ab0f3db1babcc502862924 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 19 Apr 2013 15:18:38 -0700 Subject: [PATCH 001/215] wip --- src/libcore/rt/io/{util.rs => extensions.rs} | 0 src/libcore/rt/io/file.rs | 6 +----- src/libcore/rt/io/mod.rs | 11 +++++------ src/libcore/rt/io/net/unix.rs | 2 +- src/libcore/rt/io/{misc.rs => support.rs} | 0 5 files changed, 7 insertions(+), 12 deletions(-) rename src/libcore/rt/io/{util.rs => extensions.rs} (100%) rename src/libcore/rt/io/{misc.rs => support.rs} (100%) diff --git a/src/libcore/rt/io/util.rs b/src/libcore/rt/io/extensions.rs similarity index 100% rename from src/libcore/rt/io/util.rs rename to src/libcore/rt/io/extensions.rs diff --git a/src/libcore/rt/io/file.rs b/src/libcore/rt/io/file.rs index e041183b58452..4e3e01a5eceb9 100644 --- a/src/libcore/rt/io/file.rs +++ b/src/libcore/rt/io/file.rs @@ -9,14 +9,10 @@ // except according to those terms. use prelude::*; -use super::misc::PathLike; +use super::support::PathLike; use super::{Reader, Writer, Seek, Close}; use super::{IoError, SeekStyle}; -/// Open a file with the default FileMode and FileAccess -/// # XXX are there sane defaults here? -pub fn open_file(_path: &P) -> FileStream { fail!() } - /// # XXX /// * Ugh, this is ridiculous. What is the best way to represent these options? enum FileMode { diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs index b035532144c44..7ab27cdd7ec55 100644 --- a/src/libcore/rt/io/mod.rs +++ b/src/libcore/rt/io/mod.rs @@ -104,7 +104,6 @@ pub use self::stdio::stderr; pub use self::stdio::print; pub use self::stdio::println; -pub use self::file::open_file; pub use self::file::FileStream; pub use self::net::Listener; pub use self::net::ip::IpAddr; @@ -113,9 +112,9 @@ pub use self::net::tcp::TcpStream; pub use self::net::udp::UdpStream; // Some extension traits that all Readers and Writers get. -pub use self::util::ReaderUtil; -pub use self::util::ReaderByteConversions; -pub use self::util::WriterByteConversions; +pub use self::extensions::ReaderUtil; +pub use self::extensions::ReaderByteConversions; +pub use self::extensions::WriterByteConversions; /// Synchronous, non-blocking file I/O. pub mod file; @@ -140,10 +139,10 @@ pub mod flate; pub mod comm_adapters; /// Extension traits -mod util; +mod extensions; /// Non-I/O things needed by the I/O module -mod misc; +mod support; /// Thread-blocking implementations pub mod native { diff --git a/src/libcore/rt/io/net/unix.rs b/src/libcore/rt/io/net/unix.rs index 35eabe21b2a6b..de886949e7b0d 100644 --- a/src/libcore/rt/io/net/unix.rs +++ b/src/libcore/rt/io/net/unix.rs @@ -11,7 +11,7 @@ use prelude::*; use super::*; use super::super::*; -use super::super::misc::PathLike; +use super::super::support::PathLike; pub struct UnixStream; diff --git a/src/libcore/rt/io/misc.rs b/src/libcore/rt/io/support.rs similarity index 100% rename from src/libcore/rt/io/misc.rs rename to src/libcore/rt/io/support.rs From 6a5c4f68c2f8c10bf439a39373f5c518ed2f58a1 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 19 Apr 2013 18:47:31 -0700 Subject: [PATCH 002/215] core::rt: Just some poking at the I/O docs --- src/libcore/rt/io/mod.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs index 7ab27cdd7ec55..c04389e029060 100644 --- a/src/libcore/rt/io/mod.rs +++ b/src/libcore/rt/io/mod.rs @@ -10,8 +10,12 @@ /*! Synchronous I/O -This module defines the Rust interface for synchronous I/O. -It supports file access, +This module defines the Rust interface for synchronous I/O. It is +build around Reader and Writer traits that define byte stream sources +and sinks. Implementations are provided for common I/O streams like +file, TCP, UDP, Unix domain sockets, multiple types of memory bufers. +Readers and Writers may be composed to add things like string parsing, +and compression. This will likely live in core::io, not core::rt::io. @@ -27,7 +31,7 @@ Some examples of obvious things you might want to do * Read a complete file to a string, (converting newlines?) - let contents = open("message.txt").read_to_str(); // read_to_str?? + let contents = FileStream::open("message.txt").read_to_str(); // read_to_str?? * Write a line to a file @@ -36,13 +40,26 @@ Some examples of obvious things you might want to do * Iterate over the lines of a file + do FileStream::open("message.txt").each_line |line| { + println(line) + } + * Pull the lines of a file into a vector of strings + let lines = FileStream::open("message.txt").line_iter().to_vec(); + +* Make an simple HTTP request + + let socket = TcpStream::open("localhost:8080"); + socket.write_line("GET / HTTP/1.0"); + socket.write_line(""); + let response = socket.read_to_end(); + * Connect based on URL? Requires thinking about where the URL type lives and how to make protocol handlers extensible, e.g. the "tcp" protocol yields a `TcpStream`. - connect("tcp://localhost:8080").write_line("HTTP 1.0 GET /"); + connect("tcp://localhost:8080"); # Terms From 1f97e6d47f90f1ddfef2d3a888099bd95b0bb1df Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 00:24:44 -0700 Subject: [PATCH 003/215] rt: Add rust_dbg_next_port for generating test port numbers --- src/rt/rust_test_helpers.cpp | 11 +++++++++++ src/rt/rustrt.def.in | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/rt/rust_test_helpers.cpp b/src/rt/rust_test_helpers.cpp index 64966bd345489..7938d65acd21d 100644 --- a/src/rt/rust_test_helpers.cpp +++ b/src/rt/rust_test_helpers.cpp @@ -165,3 +165,14 @@ extern "C" CDECL TwoDoubles rust_dbg_extern_identity_TwoDoubles(TwoDoubles u) { return u; } + +// Generates increasing port numbers for network testing +extern "C" CDECL uintptr_t +rust_dbg_next_port() { + static lock_and_signal dbg_port_lock; + static uintptr_t next_port = 9000; + scoped_lock with(dbg_port_lock); + uintptr_t this_port = next_port; + next_port += 1; + return this_port; +} diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 5a556ed2107df..f84a73a394b6c 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -221,4 +221,4 @@ rust_uv_free_ip4_addr rust_uv_free_ip6_addr rust_call_nullary_fn rust_initialize_global_state - +rust_dbg_next_port From 744ba627f34ebf76b5a784085645780066d8d92a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 00:33:49 -0700 Subject: [PATCH 004/215] core::rt: Add a test mod and put run_in_newsched_task there --- src/libcore/rt/mod.rs | 4 ++++ src/libcore/rt/test.rs | 29 +++++++++++++++++++++++++++++ src/libcore/task/mod.rs | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/libcore/rt/test.rs diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs index e93e0c6fc6cc9..70bc2c7e063fc 100644 --- a/src/libcore/rt/mod.rs +++ b/src/libcore/rt/mod.rs @@ -49,6 +49,10 @@ mod context; mod thread; pub mod env; +/// Tools for testing the runtime +#[cfg(test)] +pub mod test; + #[cfg(stage0)] pub fn start(main: *u8, _argc: int, _argv: *c_char, _crate_map: *u8) -> int { use self::sched::{Scheduler, Task}; diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs new file mode 100644 index 0000000000000..14d69c2373253 --- /dev/null +++ b/src/libcore/rt/test.rs @@ -0,0 +1,29 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// For setting up tests of the new scheduler +pub fn run_in_newsched_task(f: ~fn()) { + use cell::Cell; + use unstable::run_in_bare_thread; + use super::sched::Task; + use super::uvio::UvEventLoop; + + let f = Cell(Cell(f)); + + do run_in_bare_thread { + let mut sched = ~UvEventLoop::new_scheduler(); + let f = f.take(); + let task = ~do Task::new(&mut sched.stack_pool) { + (f.take())(); + }; + sched.task_queue.push_back(task); + sched.run(); + } +} diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index a6c03638713ed..a243bfba85c6f 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -1229,7 +1229,7 @@ fn test_spawn_thread_on_demand() { #[test] fn test_simple_newsched_spawn() { - use rt::run_in_newsched_task; + use rt::test::run_in_newsched_task; do run_in_newsched_task { spawn(||()) From d24a3a4b016331438ec3c611e37c11cfe41fa4af Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 01:16:06 -0700 Subject: [PATCH 005/215] core::rt: Use generated port numbers in tests --- src/libcore/rt/test.rs | 10 ++++++++ src/libcore/rt/uv/net.rs | 48 +++++------------------------------- src/libcore/rt/uvio.rs | 13 +++++----- src/rt/rust_test_helpers.cpp | 2 +- 4 files changed, 24 insertions(+), 49 deletions(-) diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs index 14d69c2373253..c2ad7d37d42ad 100644 --- a/src/libcore/rt/test.rs +++ b/src/libcore/rt/test.rs @@ -27,3 +27,13 @@ pub fn run_in_newsched_task(f: ~fn()) { sched.run(); } } + +/// Get a port number, starting at 9600, for use in tests +pub fn next_test_port() -> u16 { + unsafe { + return rust_dbg_next_port() as u16; + } + extern { + fn rust_dbg_next_port() -> ::libc::uintptr_t; + } +} diff --git a/src/libcore/rt/uv/net.rs b/src/libcore/rt/uv/net.rs index 0dc1a4d86cbc9..54823d4dbcf61 100644 --- a/src/libcore/rt/uv/net.rs +++ b/src/libcore/rt/uv/net.rs @@ -19,12 +19,10 @@ use super::{Loop, Watcher, Request, UvError, Buf, Callback, NativeHandle, NullCa vec_to_uv_buf, vec_from_uv_buf}; use super::super::io::net::ip::{IpAddr, Ipv4, Ipv6}; -#[cfg(test)] -use unstable::run_in_bare_thread; -#[cfg(test)] -use super::super::thread::Thread; -#[cfg(test)] -use cell::Cell; +#[cfg(test)] use cell::Cell; +#[cfg(test)] use unstable::run_in_bare_thread; +#[cfg(test)] use super::super::thread::Thread; +#[cfg(test)] use super::super::test::next_test_port; fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in)) { match addr { @@ -361,7 +359,7 @@ fn connect_close() { let mut loop_ = Loop::new(); let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; // Connect to a port where nobody is listening - let addr = Ipv4(127, 0, 0, 1, 2923); + let addr = Ipv4(127, 0, 0, 1, next_test_port()); do tcp_watcher.connect(addr) |stream_watcher, status| { rtdebug!("tcp_watcher.connect!"); assert!(status.is_some()); @@ -373,47 +371,13 @@ fn connect_close() { } } -#[test] -#[ignore(reason = "need a server to connect to")] -fn connect_read() { - do run_in_bare_thread() { - let mut loop_ = Loop::new(); - let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; - let addr = Ipv4(127, 0, 0, 1, 2924); - do tcp_watcher.connect(addr) |stream_watcher, status| { - let mut stream_watcher = stream_watcher; - rtdebug!("tcp_watcher.connect!"); - assert!(status.is_none()); - let alloc: AllocCallback = |size| { - vec_to_uv_buf(vec::from_elem(size, 0)) - }; - do stream_watcher.read_start(alloc) - |stream_watcher, nread, buf, status| { - - let buf = vec_from_uv_buf(buf); - rtdebug!("read cb!"); - if status.is_none() { - let bytes = buf.unwrap(); - rtdebug!("%s", bytes.slice(0, nread as uint).to_str()); - } else { - rtdebug!("status after read: %s", status.get().to_str()); - rtdebug!("closing"); - stream_watcher.close(||()); - } - } - } - loop_.run(); - loop_.close(); - } -} - #[test] fn listen() { do run_in_bare_thread() { static MAX: int = 10; let mut loop_ = Loop::new(); let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) }; - let addr = Ipv4(127, 0, 0, 1, 2925); + let addr = Ipv4(127, 0, 0, 1, next_test_port()); server_tcp_watcher.bind(addr); let loop_ = loop_; rtdebug!("listening"); diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index ff5397398354a..a9aa0333b1631 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -19,9 +19,10 @@ use cell::{Cell, empty_cell}; use cast::transmute; use super::sched::{Scheduler, local_sched}; -#[cfg(test)] use super::sched::Task; -#[cfg(test)] use unstable::run_in_bare_thread; #[cfg(test)] use uint; +#[cfg(test)] use unstable::run_in_bare_thread; +#[cfg(test)] use super::sched::Task; +#[cfg(test)] use super::test::next_test_port; pub struct UvEventLoop { uvio: UvIoFactory @@ -340,7 +341,7 @@ fn test_simple_io_no_connect() { let mut sched = ~UvEventLoop::new_scheduler(); let task = ~do Task::new(&mut sched.stack_pool) { let io = unsafe { local_sched::unsafe_borrow_io() }; - let addr = Ipv4(127, 0, 0, 1, 2926); + let addr = Ipv4(127, 0, 0, 1, next_test_port()); let maybe_chan = io.connect(addr); assert!(maybe_chan.is_none()); }; @@ -354,7 +355,7 @@ fn test_simple_io_no_connect() { fn test_simple_tcp_server_and_client() { do run_in_bare_thread { let mut sched = ~UvEventLoop::new_scheduler(); - let addr = Ipv4(127, 0, 0, 1, 2929); + let addr = Ipv4(127, 0, 0, 1, next_test_port()); let client_task = ~do Task::new(&mut sched.stack_pool) { unsafe { @@ -393,7 +394,7 @@ fn test_simple_tcp_server_and_client() { fn test_read_and_block() { do run_in_bare_thread { let mut sched = ~UvEventLoop::new_scheduler(); - let addr = Ipv4(127, 0, 0, 1, 2930); + let addr = Ipv4(127, 0, 0, 1, next_test_port()); let client_task = ~do Task::new(&mut sched.stack_pool) { let io = unsafe { local_sched::unsafe_borrow_io() }; @@ -454,7 +455,7 @@ fn test_read_and_block() { fn test_read_read_read() { do run_in_bare_thread { let mut sched = ~UvEventLoop::new_scheduler(); - let addr = Ipv4(127, 0, 0, 1, 2931); + let addr = Ipv4(127, 0, 0, 1, next_test_port()); let client_task = ~do Task::new(&mut sched.stack_pool) { let io = unsafe { local_sched::unsafe_borrow_io() }; diff --git a/src/rt/rust_test_helpers.cpp b/src/rt/rust_test_helpers.cpp index 7938d65acd21d..d82c39d6838ec 100644 --- a/src/rt/rust_test_helpers.cpp +++ b/src/rt/rust_test_helpers.cpp @@ -170,7 +170,7 @@ rust_dbg_extern_identity_TwoDoubles(TwoDoubles u) { extern "C" CDECL uintptr_t rust_dbg_next_port() { static lock_and_signal dbg_port_lock; - static uintptr_t next_port = 9000; + static uintptr_t next_port = 9600; scoped_lock with(dbg_port_lock); uintptr_t this_port = next_port; next_port += 1; From eac629bf5c4b9efd0de3ff6a14d63584eb4a967d Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 01:32:06 -0700 Subject: [PATCH 006/215] core::rt: Unignore some networking tests These should work now, I hope --- src/libcore/rt/uvio.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index a9aa0333b1631..c615f068a6955 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -335,7 +335,6 @@ impl Stream for UvStream { } #[test] -#[ignore(reason = "ffi struct issues")] fn test_simple_io_no_connect() { do run_in_bare_thread { let mut sched = ~UvEventLoop::new_scheduler(); @@ -351,7 +350,6 @@ fn test_simple_io_no_connect() { } #[test] -#[ignore(reason = "ffi struct issues")] fn test_simple_tcp_server_and_client() { do run_in_bare_thread { let mut sched = ~UvEventLoop::new_scheduler(); From 1a7561be4d2046a6a6b78ae5dab2e6fd3ba8db82 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 01:37:59 -0700 Subject: [PATCH 007/215] core::rt: Remove redundant copy of run_in_newsched_task --- src/libcore/rt/mod.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs index 70bc2c7e063fc..cf896dd18f34c 100644 --- a/src/libcore/rt/mod.rs +++ b/src/libcore/rt/mod.rs @@ -164,24 +164,3 @@ fn test_context() { sched.run(); } } - -// For setting up tests of the new scheduler -#[cfg(test)] -pub fn run_in_newsched_task(f: ~fn()) { - use cell::Cell; - use unstable::run_in_bare_thread; - use self::sched::Task; - use self::uvio::UvEventLoop; - - let f = Cell(Cell(f)); - - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let f = f.take(); - let task = ~do Task::new(&mut sched.stack_pool) { - (f.take())(); - }; - sched.task_queue.push_back(task); - sched.run(); - } -} From e564fc7f6b02e917407b3aa6235fc0727afdaf2c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 01:55:10 -0700 Subject: [PATCH 008/215] core::rt: Don't directly create scheduler types in I/O tests There are some better abstractions for this now --- src/libcore/rt/test.rs | 16 ++++++++ src/libcore/rt/uvio.rs | 87 +++++++++++++++++------------------------- 2 files changed, 50 insertions(+), 53 deletions(-) diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs index c2ad7d37d42ad..dfc058d6eba5c 100644 --- a/src/libcore/rt/test.rs +++ b/src/libcore/rt/test.rs @@ -28,6 +28,22 @@ pub fn run_in_newsched_task(f: ~fn()) { } } +/// Create a new task and run it right now +pub fn spawn_immediately(f: ~fn()) { + use cell::Cell; + use super::*; + use super::sched::*; + + let mut sched = local_sched::take(); + let task = ~Task::new(&mut sched.stack_pool, f); + do sched.switch_running_tasks_and_then(task) |task| { + let task = Cell(task); + do local_sched::borrow |sched| { + sched.task_queue.push_front(task.take()); + } + } +} + /// Get a port number, starting at 9600, for use in tests pub fn next_test_port() -> u16 { unsafe { diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index c615f068a6955..d3953b7a797ab 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -22,7 +22,7 @@ use super::sched::{Scheduler, local_sched}; #[cfg(test)] use uint; #[cfg(test)] use unstable::run_in_bare_thread; #[cfg(test)] use super::sched::Task; -#[cfg(test)] use super::test::next_test_port; +#[cfg(test)] use super::test::*; pub struct UvEventLoop { uvio: UvIoFactory @@ -336,35 +336,21 @@ impl Stream for UvStream { #[test] fn test_simple_io_no_connect() { - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); - let task = ~do Task::new(&mut sched.stack_pool) { - let io = unsafe { local_sched::unsafe_borrow_io() }; - let addr = Ipv4(127, 0, 0, 1, next_test_port()); - let maybe_chan = io.connect(addr); - assert!(maybe_chan.is_none()); - }; - sched.task_queue.push_back(task); - sched.run(); + do run_in_newsched_task { + let io = unsafe { local_sched::unsafe_borrow_io() }; + let addr = Ipv4(127, 0, 0, 1, next_test_port()); + let maybe_chan = io.connect(addr); + assert!(maybe_chan.is_none()); } } #[test] fn test_simple_tcp_server_and_client() { - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); + do run_in_newsched_task { let addr = Ipv4(127, 0, 0, 1, next_test_port()); - let client_task = ~do Task::new(&mut sched.stack_pool) { - unsafe { - let io = local_sched::unsafe_borrow_io(); - let mut stream = io.connect(addr).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.close(); - } - }; - - let server_task = ~do Task::new(&mut sched.stack_pool) { + // Start the server first so it's listening when we connect + do spawn_immediately { unsafe { let io = local_sched::unsafe_borrow_io(); let mut listener = io.bind(addr).unwrap(); @@ -379,32 +365,25 @@ fn test_simple_tcp_server_and_client() { stream.close(); listener.close(); } - }; + } - // Start the server first so it listens before the client connects - sched.task_queue.push_back(server_task); - sched.task_queue.push_back(client_task); - sched.run(); + do spawn_immediately { + unsafe { + let io = local_sched::unsafe_borrow_io(); + let mut stream = io.connect(addr).unwrap(); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.close(); + } + } } } #[test] #[ignore(reason = "busted")] fn test_read_and_block() { - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); + do run_in_newsched_task { let addr = Ipv4(127, 0, 0, 1, next_test_port()); - let client_task = ~do Task::new(&mut sched.stack_pool) { - let io = unsafe { local_sched::unsafe_borrow_io() }; - let mut stream = io.connect(addr).unwrap(); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.write([0, 1, 2, 3, 4, 5, 6, 7]); - stream.close(); - }; - - let server_task = ~do Task::new(&mut sched.stack_pool) { + do spawn_immediately { let io = unsafe { local_sched::unsafe_borrow_io() }; let mut listener = io.bind(addr).unwrap(); let mut stream = listener.listen().unwrap(); @@ -440,22 +419,27 @@ fn test_read_and_block() { stream.close(); listener.close(); - }; + } + + do spawn_immediately { + let io = unsafe { local_sched::unsafe_borrow_io() }; + let mut stream = io.connect(addr).unwrap(); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.write([0, 1, 2, 3, 4, 5, 6, 7]); + stream.close(); + } - // Start the server first so it listens before the client connects - sched.task_queue.push_back(server_task); - sched.task_queue.push_back(client_task); - sched.run(); } } #[test] #[ignore(reason = "needs server")] fn test_read_read_read() { - do run_in_bare_thread { - let mut sched = ~UvEventLoop::new_scheduler(); + do run_in_newsched_task { let addr = Ipv4(127, 0, 0, 1, next_test_port()); - let client_task = ~do Task::new(&mut sched.stack_pool) { + do spawn_immediately { let io = unsafe { local_sched::unsafe_borrow_io() }; let mut stream = io.connect(addr).unwrap(); let mut buf = [0, .. 2048]; @@ -467,9 +451,6 @@ fn test_read_read_read() { } rtdebug_!("read %u bytes total", total_bytes_read as uint); stream.close(); - }; - - sched.task_queue.push_back(client_task); - sched.run(); + } } } From a11c032f36658667bb08382cc409455b0a1d0a61 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 02:16:21 -0700 Subject: [PATCH 009/215] core::rt: Fix a broken uvio test --- src/libcore/rt/uvio.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index d3953b7a797ab..2582ddf310510 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -434,22 +434,39 @@ fn test_read_and_block() { } } -#[test] #[ignore(reason = "needs server")] +#[test] fn test_read_read_read() { do run_in_newsched_task { let addr = Ipv4(127, 0, 0, 1, next_test_port()); + static MAX: uint = 5000000; + + do spawn_immediately { + unsafe { + let io = local_sched::unsafe_borrow_io(); + let mut listener = io.bind(addr).unwrap(); + let mut stream = listener.listen().unwrap(); + let mut buf = [0, .. 2048]; + let mut total_bytes_written = 0; + while total_bytes_written < MAX { + stream.write(buf); + total_bytes_written += buf.len(); + } + stream.close(); + listener.close(); + } + } do spawn_immediately { let io = unsafe { local_sched::unsafe_borrow_io() }; let mut stream = io.connect(addr).unwrap(); let mut buf = [0, .. 2048]; let mut total_bytes_read = 0; - while total_bytes_read < 500000000 { + while total_bytes_read < MAX { let nread = stream.read(buf).unwrap(); rtdebug!("read %u bytes", nread as uint); total_bytes_read += nread; } - rtdebug_!("read %u bytes total", total_bytes_read as uint); + rtdebug!("read %u bytes total", total_bytes_read as uint); stream.close(); } } From 6e17202ff4a694a2cf96fd7d2ccb1d62265ce7c2 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 02:41:30 -0700 Subject: [PATCH 010/215] core::rt: Add `next_test_ip4` for generating test addresses --- src/libcore/rt/test.rs | 7 +++++++ src/libcore/rt/uv/net.rs | 6 +++--- src/libcore/rt/uvio.rs | 8 ++++---- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs index dfc058d6eba5c..585d43a3ade8b 100644 --- a/src/libcore/rt/test.rs +++ b/src/libcore/rt/test.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use super::io::net::ip::{IpAddr, Ipv4}; + // For setting up tests of the new scheduler pub fn run_in_newsched_task(f: ~fn()) { use cell::Cell; @@ -53,3 +55,8 @@ pub fn next_test_port() -> u16 { fn rust_dbg_next_port() -> ::libc::uintptr_t; } } + +/// Get a unique localhost:port pair starting at 9600 +pub fn next_test_ip4() -> IpAddr { + Ipv4(127, 0, 0, 1, next_test_port()) +} diff --git a/src/libcore/rt/uv/net.rs b/src/libcore/rt/uv/net.rs index 54823d4dbcf61..860c988b9c990 100644 --- a/src/libcore/rt/uv/net.rs +++ b/src/libcore/rt/uv/net.rs @@ -22,7 +22,7 @@ use super::super::io::net::ip::{IpAddr, Ipv4, Ipv6}; #[cfg(test)] use cell::Cell; #[cfg(test)] use unstable::run_in_bare_thread; #[cfg(test)] use super::super::thread::Thread; -#[cfg(test)] use super::super::test::next_test_port; +#[cfg(test)] use super::super::test::*; fn ip4_as_uv_ip4(addr: IpAddr, f: &fn(*sockaddr_in)) { match addr { @@ -359,7 +359,7 @@ fn connect_close() { let mut loop_ = Loop::new(); let mut tcp_watcher = { TcpWatcher::new(&mut loop_) }; // Connect to a port where nobody is listening - let addr = Ipv4(127, 0, 0, 1, next_test_port()); + let addr = next_test_ip4(); do tcp_watcher.connect(addr) |stream_watcher, status| { rtdebug!("tcp_watcher.connect!"); assert!(status.is_some()); @@ -377,7 +377,7 @@ fn listen() { static MAX: int = 10; let mut loop_ = Loop::new(); let mut server_tcp_watcher = { TcpWatcher::new(&mut loop_) }; - let addr = Ipv4(127, 0, 0, 1, next_test_port()); + let addr = next_test_ip4(); server_tcp_watcher.bind(addr); let loop_ = loop_; rtdebug!("listening"); diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index 2582ddf310510..92439a41b342b 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -338,7 +338,7 @@ impl Stream for UvStream { fn test_simple_io_no_connect() { do run_in_newsched_task { let io = unsafe { local_sched::unsafe_borrow_io() }; - let addr = Ipv4(127, 0, 0, 1, next_test_port()); + let addr = next_test_ip4(); let maybe_chan = io.connect(addr); assert!(maybe_chan.is_none()); } @@ -347,7 +347,7 @@ fn test_simple_io_no_connect() { #[test] fn test_simple_tcp_server_and_client() { do run_in_newsched_task { - let addr = Ipv4(127, 0, 0, 1, next_test_port()); + let addr = next_test_ip4(); // Start the server first so it's listening when we connect do spawn_immediately { @@ -381,7 +381,7 @@ fn test_simple_tcp_server_and_client() { #[test] #[ignore(reason = "busted")] fn test_read_and_block() { do run_in_newsched_task { - let addr = Ipv4(127, 0, 0, 1, next_test_port()); + let addr = next_test_ip4(); do spawn_immediately { let io = unsafe { local_sched::unsafe_borrow_io() }; @@ -437,7 +437,7 @@ fn test_read_and_block() { #[test] fn test_read_read_read() { do run_in_newsched_task { - let addr = Ipv4(127, 0, 0, 1, next_test_port()); + let addr = next_test_ip4(); static MAX: uint = 5000000; do spawn_immediately { From bcb3cfb8ce8353ef91b8b7acc0d6339c809d9a29 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 15:55:07 -0700 Subject: [PATCH 011/215] core::rt: Improve docs for run_in_newsched_task testing function --- src/libcore/rt/test.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs index 585d43a3ade8b..e394a873feac6 100644 --- a/src/libcore/rt/test.rs +++ b/src/libcore/rt/test.rs @@ -10,7 +10,8 @@ use super::io::net::ip::{IpAddr, Ipv4}; -// For setting up tests of the new scheduler +/// Creates a new scheduler in a new thread and runs a task in it, +/// then waits for the scheduler to exit. pub fn run_in_newsched_task(f: ~fn()) { use cell::Cell; use unstable::run_in_bare_thread; From d818ea81549a2ce12ba7b722997567f45417f099 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 15:55:37 -0700 Subject: [PATCH 012/215] core::rt: Listener constructors are called and return a --- src/libcore/rt/io/net/tcp.rs | 29 ++++++++++++++++++++++++++++- src/libcore/rt/io/net/udp.rs | 2 +- src/libcore/rt/io/net/unix.rs | 2 +- 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/libcore/rt/io/net/tcp.rs b/src/libcore/rt/io/net/tcp.rs index e3f71dca8c827..d78241b8e446e 100644 --- a/src/libcore/rt/io/net/tcp.rs +++ b/src/libcore/rt/io/net/tcp.rs @@ -40,7 +40,7 @@ impl Close for TcpStream { pub struct TcpListener; impl TcpListener { - pub fn new(_addr: IpAddr) -> TcpListener { + pub fn bind(_addr: IpAddr) -> Result { fail!() } } @@ -48,3 +48,30 @@ impl TcpListener { impl Listener for TcpListener { fn accept(&mut self) -> Option { fail!() } } + +#[cfg(test)] +mod test { + use super::*; + use rt::test::*; + + #[test] #[ignore] + fn smoke_test() { + /*do run_in_newsched_task { + let addr = next_test_ip4(); + + do spawn_immediately { + let listener = TcpListener::bind(addr); + do listener.accept() { + let mut buf = [0]; + listener.read(buf); + assert!(buf[0] == 99); + } + } + + do spawn_immediately { + let stream = TcpStream::connect(addr); + stream.write([99]); + } + }*/ + } +} diff --git a/src/libcore/rt/io/net/udp.rs b/src/libcore/rt/io/net/udp.rs index f76bb58a45eb9..81a6677c14afa 100644 --- a/src/libcore/rt/io/net/udp.rs +++ b/src/libcore/rt/io/net/udp.rs @@ -40,7 +40,7 @@ impl Close for UdpStream { pub struct UdpListener; impl UdpListener { - pub fn new(_addr: IpAddr) -> UdpListener { + pub fn bind(_addr: IpAddr) -> Result { fail!() } } diff --git a/src/libcore/rt/io/net/unix.rs b/src/libcore/rt/io/net/unix.rs index de886949e7b0d..a5f4f8e3ba8b4 100644 --- a/src/libcore/rt/io/net/unix.rs +++ b/src/libcore/rt/io/net/unix.rs @@ -40,7 +40,7 @@ impl Close for UnixStream { pub struct UnixListener; impl UnixListener { - pub fn new(_path: &P) -> UnixListener { + pub fn bind(_path: &P) -> Result { fail!() } } From 00474c13f32db8903e0c9ea4ab6186007a79e77c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 16:15:06 -0700 Subject: [PATCH 013/215] core: Ignore two long-running tests --- src/libcore/run.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 8b18cc3c6968c..96f88e6368080 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -598,12 +598,14 @@ mod tests { #[test] #[cfg(unix)] + #[ignore(reason = "long run time")] fn test_unforced_destroy_actually_kills() { test_destroy_actually_kills(false); } #[test] #[cfg(unix)] + #[ignore(reason = "long run time")] fn test_forced_destroy_actually_kills() { test_destroy_actually_kills(true); } From fa478f577565174327888ea768dfa3a1018416f2 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 16:15:32 -0700 Subject: [PATCH 014/215] core: Speed up a test case --- src/libcore/rt/uvio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index 92439a41b342b..2e9d0afa52fe5 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -438,7 +438,7 @@ fn test_read_and_block() { fn test_read_read_read() { do run_in_newsched_task { let addr = next_test_ip4(); - static MAX: uint = 5000000; + static MAX: uint = 500000; do spawn_immediately { unsafe { From 4eff3130c589b5fb256c537e90272646fd8406ab Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 20 Apr 2013 17:25:00 -0700 Subject: [PATCH 015/215] core::rt:: Implement Reader/Writer for MemReader/MemWriter --- src/libcore/rt/io/mem.rs | 69 ++++++++++++++++++++++++++++++++++++---- src/libcore/rt/io/mod.rs | 8 +++++ 2 files changed, 70 insertions(+), 7 deletions(-) diff --git a/src/libcore/rt/io/mem.rs b/src/libcore/rt/io/mem.rs index 600968a3c7105..06e1466831df0 100644 --- a/src/libcore/rt/io/mem.rs +++ b/src/libcore/rt/io/mem.rs @@ -17,7 +17,7 @@ use prelude::*; use super::*; - +use cmp::min; /// Writes to an owned, growable byte vector pub struct MemWriter { @@ -29,13 +29,15 @@ impl MemWriter { } impl Writer for MemWriter { - fn write(&mut self, _buf: &[u8]) { fail!() } + fn write(&mut self, buf: &[u8]) { + self.buf.push_all(buf) + } fn flush(&mut self) { /* no-op */ } } impl Seek for MemWriter { - fn tell(&self) -> u64 { fail!() } + fn tell(&self) -> u64 { self.buf.len() as u64 } fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } } @@ -77,13 +79,27 @@ impl MemReader { } impl Reader for MemReader { - fn read(&mut self, _buf: &mut [u8]) -> Option { fail!() } + fn read(&mut self, buf: &mut [u8]) -> Option { + { if self.eof() { return None; } } + + let write_len = min(buf.len(), self.buf.len() - self.pos); + { + let input = self.buf.slice(self.pos, self.pos + write_len); + let output = vec::mut_slice(buf, 0, write_len); + assert!(input.len() == output.len()); + vec::bytes::copy_memory(output, input, write_len); + } + self.pos += write_len; + assert!(self.pos <= self.buf.len()); - fn eof(&mut self) -> bool { fail!() } + return Some(write_len); + } + + fn eof(&mut self) -> bool { self.pos == self.buf.len() } } impl Seek for MemReader { - fn tell(&self) -> u64 { fail!() } + fn tell(&self) -> u64 { self.pos as u64 } fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } } @@ -163,4 +179,43 @@ impl<'self> Seek for BufReader<'self> { fn tell(&self) -> u64 { fail!() } fn seek(&mut self, _pos: i64, _style: SeekStyle) { fail!() } -} \ No newline at end of file +} + +#[cfg(test)] +mod test { + use prelude::*; + use super::*; + + #[test] + fn test_mem_writer() { + let mut writer = MemWriter::new(); + assert!(writer.tell() == 0); + writer.write([0]); + assert!(writer.tell() == 1); + writer.write([1, 2, 3]); + writer.write([4, 5, 6, 7]); + assert!(writer.tell() == 8); + assert!(writer.inner() == ~[0, 1, 2, 3, 4, 5 , 6, 7]); + } + + #[test] + fn test_mem_reader() { + let mut reader = MemReader::new(~[0, 1, 2, 3, 4, 5, 6, 7]); + let mut buf = []; + assert!(reader.read(buf) == Some(0)); + assert!(reader.tell() == 0); + let mut buf = [0]; + assert!(reader.read(buf) == Some(1)); + assert!(reader.tell() == 1); + assert!(buf == [0]); + let mut buf = [0, ..4]; + assert!(reader.read(buf) == Some(4)); + assert!(reader.tell() == 5); + assert!(buf == [1, 2, 3, 4]); + assert!(reader.read(buf) == Some(3)); + assert!(buf.slice(0, 3) == [5, 6, 7]); + assert!(reader.eof()); + assert!(reader.read(buf) == None); + assert!(reader.eof()); + } +} diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs index c04389e029060..238bd97a62d17 100644 --- a/src/libcore/rt/io/mod.rs +++ b/src/libcore/rt/io/mod.rs @@ -269,6 +269,14 @@ pub enum SeekStyle { /// * Are `u64` and `i64` the right choices? pub trait Seek { fn tell(&self) -> u64; + + /// Seek to an offset in a stream + /// + /// A successful seek clears the EOF indicator. + /// + /// # XXX + /// + /// * What is the behavior when seeking past the end of a stream? fn seek(&mut self, pos: i64, style: SeekStyle); } From f9069baa70ea78117f2087fe6e359fb2ea0ae16a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 21 Apr 2013 16:28:17 -0700 Subject: [PATCH 016/215] core::rt: Add LocalServices for thread-local language services Things like the GC heap and unwinding are desirable everywhere the language might be used, not just in tasks. All Rust code should have access to LocalServices. --- src/libcore/rt/local_services.rs | 63 ++++++++++++++++++++++++++++++++ src/libcore/rt/mod.rs | 3 +- src/libcore/rt/sched/mod.rs | 6 ++- 3 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 src/libcore/rt/local_services.rs diff --git a/src/libcore/rt/local_services.rs b/src/libcore/rt/local_services.rs new file mode 100644 index 0000000000000..8e386f80b77d7 --- /dev/null +++ b/src/libcore/rt/local_services.rs @@ -0,0 +1,63 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Language-level runtime services that should reasonably expected +//! to be available 'everywhere'. Local heaps, GC, unwinding, +//! local storage, and logging. Even a 'freestanding' Rust would likely want +//! to implement this. + +//! Local services may exist in at least three different contexts: +//! when running as a task, when running in the scheduler's context, +//! or when running outside of a scheduler but with local services +//! (freestanding rust with local services?). + +use prelude::*; +use super::sched::{Task, local_sched}; + +pub struct LocalServices { + heap: LocalHeap, + gc: GarbageCollector, + storage: LocalStorage, + logger: Logger, + unwinder: Unwinder +} + +pub struct LocalHeap; +pub struct GarbageCollector; +pub struct LocalStorage; +pub struct Logger; +pub struct Unwinder; + +impl LocalServices { + pub fn new() -> LocalServices { + LocalServices { + heap: LocalHeap, + gc: GarbageCollector, + storage: LocalStorage, + logger: Logger, + unwinder: Unwinder + } + } +} + +/// Borrow a pointer to the installed local services. +/// Fails (likely aborting the process) if local services are not available. +pub fn borrow_local_services(f: &fn(&mut LocalServices)) { + do local_sched::borrow |sched| { + match sched.current_task { + Some(~ref mut task) => { + f(&mut task.local_services) + } + None => { + fail!(~"no local services for schedulers yet") + } + } + } +} diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs index cf896dd18f34c..e0190418b132b 100644 --- a/src/libcore/rt/mod.rs +++ b/src/libcore/rt/mod.rs @@ -48,6 +48,7 @@ mod stack; mod context; mod thread; pub mod env; +pub mod local_services; /// Tools for testing the runtime #[cfg(test)] @@ -97,7 +98,7 @@ pub fn start(main: *u8, _argc: int, _argv: **c_char, _crate_map: *u8) -> int { /// Different runtime services are available depending on context. #[deriving(Eq)] pub enum RuntimeContext { - // Only default services, e.g. exchange heap + // Only the exchange heap is available GlobalContext, // The scheduler may be accessed SchedulerContext, diff --git a/src/libcore/rt/sched/mod.rs b/src/libcore/rt/sched/mod.rs index 28946281628b1..30136e443ee39 100644 --- a/src/libcore/rt/sched/mod.rs +++ b/src/libcore/rt/sched/mod.rs @@ -16,6 +16,7 @@ use super::work_queue::WorkQueue; use super::stack::{StackPool, StackSegment}; use super::rtio::{EventLoop, EventLoopObject}; use super::context::Context; +use super::local_services::LocalServices; use cell::Cell; #[cfg(test)] use super::uvio::UvEventLoop; @@ -38,7 +39,7 @@ pub struct Scheduler { /// Always valid when a task is executing, otherwise not priv saved_context: Context, /// The currently executing task - priv current_task: Option<~Task>, + current_task: Option<~Task>, /// An action performed after a context switch on behalf of the /// code running before the context switch priv cleanup_job: Option @@ -326,6 +327,8 @@ pub struct Task { /// These are always valid when the task is not running, unless /// the task is dead priv saved_context: Context, + /// The heap, GC, unwinding, local storage, logging + local_services: LocalServices } pub impl Task { @@ -337,6 +340,7 @@ pub impl Task { return Task { current_stack_segment: stack, saved_context: initial_context, + local_services: LocalServices::new() }; } From 2fe118b26fdb2897eb000ae47f912cc6b2534324 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 21 Apr 2013 17:42:45 -0700 Subject: [PATCH 017/215] rt: Don't make memory_region depend on rust_env I am going to use memory_region and boxed_region as the local heap in the new scheduler, for now at least, and I don't have a rust_env available. --- src/rt/boxed_region.cpp | 2 +- src/rt/boxed_region.h | 6 +++--- src/rt/memory_region.cpp | 15 +++++++++------ src/rt/memory_region.h | 5 +++-- src/rt/rust_sched_loop.cpp | 2 +- src/rt/rust_task.cpp | 2 +- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/src/rt/boxed_region.cpp b/src/rt/boxed_region.cpp index d159df03dc3c0..e8ddb53148c1a 100644 --- a/src/rt/boxed_region.cpp +++ b/src/rt/boxed_region.cpp @@ -82,7 +82,7 @@ void boxed_region::free(rust_opaque_box *box) { if (box->next) box->next->prev = box->prev; if (live_allocs == box) live_allocs = box->next; - if (env->poison_on_free) { + if (poison_on_free) { memset(box_body(box), 0xab, box->td->size); } diff --git a/src/rt/boxed_region.h b/src/rt/boxed_region.h index 4097b6d41b756..178772007e518 100644 --- a/src/rt/boxed_region.h +++ b/src/rt/boxed_region.h @@ -24,7 +24,7 @@ struct rust_env; * a type descr which describes the payload (what follows the header). */ class boxed_region { private: - rust_env *env; + bool poison_on_free; memory_region *backing_region; rust_opaque_box *live_allocs; @@ -41,8 +41,8 @@ class boxed_region { boxed_region& operator=(const boxed_region& rhs); public: - boxed_region(rust_env *e, memory_region *br) - : env(e) + boxed_region(memory_region *br, bool poison_on_free) + : poison_on_free(poison_on_free) , backing_region(br) , live_allocs(NULL) {} diff --git a/src/rt/memory_region.cpp b/src/rt/memory_region.cpp index 6de9d5a1df4a2..f3406712cb012 100644 --- a/src/rt/memory_region.cpp +++ b/src/rt/memory_region.cpp @@ -11,7 +11,6 @@ #include "sync/sync.h" #include "memory_region.h" -#include "rust_env.h" #if RUSTRT_TRACK_ALLOCATIONS >= 3 #include @@ -35,15 +34,19 @@ void *memory_region::get_data(alloc_header *ptr) { return (void*)((char *)ptr + HEADER_SIZE); } -memory_region::memory_region(rust_env *env, bool synchronized) : - _env(env), _parent(NULL), _live_allocations(0), - _detailed_leaks(env->detailed_leaks), +memory_region::memory_region(bool synchronized, + bool detailed_leaks, + bool poison_on_free) : + _parent(NULL), _live_allocations(0), + _detailed_leaks(detailed_leaks), + _poison_on_free(poison_on_free), _synchronized(synchronized) { } memory_region::memory_region(memory_region *parent) : - _env(parent->_env), _parent(parent), _live_allocations(0), + _parent(parent), _live_allocations(0), _detailed_leaks(parent->_detailed_leaks), + _poison_on_free(parent->_poison_on_free), _synchronized(parent->_synchronized) { } @@ -241,7 +244,7 @@ memory_region::claim_alloc(void *mem) { void memory_region::maybe_poison(void *mem) { - if (!_env->poison_on_free) + if (!_poison_on_free) return; # if RUSTRT_TRACK_ALLOCATIONS >= 1 diff --git a/src/rt/memory_region.h b/src/rt/memory_region.h index 999a992eefaea..4ad57c11809cc 100644 --- a/src/rt/memory_region.h +++ b/src/rt/memory_region.h @@ -54,11 +54,11 @@ class memory_region { inline alloc_header *get_header(void *mem); inline void *get_data(alloc_header *); - rust_env *_env; memory_region *_parent; int _live_allocations; array_list _allocation_list; const bool _detailed_leaks; + const bool _poison_on_free; const bool _synchronized; lock_and_signal _lock; @@ -75,7 +75,8 @@ class memory_region { memory_region& operator=(const memory_region& rhs); public: - memory_region(rust_env *env, bool synchronized); + memory_region(bool synchronized, + bool detailed_leaks, bool poison_on_free); memory_region(memory_region *parent); void *malloc(size_t size, const char *tag); void *realloc(void *mem, size_t size); diff --git a/src/rt/rust_sched_loop.cpp b/src/rt/rust_sched_loop.cpp index 90393acdd59d6..e7ce4b08ee46a 100644 --- a/src/rt/rust_sched_loop.cpp +++ b/src/rt/rust_sched_loop.cpp @@ -36,7 +36,7 @@ rust_sched_loop::rust_sched_loop(rust_scheduler *sched, int id, bool killed) : sched(sched), log_lvl(log_debug), min_stack_size(kernel->env->min_stack_size), - local_region(kernel->env, false), + local_region(false, kernel->env->detailed_leaks, kernel->env->poison_on_free), // FIXME #2891: calculate a per-scheduler name. name("main") { diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index 63dc1c9833e21..4680f32c19a84 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -36,7 +36,7 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state, kernel(sched_loop->kernel), name(name), list_index(-1), - boxed(sched_loop->kernel->env, &local_region), + boxed(&local_region, sched_loop->kernel->env->poison_on_free), local_region(&sched_loop->local_region), unwinding(false), total_stack_sz(0), From d7f5e437a28dd85b8a7523af9212a9a1100ea725 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 21 Apr 2013 19:03:52 -0700 Subject: [PATCH 018/215] core::rt: Add the local heap to newsched tasks Reusing the existing boxed_region implementation from the runtime --- src/libcore/rt/local_heap.rs | 81 ++++++++++++++++++++++++++++++++ src/libcore/rt/local_services.rs | 19 +++++++- src/libcore/rt/mod.rs | 1 + src/libcore/unstable/lang.rs | 26 +++++++++- src/rt/boxed_region.cpp | 12 ++--- src/rt/rust_builtin.cpp | 35 ++++++++++++++ src/rt/rustrt.def.in | 6 +++ 7 files changed, 170 insertions(+), 10 deletions(-) create mode 100644 src/libcore/rt/local_heap.rs diff --git a/src/libcore/rt/local_heap.rs b/src/libcore/rt/local_heap.rs new file mode 100644 index 0000000000000..fbd4a77d79b98 --- /dev/null +++ b/src/libcore/rt/local_heap.rs @@ -0,0 +1,81 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The local, garbage collected heap + +use libc::{c_void, uintptr_t, size_t}; +use ops::Drop; + +type MemoryRegion = c_void; +type BoxedRegion = c_void; + +pub type OpaqueBox = c_void; +pub type TypeDesc = c_void; + +pub struct LocalHeap { + memory_region: *MemoryRegion, + boxed_region: *BoxedRegion +} + +impl LocalHeap { + pub fn new() -> LocalHeap { + unsafe { + // Don't need synchronization for the single-threaded local heap + let synchronized = false as uintptr_t; + // XXX: These usually come from the environment + let detailed_leaks = false as uintptr_t; + let poison_on_free = false as uintptr_t; + let region = rust_new_memory_region(synchronized, detailed_leaks, poison_on_free); + assert!(region.is_not_null()); + let boxed = rust_new_boxed_region(region, poison_on_free); + assert!(boxed.is_not_null()); + LocalHeap { + memory_region: region, + boxed_region: boxed + } + } + } + + pub fn alloc(&mut self, td: *TypeDesc, size: uint) -> *OpaqueBox { + unsafe { + return rust_boxed_region_malloc(self.boxed_region, td, size as size_t); + } + } + + pub fn free(&mut self, box: *OpaqueBox) { + unsafe { + return rust_boxed_region_free(self.boxed_region, box); + } + } +} + +impl Drop for LocalHeap { + fn finalize(&self) { + unsafe { + rust_delete_boxed_region(self.boxed_region); + rust_delete_memory_region(self.memory_region); + } + } +} + +extern { + fn rust_new_memory_region(synchronized: uintptr_t, + detailed_leaks: uintptr_t, + poison_on_free: uintptr_t) -> *MemoryRegion; + fn rust_delete_memory_region(region: *MemoryRegion); + fn rust_new_boxed_region(region: *MemoryRegion, + poison_on_free: uintptr_t) -> *BoxedRegion; + fn rust_delete_boxed_region(region: *BoxedRegion); + fn rust_boxed_region_malloc(region: *BoxedRegion, + td: *TypeDesc, + size: size_t) -> *OpaqueBox; + fn rust_boxed_region_free(region: *BoxedRegion, box: *OpaqueBox); +} + diff --git a/src/libcore/rt/local_services.rs b/src/libcore/rt/local_services.rs index 8e386f80b77d7..b9d99283e14f2 100644 --- a/src/libcore/rt/local_services.rs +++ b/src/libcore/rt/local_services.rs @@ -20,6 +20,7 @@ use prelude::*; use super::sched::{Task, local_sched}; +use super::local_heap::LocalHeap; pub struct LocalServices { heap: LocalHeap, @@ -29,7 +30,6 @@ pub struct LocalServices { unwinder: Unwinder } -pub struct LocalHeap; pub struct GarbageCollector; pub struct LocalStorage; pub struct Logger; @@ -38,7 +38,7 @@ pub struct Unwinder; impl LocalServices { pub fn new() -> LocalServices { LocalServices { - heap: LocalHeap, + heap: LocalHeap::new(), gc: GarbageCollector, storage: LocalStorage, logger: Logger, @@ -61,3 +61,18 @@ pub fn borrow_local_services(f: &fn(&mut LocalServices)) { } } } + +#[cfg(test)] +mod test { + use rt::test::*; + + #[test] + fn local_heap() { + do run_in_newsched_task() { + let a = @5; + let b = a; + assert!(*a == 5); + assert!(*b == 5); + } + } +} \ No newline at end of file diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs index e0190418b132b..4a767d61f7444 100644 --- a/src/libcore/rt/mod.rs +++ b/src/libcore/rt/mod.rs @@ -49,6 +49,7 @@ mod context; mod thread; pub mod env; pub mod local_services; +mod local_heap; /// Tools for testing the runtime #[cfg(test)] diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index be776a39742f0..0bf1ad36a1faf 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -17,6 +17,8 @@ use str; use sys; use unstable::exchange_alloc; use cast::transmute; +use rt::{context, OldTaskContext}; +use rt::local_services::borrow_local_services; #[allow(non_camel_case_types)] pub type rust_task = c_void; @@ -81,7 +83,18 @@ pub unsafe fn exchange_free(ptr: *c_char) { #[lang="malloc"] #[inline(always)] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { - return rustrt::rust_upcall_malloc(td, size); + match context() { + OldTaskContext => { + return rustrt::rust_upcall_malloc(td, size); + } + _ => { + let mut alloc = ::ptr::null(); + do borrow_local_services |srv| { + alloc = srv.heap.alloc(td as *c_void, size as uint) as *c_char; + } + return alloc; + } + } } // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from @@ -90,7 +103,16 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { #[lang="free"] #[inline(always)] pub unsafe fn local_free(ptr: *c_char) { - rustrt::rust_upcall_free(ptr); + match context() { + OldTaskContext => { + rustrt::rust_upcall_free(ptr); + } + _ => { + do borrow_local_services |srv| { + srv.heap.free(ptr as *c_void); + } + } + } } #[lang="borrow_as_imm"] diff --git a/src/rt/boxed_region.cpp b/src/rt/boxed_region.cpp index e8ddb53148c1a..a49b52bffe153 100644 --- a/src/rt/boxed_region.cpp +++ b/src/rt/boxed_region.cpp @@ -27,11 +27,11 @@ rust_opaque_box *boxed_region::malloc(type_desc *td, size_t body_size) { if (live_allocs) live_allocs->prev = box; live_allocs = box; - LOG(rust_get_current_task(), box, + /*LOG(rust_get_current_task(), box, "@malloc()=%p with td %p, size %lu==%lu+%lu, " "align %lu, prev %p, next %p\n", box, td, total_size, sizeof(rust_opaque_box), body_size, - td->align, box->prev, box->next); + td->align, box->prev, box->next);*/ return box; } @@ -50,9 +50,9 @@ rust_opaque_box *boxed_region::realloc(rust_opaque_box *box, if (new_box->next) new_box->next->prev = new_box; if (live_allocs == box) live_allocs = new_box; - LOG(rust_get_current_task(), box, + /*LOG(rust_get_current_task(), box, "@realloc()=%p with orig=%p, size %lu==%lu+%lu", - new_box, box, total_size, sizeof(rust_opaque_box), new_size); + new_box, box, total_size, sizeof(rust_opaque_box), new_size);*/ return new_box; } @@ -74,9 +74,9 @@ void boxed_region::free(rust_opaque_box *box) { // double frees (kind of). assert(box->td != NULL); - LOG(rust_get_current_task(), box, + /*LOG(rust_get_current_task(), box, "@free(%p) with td %p, prev %p, next %p\n", - box, box->td, box->prev, box->next); + box, box->td, box->prev, box->next);*/ if (box->prev) box->prev->next = box->next; if (box->next) box->next->prev = box->prev; diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index a0db6f64f69fc..b8749b8f73d81 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -851,6 +851,41 @@ rust_initialize_global_state() { } } +extern "C" CDECL memory_region* +rust_new_memory_region(uintptr_t synchronized, + uintptr_t detailed_leaks, + uintptr_t poison_on_free) { + return new memory_region((bool)synchronized, + (bool)detailed_leaks, + (bool)poison_on_free); +} + +extern "C" CDECL void +rust_delete_memory_region(memory_region *region) { + delete region; +} + +extern "C" CDECL boxed_region* +rust_new_boxed_region(memory_region *region, + uintptr_t poison_on_free) { + return new boxed_region(region, poison_on_free); +} + +extern "C" CDECL void +rust_delete_boxed_region(boxed_region *region) { + delete region; +} + +extern "C" CDECL rust_opaque_box* +rust_boxed_region_malloc(boxed_region *region, type_desc *td, size_t size) { + return region->malloc(td, size); +} + +extern "C" CDECL void +rust_boxed_region_free(boxed_region *region, rust_opaque_box *box) { + region->free(box); +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index f84a73a394b6c..9aa8015678360 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -222,3 +222,9 @@ rust_uv_free_ip6_addr rust_call_nullary_fn rust_initialize_global_state rust_dbg_next_port +rust_new_memory_region +rust_delete_memory_region +rust_new_boxed_region +rust_delete_boxed_region +rust_boxed_region_malloc +rust_boxed_region_free From d0786fdffcbae5c89762455fd3b3ffb5b9a3b6a1 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 22 Apr 2013 12:54:03 -0700 Subject: [PATCH 019/215] core::rt Wire up task-local storage to the new scheduler --- src/libcore/rt/local_services.rs | 58 +++++++++++++++++-- src/libcore/rt/sched/mod.rs | 7 +++ src/libcore/task/local_data.rs | 10 ++-- src/libcore/task/local_data_priv.rs | 87 ++++++++++++++++++++++++----- src/libcore/task/spawn.rs | 8 +-- 5 files changed, 144 insertions(+), 26 deletions(-) diff --git a/src/libcore/rt/local_services.rs b/src/libcore/rt/local_services.rs index b9d99283e14f2..d29e57a17af15 100644 --- a/src/libcore/rt/local_services.rs +++ b/src/libcore/rt/local_services.rs @@ -19,6 +19,7 @@ //! (freestanding rust with local services?). use prelude::*; +use libc::c_void; use super::sched::{Task, local_sched}; use super::local_heap::LocalHeap; @@ -27,11 +28,12 @@ pub struct LocalServices { gc: GarbageCollector, storage: LocalStorage, logger: Logger, - unwinder: Unwinder + unwinder: Unwinder, + destroyed: bool } pub struct GarbageCollector; -pub struct LocalStorage; +pub struct LocalStorage(*c_void, Option<~fn(*c_void)>); pub struct Logger; pub struct Unwinder; @@ -40,11 +42,34 @@ impl LocalServices { LocalServices { heap: LocalHeap::new(), gc: GarbageCollector, - storage: LocalStorage, + storage: LocalStorage(ptr::null(), None), logger: Logger, - unwinder: Unwinder + unwinder: Unwinder, + destroyed: false } } + + /// Must be called manually before finalization to clean up + /// thread-local resources. Some of the routines here expect + /// LocalServices to be available recursively so this must be + /// called unsafely, without removing LocalServices from + /// thread-local-storage. + pub fn destroy(&mut self) { + // This is just an assertion that `destroy` was called unsafely + // and this instance of LocalServices is still accessible. + do borrow_local_services |sched| { + assert!(ptr::ref_eq(sched, self)); + } + match self.storage { + LocalStorage(ptr, Some(ref dtor)) => (*dtor)(ptr), + _ => () + } + self.destroyed = true; + } +} + +impl Drop for LocalServices { + fn finalize(&self) { assert!(self.destroyed) } } /// Borrow a pointer to the installed local services. @@ -62,6 +87,19 @@ pub fn borrow_local_services(f: &fn(&mut LocalServices)) { } } +pub unsafe fn unsafe_borrow_local_services() -> &mut LocalServices { + use cast::transmute_mut_region; + + match local_sched::unsafe_borrow().current_task { + Some(~ref mut task) => { + transmute_mut_region(&mut task.local_services) + } + None => { + fail!(~"no local services for schedulers yet") + } + } +} + #[cfg(test)] mod test { use rt::test::*; @@ -75,4 +113,16 @@ mod test { assert!(*b == 5); } } + + #[test] + fn tls() { + use task::local_data::*; + do run_in_newsched_task() { + unsafe { + fn key(_x: @~str) { } + local_data_set(key, @~"data"); + assert!(*local_data_get(key).get() == ~"data"); + } + } + } } \ No newline at end of file diff --git a/src/libcore/rt/sched/mod.rs b/src/libcore/rt/sched/mod.rs index 30136e443ee39..b7d861b8946b8 100644 --- a/src/libcore/rt/sched/mod.rs +++ b/src/libcore/rt/sched/mod.rs @@ -357,6 +357,13 @@ pub impl Task { start(); + unsafe { + // Destroy the local heap, TLS, etc. + let sched = local_sched::unsafe_borrow(); + let task = sched.current_task.get_mut_ref(); + task.local_services.destroy(); + } + let sched = local_sched::take(); sched.terminate_current_task(); }; diff --git a/src/libcore/task/local_data.rs b/src/libcore/task/local_data.rs index 261671f6de9ae..6e919a74ed4f2 100644 --- a/src/libcore/task/local_data.rs +++ b/src/libcore/task/local_data.rs @@ -27,7 +27,7 @@ magic. */ use prelude::*; -use task::local_data_priv::{local_get, local_pop, local_modify, local_set}; +use task::local_data_priv::{local_get, local_pop, local_modify, local_set, Handle}; use task::rt; /** @@ -53,7 +53,7 @@ pub type LocalDataKey<'self,T> = &'self fn(v: @T); pub unsafe fn local_data_pop( key: LocalDataKey) -> Option<@T> { - local_pop(rt::rust_get_task(), key) + local_pop(Handle::new(), key) } /** * Retrieve a task-local data value. It will also be kept alive in the @@ -62,7 +62,7 @@ pub unsafe fn local_data_pop( pub unsafe fn local_data_get( key: LocalDataKey) -> Option<@T> { - local_get(rt::rust_get_task(), key) + local_get(Handle::new(), key) } /** * Store a value in task-local data. If this key already has a value, @@ -71,7 +71,7 @@ pub unsafe fn local_data_get( pub unsafe fn local_data_set( key: LocalDataKey, data: @T) { - local_set(rt::rust_get_task(), key, data) + local_set(Handle::new(), key, data) } /** * Modify a task-local data value. If the function returns 'None', the @@ -81,7 +81,7 @@ pub unsafe fn local_data_modify( key: LocalDataKey, modify_fn: &fn(Option<@T>) -> Option<@T>) { - local_modify(rt::rust_get_task(), key, modify_fn) + local_modify(Handle::new(), key, modify_fn) } #[test] diff --git a/src/libcore/task/local_data_priv.rs b/src/libcore/task/local_data_priv.rs index 43f5fa4654bc7..50e8286e738d2 100644 --- a/src/libcore/task/local_data_priv.rs +++ b/src/libcore/task/local_data_priv.rs @@ -18,6 +18,30 @@ use task::rt; use task::local_data::LocalDataKey; use super::rt::rust_task; +use rt::local_services::LocalStorage; + +pub enum Handle { + OldHandle(*rust_task), + NewHandle(*mut LocalStorage) +} + +impl Handle { + pub fn new() -> Handle { + use rt::{context, OldTaskContext}; + use rt::local_services::unsafe_borrow_local_services; + unsafe { + match context() { + OldTaskContext => { + OldHandle(rt::rust_get_task()) + } + _ => { + let local_services = unsafe_borrow_local_services(); + NewHandle(&mut local_services.storage) + } + } + } + } +} pub trait LocalData { } impl LocalData for @T { } @@ -39,7 +63,7 @@ type TaskLocalElement = (*libc::c_void, *libc::c_void, @LocalData); // Has to be a pointer at outermost layer; the foreign call returns void *. type TaskLocalMap = @mut ~[Option]; -extern fn cleanup_task_local_map(map_ptr: *libc::c_void) { +fn cleanup_task_local_map(map_ptr: *libc::c_void) { unsafe { assert!(!map_ptr.is_null()); // Get and keep the single reference that was created at the @@ -50,8 +74,19 @@ extern fn cleanup_task_local_map(map_ptr: *libc::c_void) { } // Gets the map from the runtime. Lazily initialises if not done so already. +unsafe fn get_local_map(handle: Handle) -> TaskLocalMap { + match handle { + OldHandle(task) => get_task_local_map(task), + NewHandle(local_storage) => get_newsched_local_map(local_storage) + } +} + unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { + extern fn cleanup_task_local_map_(map_ptr: *libc::c_void) { + cleanup_task_local_map(map_ptr); + } + // Relies on the runtime initialising the pointer to null. // Note: The map's box lives in TLS invisibly referenced once. Each time // we retrieve it for get/set, we make another reference, which get/set @@ -62,7 +97,7 @@ unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { // Use reinterpret_cast -- transmute would take map away from us also. rt::rust_set_task_local_data( task, cast::reinterpret_cast(&map)); - rt::rust_task_local_data_atexit(task, cleanup_task_local_map); + rt::rust_task_local_data_atexit(task, cleanup_task_local_map_); // Also need to reference it an extra time to keep it for now. let nonmut = cast::transmute::]>(map); @@ -77,6 +112,32 @@ unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { } } +unsafe fn get_newsched_local_map(local: *mut LocalStorage) -> TaskLocalMap { + match &mut *local { + &LocalStorage(map_ptr, Some(_)) => { + assert!(map_ptr.is_not_null()); + let map = cast::transmute(map_ptr); + let nonmut = cast::transmute::]>(map); + cast::bump_box_refcount(nonmut); + return map; + } + &LocalStorage(ref mut map_ptr, ref mut at_exit) => { + assert!((*map_ptr).is_null()); + let map: TaskLocalMap = @mut ~[]; + // Use reinterpret_cast -- transmute would take map away from us also. + *map_ptr = cast::reinterpret_cast(&map); + let at_exit_fn: ~fn(*libc::c_void) = |p|cleanup_task_local_map(p); + *at_exit = Some(at_exit_fn); + // Also need to reference it an extra time to keep it for now. + let nonmut = cast::transmute::]>(map); + cast::bump_box_refcount(nonmut); + return map; + } + } +} + unsafe fn key_to_key_value( key: LocalDataKey) -> *libc::c_void { @@ -106,10 +167,10 @@ unsafe fn local_data_lookup( } unsafe fn local_get_helper( - task: *rust_task, key: LocalDataKey, + handle: Handle, key: LocalDataKey, do_pop: bool) -> Option<@T> { - let map = get_task_local_map(task); + let map = get_local_map(handle); // Interpreturn our findings from the map do local_data_lookup(map, key).map |result| { // A reference count magically appears on 'data' out of thin air. It @@ -128,23 +189,23 @@ unsafe fn local_get_helper( pub unsafe fn local_pop( - task: *rust_task, + handle: Handle, key: LocalDataKey) -> Option<@T> { - local_get_helper(task, key, true) + local_get_helper(handle, key, true) } pub unsafe fn local_get( - task: *rust_task, + handle: Handle, key: LocalDataKey) -> Option<@T> { - local_get_helper(task, key, false) + local_get_helper(handle, key, false) } pub unsafe fn local_set( - task: *rust_task, key: LocalDataKey, data: @T) { + handle: Handle, key: LocalDataKey, data: @T) { - let map = get_task_local_map(task); + let map = get_local_map(handle); // Store key+data as *voids. Data is invisibly referenced once; key isn't. let keyval = key_to_key_value(key); // We keep the data in two forms: one as an unsafe pointer, so we can get @@ -174,12 +235,12 @@ pub unsafe fn local_set( } pub unsafe fn local_modify( - task: *rust_task, key: LocalDataKey, + handle: Handle, key: LocalDataKey, modify_fn: &fn(Option<@T>) -> Option<@T>) { // Could be more efficient by doing the lookup work, but this is easy. - let newdata = modify_fn(local_pop(task, key)); + let newdata = modify_fn(local_pop(handle, key)); if newdata.is_some() { - local_set(task, key, newdata.unwrap()); + local_set(handle, key, newdata.unwrap()); } } diff --git a/src/libcore/task/spawn.rs b/src/libcore/task/spawn.rs index 118c4cc23125b..1e3857dff9a95 100644 --- a/src/libcore/task/spawn.rs +++ b/src/libcore/task/spawn.rs @@ -80,7 +80,7 @@ use prelude::*; use unstable; use ptr; use hashmap::HashSet; -use task::local_data_priv::{local_get, local_set}; +use task::local_data_priv::{local_get, local_set, OldHandle}; use task::rt::rust_task; use task::rt; use task::{Failure, ManualThreads, PlatformThread, SchedOpts, SingleThreaded}; @@ -451,7 +451,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) /*##################################################################* * Step 1. Get spawner's taskgroup info. *##################################################################*/ - let spawner_group = match local_get(spawner, taskgroup_key!()) { + let spawner_group = match local_get(OldHandle(spawner), taskgroup_key!()) { None => { // Main task, doing first spawn ever. Lazily initialise here. let mut members = new_taskset(); @@ -463,7 +463,7 @@ fn gen_child_taskgroup(linked: bool, supervised: bool) // Main task/group has no ancestors, no notifier, etc. let group = @TCB(spawner, tasks, AncestorList(None), true, None); - local_set(spawner, taskgroup_key!(), group); + local_set(OldHandle(spawner), taskgroup_key!(), group); group } Some(group) => group @@ -627,7 +627,7 @@ fn spawn_raw_oldsched(opts: TaskOpts, f: ~fn()) { let group = @TCB(child, child_arc, ancestors, is_main, notifier); unsafe { - local_set(child, taskgroup_key!(), group); + local_set(OldHandle(child), taskgroup_key!(), group); } // Run the child's body. From e5d21b9ff1ea4160b728b62aeca110c0a563d9ee Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 22 Apr 2013 13:10:59 -0700 Subject: [PATCH 020/215] core::rt: Make I/O constructors return Option instead of Result For consistency, for all I/O calls, inspecting the error can be done with the io_error condition. --- src/libcore/rt/io/file.rs | 2 +- src/libcore/rt/io/net/tcp.rs | 4 ++-- src/libcore/rt/io/net/udp.rs | 4 ++-- src/libcore/rt/io/net/unix.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libcore/rt/io/file.rs b/src/libcore/rt/io/file.rs index 4e3e01a5eceb9..e4fe066a173f4 100644 --- a/src/libcore/rt/io/file.rs +++ b/src/libcore/rt/io/file.rs @@ -42,7 +42,7 @@ impl FileStream { pub fn open(_path: &P, _mode: FileMode, _access: FileAccess - ) -> Result { + ) -> Option { fail!() } } diff --git a/src/libcore/rt/io/net/tcp.rs b/src/libcore/rt/io/net/tcp.rs index d78241b8e446e..d726bae821c87 100644 --- a/src/libcore/rt/io/net/tcp.rs +++ b/src/libcore/rt/io/net/tcp.rs @@ -16,7 +16,7 @@ use super::ip::IpAddr; pub struct TcpStream; impl TcpStream { - pub fn connect(_addr: IpAddr) -> Result { + pub fn connect(_addr: IpAddr) -> Option { fail!() } } @@ -40,7 +40,7 @@ impl Close for TcpStream { pub struct TcpListener; impl TcpListener { - pub fn bind(_addr: IpAddr) -> Result { + pub fn bind(_addr: IpAddr) -> Option { fail!() } } diff --git a/src/libcore/rt/io/net/udp.rs b/src/libcore/rt/io/net/udp.rs index 81a6677c14afa..8691a697e8888 100644 --- a/src/libcore/rt/io/net/udp.rs +++ b/src/libcore/rt/io/net/udp.rs @@ -16,7 +16,7 @@ use super::ip::IpAddr; pub struct UdpStream; impl UdpStream { - pub fn connect(_addr: IpAddr) -> Result { + pub fn connect(_addr: IpAddr) -> Option { fail!() } } @@ -40,7 +40,7 @@ impl Close for UdpStream { pub struct UdpListener; impl UdpListener { - pub fn bind(_addr: IpAddr) -> Result { + pub fn bind(_addr: IpAddr) -> Option { fail!() } } diff --git a/src/libcore/rt/io/net/unix.rs b/src/libcore/rt/io/net/unix.rs index a5f4f8e3ba8b4..bb3db6ec0d502 100644 --- a/src/libcore/rt/io/net/unix.rs +++ b/src/libcore/rt/io/net/unix.rs @@ -16,7 +16,7 @@ use super::super::support::PathLike; pub struct UnixStream; impl UnixStream { - pub fn connect(_path: &P) -> Result { + pub fn connect(_path: &P) -> Option { fail!() } } @@ -40,7 +40,7 @@ impl Close for UnixStream { pub struct UnixListener; impl UnixListener { - pub fn bind(_path: &P) -> Result { + pub fn bind(_path: &P) -> Option { fail!() } } From 6644a034f0650c638eea8809a5f035ffaca0de88 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 22 Apr 2013 13:26:37 -0700 Subject: [PATCH 021/215] core::rt: Move the definition of Listener to rt::io --- src/libcore/rt/io/mod.rs | 24 +++++++++++++++++++++--- src/libcore/rt/io/net/mod.rs | 31 ------------------------------- 2 files changed, 21 insertions(+), 34 deletions(-) delete mode 100644 src/libcore/rt/io/net/mod.rs diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs index 238bd97a62d17..f1b248c6e1d71 100644 --- a/src/libcore/rt/io/mod.rs +++ b/src/libcore/rt/io/mod.rs @@ -122,7 +122,6 @@ pub use self::stdio::print; pub use self::stdio::println; pub use self::file::FileStream; -pub use self::net::Listener; pub use self::net::ip::IpAddr; pub use self::net::tcp::TcpListener; pub use self::net::tcp::TcpStream; @@ -137,8 +136,14 @@ pub use self::extensions::WriterByteConversions; pub mod file; /// Synchronous, non-blocking network I/O. -#[path = "net/mod.rs"] -pub mod net; +pub mod net { + pub mod tcp; + pub mod udp; + pub mod ip; + #[cfg(unix)] + pub mod unix; + pub mod http; +} /// Readers and Writers for memory buffers and strings. #[cfg(not(stage0))] // XXX Using unsnapshotted features @@ -280,6 +285,19 @@ pub trait Seek { fn seek(&mut self, pos: i64, style: SeekStyle); } +/// A listener is a value that listens for connections +pub trait Listener { + /// Wait for and accept an incoming connection + /// + /// Returns `None` on timeout. + /// + /// # Failure + /// + /// Raises `io_error` condition. If the condition is handled, + /// then `accept` returns `None`. + fn accept(&mut self) -> Option; +} + /// Common trait for decorator types. /// /// Provides accessors to get the inner, 'decorated' values. The I/O library diff --git a/src/libcore/rt/io/net/mod.rs b/src/libcore/rt/io/net/mod.rs deleted file mode 100644 index 130ff6b38fa82..0000000000000 --- a/src/libcore/rt/io/net/mod.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use prelude::*; - -pub mod tcp; -pub mod udp; -pub mod ip; -#[cfg(unix)] -pub mod unix; -pub mod http; - -/// A listener is a value that listens for connections -pub trait Listener { - /// Wait for and accept an incoming connection - /// - /// Returns `None` on timeout. - /// - /// # Failure - /// - /// Raises `io_error` condition. If the condition is handled, - /// then `accept` returns `None`. - fn accept(&mut self) -> Option; -} From fe13b865192028645b50c17d2cb1a6d44481f338 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 22 Apr 2013 14:43:02 -0700 Subject: [PATCH 022/215] Make conditions public. #6009 --- src/libcore/condition.rs | 21 +++++++++++++++++++++ src/libsyntax/ext/expand.rs | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/libcore/condition.rs b/src/libcore/condition.rs index dc6c80228dd74..c639239981cab 100644 --- a/src/libcore/condition.rs +++ b/src/libcore/condition.rs @@ -192,4 +192,25 @@ mod test { assert!(trapped); } + + // Issue #6009 + mod m { + condition! { + sadness: int -> int; + } + + mod n { + use super::sadness; + + #[test] + fn test_conditions_are_public() { + let mut trapped = false; + do sadness::cond.trap(|_| { + 0 + }).in { + sadness::cond.raise(0); + } + } + } + } } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 430402a8982fc..5c5817d480dc4 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -475,7 +475,7 @@ pub fn core_macros() -> ~str { { $c:ident: $in:ty -> $out:ty; } => { - mod $c { + pub mod $c { fn key(_x: @::core::condition::Handler<$in,$out>) { } pub static cond : From 5fbb0949a53a6ac51c6d9b187ef4c464e52ae536 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 22 Apr 2013 14:52:40 -0700 Subject: [PATCH 023/215] core::rt: Add implementations of Reader, Writer, and Listener for Option These will make it easier to write I/O code without worrying about errors --- src/libcore/rt/io/mod.rs | 24 +++++- src/libcore/rt/io/option.rs | 153 ++++++++++++++++++++++++++++++++++++ 2 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 src/libcore/rt/io/option.rs diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs index f1b248c6e1d71..d9d6622277f77 100644 --- a/src/libcore/rt/io/mod.rs +++ b/src/libcore/rt/io/mod.rs @@ -152,6 +152,9 @@ pub mod mem; /// Non-blocking access to stdin, stdout, stderr pub mod stdio; +/// Implementations for Option +mod option; + /// Basic stream compression. XXX: Belongs with other flate code #[cfg(not(stage0))] // XXX Using unsnapshotted features pub mod flate; @@ -194,12 +197,14 @@ pub struct IoError { detail: Option<~str> } +#[deriving(Eq)] pub enum IoErrorKind { FileNotFound, FilePermission, ConnectionFailed, Closed, - OtherIoError + OtherIoError, + PreviousIoError } // XXX: Can't put doc comments on macros @@ -232,9 +237,9 @@ pub trait Reader { /// println(reader.read_line()); /// } /// - /// # XXX + /// # Failue /// - /// What does this return if the Reader is in an error state? + /// Returns `true` on failure. fn eof(&mut self) -> bool; } @@ -323,3 +328,16 @@ pub trait Decorator { /// Take a mutable reference to the decorated value fn inner_mut_ref<'a>(&'a mut self) -> &'a mut T; } + +pub fn standard_error(kind: IoErrorKind) -> IoError { + match kind { + PreviousIoError => { + IoError { + kind: PreviousIoError, + desc: "Failing due to a previous I/O error", + detail: None + } + } + _ => fail!() + } +} diff --git a/src/libcore/rt/io/option.rs b/src/libcore/rt/io/option.rs new file mode 100644 index 0000000000000..95f8711cb5bd5 --- /dev/null +++ b/src/libcore/rt/io/option.rs @@ -0,0 +1,153 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Implementations of I/O traits for the Option type +//! +//! I/O constructors return option types to allow errors to be handled. +//! These implementations allow e.g. `Option` to be used +//! as a `Reader` without unwrapping the option first. +//! +//! # XXX Seek and Close + +use option::*; +use super::{Reader, Writer, Listener}; +use super::{standard_error, PreviousIoError, io_error, IoError}; + +fn prev_io_error() -> IoError { + standard_error(PreviousIoError) +} + +impl Writer for Option { + fn write(&mut self, buf: &[u8]) { + match *self { + Some(ref mut writer) => writer.write(buf), + None => io_error::cond.raise(prev_io_error()) + } + } + + fn flush(&mut self) { + match *self { + Some(ref mut writer) => writer.flush(), + None => io_error::cond.raise(prev_io_error()) + } + } +} + +impl Reader for Option { + fn read(&mut self, buf: &mut [u8]) -> Option { + match *self { + Some(ref mut reader) => reader.read(buf), + None => { + io_error::cond.raise(prev_io_error()); + None + } + } + } + + fn eof(&mut self) -> bool { + match *self { + Some(ref mut reader) => reader.eof(), + None => { + io_error::cond.raise(prev_io_error()); + true + } + } + } +} + +impl, S> Listener for Option { + fn accept(&mut self) -> Option { + match *self { + Some(ref mut listener) => listener.accept(), + None => { + io_error::cond.raise(prev_io_error()); + None + } + } + } +} + +#[cfg(test)] +mod test { + use option::*; + use super::super::mem::*; + use rt::test::*; + use super::super::{PreviousIoError, io_error}; + + #[test] + fn test_option_writer() { + do run_in_newsched_task { + let mut writer: Option = Some(MemWriter::new()); + writer.write([0, 1, 2]); + writer.flush(); + assert!(writer.unwrap().inner() == ~[0, 1, 2]); + } + } + + #[test] + fn test_option_writer_error() { + do run_in_newsched_task { + let mut writer: Option = None; + + let mut called = false; + do io_error::cond.trap(|err| { + assert!(err.kind == PreviousIoError); + called = true; + }).in { + writer.write([0, 0, 0]); + } + assert!(called); + + let mut called = false; + do io_error::cond.trap(|err| { + assert!(err.kind == PreviousIoError); + called = true; + }).in { + writer.flush(); + } + assert!(called); + } + } + + #[test] + fn test_option_reader() { + do run_in_newsched_task { + let mut reader: Option = Some(MemReader::new(~[0, 1, 2, 3])); + let mut buf = [0, 0]; + reader.read(buf); + assert!(buf == [0, 1]); + assert!(!reader.eof()); + } + } + + #[test] + fn test_option_reader_error() { + let mut reader: Option = None; + let mut buf = []; + + let mut called = false; + do io_error::cond.trap(|err| { + assert!(err.kind == PreviousIoError); + called = true; + }).in { + reader.read(buf); + } + assert!(called); + + let mut called = false; + do io_error::cond.trap(|err| { + assert!(err.kind == PreviousIoError); + called = true; + }).in { + assert!(reader.eof()); + } + assert!(called); + } +} From 42c0f88232847e97e6cf3578ef197d1942bba44d Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 22 Apr 2013 17:15:31 -0700 Subject: [PATCH 024/215] core::rt: Add unwinding to newsched tasks --- src/libcore/rt/io/mod.rs | 1 + src/libcore/rt/local_services.rs | 78 ++++++++++++++++++++++++++++++-- src/libcore/rt/sched/mod.rs | 7 +-- src/libcore/rt/test.rs | 41 +++++++++++++++++ src/libcore/sys.rs | 25 ++++++++-- src/libcore/task/mod.rs | 18 +++++++- src/rt/rust_builtin.cpp | 22 +++++++++ src/rt/rust_upcall.cpp | 16 +++++-- src/rt/rustrt.def.in | 2 + 9 files changed, 190 insertions(+), 20 deletions(-) diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs index d9d6622277f77..131743305bcce 100644 --- a/src/libcore/rt/io/mod.rs +++ b/src/libcore/rt/io/mod.rs @@ -153,6 +153,7 @@ pub mod mem; pub mod stdio; /// Implementations for Option +#[cfg(not(stage0))] // Requires condition! fixes mod option; /// Basic stream compression. XXX: Belongs with other flate code diff --git a/src/libcore/rt/local_services.rs b/src/libcore/rt/local_services.rs index d29e57a17af15..fc75a25642861 100644 --- a/src/libcore/rt/local_services.rs +++ b/src/libcore/rt/local_services.rs @@ -19,7 +19,8 @@ //! (freestanding rust with local services?). use prelude::*; -use libc::c_void; +use libc::{c_void, uintptr_t}; +use cast::transmute; use super::sched::{Task, local_sched}; use super::local_heap::LocalHeap; @@ -35,7 +36,10 @@ pub struct LocalServices { pub struct GarbageCollector; pub struct LocalStorage(*c_void, Option<~fn(*c_void)>); pub struct Logger; -pub struct Unwinder; + +pub struct Unwinder { + unwinding: bool, +} impl LocalServices { pub fn new() -> LocalServices { @@ -44,17 +48,28 @@ impl LocalServices { gc: GarbageCollector, storage: LocalStorage(ptr::null(), None), logger: Logger, - unwinder: Unwinder, + unwinder: Unwinder { unwinding: false }, destroyed: false } } + pub fn run(&mut self, f: &fn()) { + // This is just an assertion that `run` was called unsafely + // and this instance of LocalServices is still accessible. + do borrow_local_services |sched| { + assert!(ptr::ref_eq(sched, self)); + } + + self.unwinder.try(f); + self.destroy(); + } + /// Must be called manually before finalization to clean up /// thread-local resources. Some of the routines here expect /// LocalServices to be available recursively so this must be /// called unsafely, without removing LocalServices from /// thread-local-storage. - pub fn destroy(&mut self) { + fn destroy(&mut self) { // This is just an assertion that `destroy` was called unsafely // and this instance of LocalServices is still accessible. do borrow_local_services |sched| { @@ -72,6 +87,51 @@ impl Drop for LocalServices { fn finalize(&self) { assert!(self.destroyed) } } +// Just a sanity check to make sure we are catching a Rust-thrown exception +static UNWIND_TOKEN: uintptr_t = 839147; + +impl Unwinder { + pub fn try(&mut self, f: &fn()) { + use sys::Closure; + + unsafe { + let closure: Closure = transmute(f); + let code = transmute(closure.code); + let env = transmute(closure.env); + + let token = rust_try(try_fn, code, env); + assert!(token == 0 || token == UNWIND_TOKEN); + } + + extern fn try_fn(code: *c_void, env: *c_void) { + unsafe { + let closure: Closure = Closure { + code: transmute(code), + env: transmute(env), + }; + let closure: &fn() = transmute(closure); + closure(); + } + } + + extern { + #[rust_stack] + fn rust_try(f: *u8, code: *c_void, data: *c_void) -> uintptr_t; + } + } + + pub fn begin_unwind(&mut self) -> ! { + self.unwinding = true; + unsafe { + rust_begin_unwind(UNWIND_TOKEN); + return transmute(()); + } + extern { + fn rust_begin_unwind(token: uintptr_t); + } + } +} + /// Borrow a pointer to the installed local services. /// Fails (likely aborting the process) if local services are not available. pub fn borrow_local_services(f: &fn(&mut LocalServices)) { @@ -125,4 +185,14 @@ mod test { } } } + + #[test] + fn unwind() { + do run_in_newsched_task() { + let result = spawn_try(||()); + assert!(result.is_ok()); + let result = spawn_try(|| fail!()); + assert!(result.is_err()); + } + } } \ No newline at end of file diff --git a/src/libcore/rt/sched/mod.rs b/src/libcore/rt/sched/mod.rs index b7d861b8946b8..65456c30fee79 100644 --- a/src/libcore/rt/sched/mod.rs +++ b/src/libcore/rt/sched/mod.rs @@ -353,15 +353,10 @@ pub impl Task { unsafe { let sched = local_sched::unsafe_borrow(); sched.run_cleanup_job(); - } - - start(); - unsafe { - // Destroy the local heap, TLS, etc. let sched = local_sched::unsafe_borrow(); let task = sched.current_task.get_mut_ref(); - task.local_services.destroy(); + task.local_services.run(start); } let sched = local_sched::take(); diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs index e394a873feac6..f3d73c91bd604 100644 --- a/src/libcore/rt/test.rs +++ b/src/libcore/rt/test.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use result::{Result, Ok, Err}; use super::io::net::ip::{IpAddr, Ipv4}; /// Creates a new scheduler in a new thread and runs a task in it, @@ -47,6 +48,46 @@ pub fn spawn_immediately(f: ~fn()) { } } +/// Spawn a task and wait for it to finish, returning whether it completed successfully or failed +pub fn spawn_try(f: ~fn()) -> Result<(), ()> { + use cell::Cell; + use super::sched::*; + use task; + use unstable::finally::Finally; + + // Our status variables will be filled in from the scheduler context + let mut failed = false; + let failed_ptr: *mut bool = &mut failed; + + // Switch to the scheduler + let f = Cell(Cell(f)); + let mut sched = local_sched::take(); + do sched.deschedule_running_task_and_then() |old_task| { + let old_task = Cell(old_task); + let f = f.take(); + let mut sched = local_sched::take(); + let new_task = ~do Task::new(&mut sched.stack_pool) { + do (|| { + (f.take())() + }).finally { + // Check for failure then resume the parent task + unsafe { *failed_ptr = task::failing(); } + let sched = local_sched::take(); + do sched.switch_running_tasks_and_then(old_task.take()) |new_task| { + let new_task = Cell(new_task); + do local_sched::borrow |sched| { + sched.task_queue.push_front(new_task.take()); + } + } + } + }; + + sched.resume_task_immediately(new_task); + } + + if !failed { Ok(()) } else { Err(()) } +} + /// Get a port number, starting at 9600, for use in tests pub fn next_test_port() -> u16 { unsafe { diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs index 04f96f5eb229e..c50bc03517fa4 100644 --- a/src/libcore/sys.rs +++ b/src/libcore/sys.rs @@ -134,12 +134,27 @@ pub fn log_str(t: &T) -> ~str { /** Initiate task failure */ pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! { - do str::as_buf(msg) |msg_buf, _msg_len| { - do str::as_buf(file) |file_buf, _file_len| { + + use rt::{context, OldTaskContext}; + use rt::local_services::unsafe_borrow_local_services; + + match context() { + OldTaskContext => { + do str::as_buf(msg) |msg_buf, _msg_len| { + do str::as_buf(file) |file_buf, _file_len| { + unsafe { + let msg_buf = cast::transmute(msg_buf); + let file_buf = cast::transmute(file_buf); + begin_unwind_(msg_buf, file_buf, line as libc::size_t) + } + } + } + } + _ => { + gc::cleanup_stack_for_failure(); unsafe { - let msg_buf = cast::transmute(msg_buf); - let file_buf = cast::transmute(file_buf); - begin_unwind_(msg_buf, file_buf, line as libc::size_t) + let local_services = unsafe_borrow_local_services(); + local_services.unwinder.begin_unwind(); } } } diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index a243bfba85c6f..e1f4805a69208 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -558,8 +558,22 @@ pub fn yield() { pub fn failing() -> bool { //! True if the running task has failed - unsafe { - rt::rust_task_is_unwinding(rt::rust_get_task()) + use rt::{context, OldTaskContext}; + use rt::local_services::borrow_local_services; + + match context() { + OldTaskContext => { + unsafe { + rt::rust_task_is_unwinding(rt::rust_get_task()) + } + } + _ => { + let mut unwinding = false; + do borrow_local_services |local| { + unwinding = local.unwinder.unwinding; + } + return unwinding; + } } } diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index b8749b8f73d81..b37644460aa9e 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -886,6 +886,28 @@ rust_boxed_region_free(boxed_region *region, rust_opaque_box *box) { region->free(box); } +typedef void *(rust_try_fn)(void*, void*); + +extern "C" CDECL uintptr_t +rust_try(rust_try_fn f, void *fptr, void *env) { + try { + f(fptr, env); + } catch (uintptr_t token) { + assert(token != 0); + return token; + } + return 0; +} + +extern "C" CDECL void +rust_begin_unwind(uintptr_t token) { +#ifndef __WIN32__ + throw token; +#else + abort("failing on win32"); +#endif +} + // // Local Variables: // mode: C++ diff --git a/src/rt/rust_upcall.cpp b/src/rt/rust_upcall.cpp index 9f39e1433fc63..34236c36c1466 100644 --- a/src/rt/rust_upcall.cpp +++ b/src/rt/rust_upcall.cpp @@ -272,7 +272,13 @@ upcall_rust_personality(int version, s_rust_personality_args args = {(_Unwind_Reason_Code)0, version, actions, exception_class, ue_header, context}; - rust_task *task = rust_get_current_task(); + rust_task *task = rust_try_get_current_task(); + + if (task == NULL) { + // Assuming we're running with the new scheduler + upcall_s_rust_personality(&args); + return args.retval; + } // The personality function is run on the stack of the // last function that threw or landed, which is going @@ -309,8 +315,12 @@ upcall_del_stack() { // needs to acquire the value of the stack pointer extern "C" CDECL void upcall_reset_stack_limit() { - rust_task *task = rust_get_current_task(); - task->reset_stack_limit(); + rust_task *task = rust_try_get_current_task(); + if (task != NULL) { + task->reset_stack_limit(); + } else { + // We must be in a newsched task + } } // diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 9aa8015678360..5e9a4b343eeda 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -228,3 +228,5 @@ rust_new_boxed_region rust_delete_boxed_region rust_boxed_region_malloc rust_boxed_region_free +rust_try +rust_begin_unwind \ No newline at end of file From a292d5175091f61e92d0f393275e32ad2b05d584 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 22 Apr 2013 19:20:12 -0700 Subject: [PATCH 025/215] mk: Pass CFLAGS to the uv build --- mk/rt.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mk/rt.mk b/mk/rt.mk index 015992abf7821..538d1e2534fae 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -169,7 +169,7 @@ $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) else ifeq ($(OSTYPE_$(1)), linux-androideabi) $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) $$(Q)$$(MAKE) -C $$(S)src/libuv/ \ - CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \ + CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES) $$(CFLAGS)" \ LDFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1)))" \ CC="$$(CC_$(1))" \ CXX="$$(CXX_$(1))" \ @@ -181,7 +181,7 @@ $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) else $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) $$(Q)$$(MAKE) -C $$(S)src/libuv/ \ - CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \ + CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES) $$(CFLAGS)" \ LDFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1)))" \ CC="$$(CC_$(1))" \ CXX="$$(CXX_$(1))" \ From 8a2f9cae213d38b31e9372b9d8a7fee1263f1363 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 22 Apr 2013 19:20:31 -0700 Subject: [PATCH 026/215] core::rt: Fix a use after free in uv 'write' --- src/libcore/rt/uv/mod.rs | 6 ++++-- src/libcore/rt/uv/net.rs | 16 ++++++++++------ src/libcore/rt/uvio.rs | 5 ++++- src/libcore/rt/uvll.rs | 6 +++--- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/libcore/rt/uv/mod.rs b/src/libcore/rt/uv/mod.rs index 32757d6376e73..4c4b2e03d3daa 100644 --- a/src/libcore/rt/uv/mod.rs +++ b/src/libcore/rt/uv/mod.rs @@ -301,7 +301,8 @@ struct WatcherData { write_cb: Option, connect_cb: Option, close_cb: Option, - alloc_cb: Option + alloc_cb: Option, + buf: Option } pub fn install_watcher_data>(watcher: &mut W) { @@ -311,7 +312,8 @@ pub fn install_watcher_data>(watcher: &mut W) { write_cb: None, connect_cb: None, close_cb: None, - alloc_cb: None + alloc_cb: None, + buf: None }; let data = transmute::<~WatcherData, *c_void>(data); uvll::set_data_for_uv_handle(watcher.native_handle(), data); diff --git a/src/libcore/rt/uv/net.rs b/src/libcore/rt/uv/net.rs index 860c988b9c990..04b9008b06770 100644 --- a/src/libcore/rt/uv/net.rs +++ b/src/libcore/rt/uv/net.rs @@ -107,21 +107,25 @@ pub impl StreamWatcher { let req = WriteRequest::new(); let buf = vec_to_uv_buf(msg); - // XXX: Allocation - let bufs = ~[buf]; + assert!(data.buf.is_none()); + data.buf = Some(buf); + let bufs = [buf]; unsafe { assert!(0 == uvll::write(req.native_handle(), self.native_handle(), - &bufs, write_cb)); + bufs, write_cb)); } - // XXX: Freeing immediately after write. Is this ok? - let _v = vec_from_uv_buf(buf); extern fn write_cb(req: *uvll::uv_write_t, status: c_int) { let write_request: WriteRequest = NativeHandle::from_native_handle(req); let mut stream_watcher = write_request.stream(); write_request.delete(); - let cb = get_watcher_data(&mut stream_watcher).write_cb.swap_unwrap(); + let cb = { + let data = get_watcher_data(&mut stream_watcher); + let _vec = vec_from_uv_buf(data.buf.swap_unwrap()); + let cb = data.write_cb.swap_unwrap(); + cb + }; let status = status_to_maybe_uv_error(stream_watcher.native_handle(), status); cb(stream_watcher, status); } diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index 2e9d0afa52fe5..e7b2880b74b50 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -445,7 +445,7 @@ fn test_read_read_read() { let io = local_sched::unsafe_borrow_io(); let mut listener = io.bind(addr).unwrap(); let mut stream = listener.listen().unwrap(); - let mut buf = [0, .. 2048]; + let mut buf = [1, .. 2048]; let mut total_bytes_written = 0; while total_bytes_written < MAX { stream.write(buf); @@ -465,6 +465,9 @@ fn test_read_read_read() { let nread = stream.read(buf).unwrap(); rtdebug!("read %u bytes", nread as uint); total_bytes_read += nread; + for uint::range(0, nread) |i| { + assert!(buf[i] == 1); + } } rtdebug!("read %u bytes total", total_bytes_read as uint); stream.close(); diff --git a/src/libcore/rt/uvll.rs b/src/libcore/rt/uvll.rs index 640a69743ba6a..0f75ebb6090a1 100644 --- a/src/libcore/rt/uvll.rs +++ b/src/libcore/rt/uvll.rs @@ -219,9 +219,9 @@ pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int { return rust_uv_accept(server as *c_void, client as *c_void); } -pub unsafe fn write(req: *uv_write_t, stream: *T, buf_in: *~[uv_buf_t], cb: *u8) -> c_int { - let buf_ptr = vec::raw::to_ptr(*buf_in); - let buf_cnt = vec::len(*buf_in) as i32; +pub unsafe fn write(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int { + let buf_ptr = vec::raw::to_ptr(buf_in); + let buf_cnt = vec::len(buf_in) as i32; return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb); } pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: *u8, on_read: *u8) -> c_int { From f4af40a1db4862cfe1f17311e3e39cfff3324d82 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 22 Apr 2013 21:27:24 -0700 Subject: [PATCH 027/215] mk: core has another level of directories with rt/io/net --- Makefile.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index dd2e6a95861bd..33077872c1696 100644 --- a/Makefile.in +++ b/Makefile.in @@ -238,7 +238,7 @@ $(foreach target,$(CFG_TARGET_TRIPLES),\ CORELIB_CRATE := $(S)src/libcore/core.rc CORELIB_INPUTS := $(wildcard $(addprefix $(S)src/libcore/, \ - core.rc *.rs */*.rs */*/*rs)) + core.rc *.rs */*.rs */*/*rs */*/*/*rs)) ###################################################################### # Standard library variables From 2a819ae465c5f375df00ead0b3f4c9009da23f25 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 23 Apr 2013 15:11:28 -0700 Subject: [PATCH 028/215] core::rt: Tasks to not require an unwinder A task without an unwinder will abort the process on failure. I'm using this in the runtime tests to guarantee that a call to `assert!` actually triggers some kind of failure (an abort) instead of silently doing nothing. This is essentially in lieu of a working linked failure implementation. --- src/libcore/core.rc | 3 +++ src/libcore/macros.rs | 39 +++++++++++++++++++++++++++++ src/libcore/rt/local_services.rs | 30 +++++++++++++++++++---- src/libcore/rt/mod.rs | 20 --------------- src/libcore/rt/sched/mod.rs | 10 ++++++-- src/libcore/rt/test.rs | 42 +++++++++++++++++++++++--------- src/libcore/rt/uvio.rs | 12 ++++----- src/libcore/sys.rs | 6 ++++- src/libcore/task/mod.rs | 11 ++++++++- 9 files changed, 126 insertions(+), 47 deletions(-) create mode 100644 src/libcore/macros.rs diff --git a/src/libcore/core.rc b/src/libcore/core.rc index e7a5cfbaf4b25..a3b2cb4aaf959 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -114,6 +114,9 @@ pub mod linkhack { } } +// Internal macros +mod macros; + /* The Prelude. */ pub mod prelude; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs new file mode 100644 index 0000000000000..e1276a75e0557 --- /dev/null +++ b/src/libcore/macros.rs @@ -0,0 +1,39 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[macro_escape]; + +// Some basic logging +macro_rules! rtdebug ( + ($( $arg:expr),+) => ( { + dumb_println(fmt!( $($arg),+ )); + + fn dumb_println(s: &str) { + use io::WriterUtil; + let dbg = ::libc::STDERR_FILENO as ::io::fd_t; + dbg.write_str(s); + dbg.write_str("\n"); + } + + } ) +) + +// An alternate version with no output, for turning off logging +macro_rules! rtdebug_ ( + ($( $arg:expr),+) => ( $(let _ = $arg)*; ) +) + +macro_rules! abort( + ($( $msg:expr),+) => ( { + rtdebug!($($msg),+); + + unsafe { ::libc::abort(); } + } ) +) diff --git a/src/libcore/rt/local_services.rs b/src/libcore/rt/local_services.rs index fc75a25642861..d09d082c8581c 100644 --- a/src/libcore/rt/local_services.rs +++ b/src/libcore/rt/local_services.rs @@ -29,7 +29,7 @@ pub struct LocalServices { gc: GarbageCollector, storage: LocalStorage, logger: Logger, - unwinder: Unwinder, + unwinder: Option, destroyed: bool } @@ -48,7 +48,18 @@ impl LocalServices { gc: GarbageCollector, storage: LocalStorage(ptr::null(), None), logger: Logger, - unwinder: Unwinder { unwinding: false }, + unwinder: Some(Unwinder { unwinding: false }), + destroyed: false + } + } + + pub fn without_unwinding() -> LocalServices { + LocalServices { + heap: LocalHeap::new(), + gc: GarbageCollector, + storage: LocalStorage(ptr::null(), None), + logger: Logger, + unwinder: None, destroyed: false } } @@ -60,7 +71,16 @@ impl LocalServices { assert!(ptr::ref_eq(sched, self)); } - self.unwinder.try(f); + match self.unwinder { + Some(ref mut unwinder) => { + // If there's an unwinder then set up the catch block + unwinder.try(f); + } + None => { + // Otherwise, just run the body + f() + } + } self.destroy(); } @@ -189,9 +209,9 @@ mod test { #[test] fn unwind() { do run_in_newsched_task() { - let result = spawn_try(||()); + let result = spawntask_try(||()); assert!(result.is_ok()); - let result = spawn_try(|| fail!()); + let result = spawntask_try(|| fail!()); assert!(result.is_err()); } } diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs index 4a767d61f7444..ab89a4c26a54d 100644 --- a/src/libcore/rt/mod.rs +++ b/src/libcore/rt/mod.rs @@ -12,26 +12,6 @@ use libc::c_char; -// Some basic logging -macro_rules! rtdebug_ ( - ($( $arg:expr),+) => ( { - dumb_println(fmt!( $($arg),+ )); - - fn dumb_println(s: &str) { - use io::WriterUtil; - let dbg = ::libc::STDERR_FILENO as ::io::fd_t; - dbg.write_str(s); - dbg.write_str("\n"); - } - - } ) -) - -// An alternate version with no output, for turning off logging -macro_rules! rtdebug ( - ($( $arg:expr),+) => ( $(let _ = $arg)*; ) -) - #[path = "sched/mod.rs"] mod sched; mod rtio; diff --git a/src/libcore/rt/sched/mod.rs b/src/libcore/rt/sched/mod.rs index 65456c30fee79..f7b9bd8266844 100644 --- a/src/libcore/rt/sched/mod.rs +++ b/src/libcore/rt/sched/mod.rs @@ -149,7 +149,7 @@ pub impl Scheduler { } } - // Control never reaches here + abort!("control reached end of task"); } fn schedule_new_task(~self, task: ~Task) { @@ -333,6 +333,12 @@ pub struct Task { pub impl Task { fn new(stack_pool: &mut StackPool, start: ~fn()) -> Task { + Task::with_local(stack_pool, LocalServices::new(), start) + } + + fn with_local(stack_pool: &mut StackPool, + local_services: LocalServices, + start: ~fn()) -> Task { let start = Task::build_start_wrapper(start); let mut stack = stack_pool.take_segment(TASK_MIN_STACK_SIZE); // NB: Context holds a pointer to that ~fn @@ -340,7 +346,7 @@ pub impl Task { return Task { current_stack_segment: stack, saved_context: initial_context, - local_services: LocalServices::new() + local_services: local_services }; } diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs index f3d73c91bd604..f7ba881f84edb 100644 --- a/src/libcore/rt/test.rs +++ b/src/libcore/rt/test.rs @@ -8,38 +8,56 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use cell::Cell; use result::{Result, Ok, Err}; use super::io::net::ip::{IpAddr, Ipv4}; +use rt::local_services::LocalServices; /// Creates a new scheduler in a new thread and runs a task in it, -/// then waits for the scheduler to exit. +/// then waits for the scheduler to exit. Failure of the task +/// will abort the process. pub fn run_in_newsched_task(f: ~fn()) { - use cell::Cell; use unstable::run_in_bare_thread; use super::sched::Task; use super::uvio::UvEventLoop; - let f = Cell(Cell(f)); + let f = Cell(f); do run_in_bare_thread { let mut sched = ~UvEventLoop::new_scheduler(); - let f = f.take(); - let task = ~do Task::new(&mut sched.stack_pool) { - (f.take())(); - }; + let task = ~Task::with_local(&mut sched.stack_pool, + LocalServices::without_unwinding(), + f.take()); sched.task_queue.push_back(task); sched.run(); } } -/// Create a new task and run it right now -pub fn spawn_immediately(f: ~fn()) { - use cell::Cell; +/// Test tasks will abort on failure instead of unwinding +pub fn spawntask(f: ~fn()) { + use super::*; + use super::sched::*; + + let mut sched = local_sched::take(); + let task = ~Task::with_local(&mut sched.stack_pool, + LocalServices::without_unwinding(), + f); + do sched.switch_running_tasks_and_then(task) |task| { + let task = Cell(task); + let sched = local_sched::take(); + sched.schedule_new_task(task.take()); + } +} + +/// Create a new task and run it right now. Aborts on failure +pub fn spawntask_immediately(f: ~fn()) { use super::*; use super::sched::*; let mut sched = local_sched::take(); - let task = ~Task::new(&mut sched.stack_pool, f); + let task = ~Task::with_local(&mut sched.stack_pool, + LocalServices::without_unwinding(), + f); do sched.switch_running_tasks_and_then(task) |task| { let task = Cell(task); do local_sched::borrow |sched| { @@ -49,7 +67,7 @@ pub fn spawn_immediately(f: ~fn()) { } /// Spawn a task and wait for it to finish, returning whether it completed successfully or failed -pub fn spawn_try(f: ~fn()) -> Result<(), ()> { +pub fn spawntask_try(f: ~fn()) -> Result<(), ()> { use cell::Cell; use super::sched::*; use task; diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index e7b2880b74b50..4cceb048cbc75 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -350,7 +350,7 @@ fn test_simple_tcp_server_and_client() { let addr = next_test_ip4(); // Start the server first so it's listening when we connect - do spawn_immediately { + do spawntask_immediately { unsafe { let io = local_sched::unsafe_borrow_io(); let mut listener = io.bind(addr).unwrap(); @@ -367,7 +367,7 @@ fn test_simple_tcp_server_and_client() { } } - do spawn_immediately { + do spawntask_immediately { unsafe { let io = local_sched::unsafe_borrow_io(); let mut stream = io.connect(addr).unwrap(); @@ -383,7 +383,7 @@ fn test_read_and_block() { do run_in_newsched_task { let addr = next_test_ip4(); - do spawn_immediately { + do spawntask_immediately { let io = unsafe { local_sched::unsafe_borrow_io() }; let mut listener = io.bind(addr).unwrap(); let mut stream = listener.listen().unwrap(); @@ -421,7 +421,7 @@ fn test_read_and_block() { listener.close(); } - do spawn_immediately { + do spawntask_immediately { let io = unsafe { local_sched::unsafe_borrow_io() }; let mut stream = io.connect(addr).unwrap(); stream.write([0, 1, 2, 3, 4, 5, 6, 7]); @@ -440,7 +440,7 @@ fn test_read_read_read() { let addr = next_test_ip4(); static MAX: uint = 500000; - do spawn_immediately { + do spawntask_immediately { unsafe { let io = local_sched::unsafe_borrow_io(); let mut listener = io.bind(addr).unwrap(); @@ -456,7 +456,7 @@ fn test_read_read_read() { } } - do spawn_immediately { + do spawntask_immediately { let io = unsafe { local_sched::unsafe_borrow_io() }; let mut stream = io.connect(addr).unwrap(); let mut buf = [0, .. 2048]; diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs index c50bc03517fa4..2c3670ad498e2 100644 --- a/src/libcore/sys.rs +++ b/src/libcore/sys.rs @@ -10,6 +10,7 @@ //! Misc low level stuff +use option::{Some, None}; use cast; use cmp::{Eq, Ord}; use gc; @@ -154,7 +155,10 @@ pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! { gc::cleanup_stack_for_failure(); unsafe { let local_services = unsafe_borrow_local_services(); - local_services.unwinder.begin_unwind(); + match local_services.unwinder { + Some(ref mut unwinder) => unwinder.begin_unwind(), + None => abort!("failure without unwinder. aborting process") + } } } } diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index e1f4805a69208..d31a511eca8c9 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -570,7 +570,16 @@ pub fn failing() -> bool { _ => { let mut unwinding = false; do borrow_local_services |local| { - unwinding = local.unwinder.unwinding; + unwinding = match local.unwinder { + Some(unwinder) => { + unwinder.unwinding + } + None => { + // Because there is no unwinder we can't be unwinding. + // (The process will abort on failure) + false + } + } } return unwinding; } From 6373861510795bcaa6e98e97942c32eb26263bd8 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 23 Apr 2013 19:52:16 -0700 Subject: [PATCH 029/215] core: Convert reinterpret_cast to transmute in TLS. #6039 --- src/libcore/task/local_data_priv.rs | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/src/libcore/task/local_data_priv.rs b/src/libcore/task/local_data_priv.rs index 66808bf21aa2b..e32d18719bd00 100644 --- a/src/libcore/task/local_data_priv.rs +++ b/src/libcore/task/local_data_priv.rs @@ -49,8 +49,8 @@ impl LocalData for @T { } impl Eq for @LocalData { fn eq(&self, other: &@LocalData) -> bool { unsafe { - let ptr_a: (uint, uint) = cast::reinterpret_cast(&(*self)); - let ptr_b: (uint, uint) = cast::reinterpret_cast(other); + let ptr_a: &(uint, uint) = cast::transmute(self); + let ptr_b: &(uint, uint) = cast::transmute(other); return ptr_a == ptr_b; } } @@ -68,7 +68,7 @@ fn cleanup_task_local_map(map_ptr: *libc::c_void) { assert!(!map_ptr.is_null()); // Get and keep the single reference that was created at the // beginning. - let _map: TaskLocalMap = cast::reinterpret_cast(&map_ptr); + let _map: TaskLocalMap = cast::transmute(map_ptr); // All local_data will be destroyed along with the map. } } @@ -125,14 +125,9 @@ unsafe fn get_newsched_local_map(local: *mut LocalStorage) -> TaskLocalMap { &LocalStorage(ref mut map_ptr, ref mut at_exit) => { assert!((*map_ptr).is_null()); let map: TaskLocalMap = @mut ~[]; - // Use reinterpret_cast -- transmute would take map away from us also. - *map_ptr = cast::reinterpret_cast(&map); + *map_ptr = cast::transmute(map); let at_exit_fn: ~fn(*libc::c_void) = |p|cleanup_task_local_map(p); *at_exit = Some(at_exit_fn); - // Also need to reference it an extra time to keep it for now. - let nonmut = cast::transmute::]>(map); - cast::bump_box_refcount(nonmut); return map; } } @@ -143,7 +138,7 @@ unsafe fn key_to_key_value( // Keys are closures, which are (fnptr,envptr) pairs. Use fnptr. // Use reintepret_cast -- transmute would leak (forget) the closure. - let pair: (*libc::c_void, *libc::c_void) = cast::reinterpret_cast(&key); + let pair: (*libc::c_void, *libc::c_void) = cast::transmute(key); pair.first() } @@ -213,7 +208,7 @@ pub unsafe fn local_set( // own on it can be dropped when the box is destroyed. The unsafe pointer // does not have a reference associated with it, so it may become invalid // when the box is destroyed. - let data_ptr = cast::reinterpret_cast(&data); + let data_ptr = *cast::transmute::<&@T, &*libc::c_void>(&data); let data_box = @data as @LocalData; // Construct new entry to store in the map. let new_entry = Some((keyval, data_ptr, data_box)); From c0e734d203ac5c51ba2cac7b4e5ef099d83350da Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 23 Apr 2013 19:21:37 -0700 Subject: [PATCH 030/215] core::rt: Add more I/O docs --- src/libcore/rt/io/mod.rs | 173 ++++++++++++++++++++++++++++++++++----- src/libcore/rt/mod.rs | 2 + 2 files changed, 153 insertions(+), 22 deletions(-) diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs index 131743305bcce..ced4ba0ee2309 100644 --- a/src/libcore/rt/io/mod.rs +++ b/src/libcore/rt/io/mod.rs @@ -10,12 +10,14 @@ /*! Synchronous I/O -This module defines the Rust interface for synchronous I/O. It is -build around Reader and Writer traits that define byte stream sources -and sinks. Implementations are provided for common I/O streams like -file, TCP, UDP, Unix domain sockets, multiple types of memory bufers. -Readers and Writers may be composed to add things like string parsing, -and compression. +This module defines the Rust interface for synchronous I/O. +It models byte-oriented input and output with the Reader and Writer traits. +Types that implement both `Reader` and `Writer` and called 'streams', +and automatically implement trait `Stream`. +Implementations are provided for common I/O streams like +file, TCP, UDP, Unix domain sockets. +Readers and Writers may be composed to add capabilities like string +parsing, encoding, and compression. This will likely live in core::io, not core::rt::io. @@ -31,22 +33,22 @@ Some examples of obvious things you might want to do * Read a complete file to a string, (converting newlines?) - let contents = FileStream::open("message.txt").read_to_str(); // read_to_str?? + let contents = File::open("message.txt").read_to_str(); // read_to_str?? * Write a line to a file - let file = FileStream::open("message.txt", Create, Write); + let file = File::open("message.txt", Create, Write); file.write_line("hello, file!"); * Iterate over the lines of a file - do FileStream::open("message.txt").each_line |line| { + do File::open("message.txt").each_line |line| { println(line) } * Pull the lines of a file into a vector of strings - let lines = FileStream::open("message.txt").line_iter().to_vec(); + let lines = File::open("message.txt").line_iter().to_vec(); * Make an simple HTTP request @@ -63,25 +65,145 @@ Some examples of obvious things you might want to do # Terms -* reader -* writer -* stream -* Blocking vs. non-blocking -* synchrony and asynchrony - -I tend to call this implementation non-blocking, because performing I/O -doesn't block the progress of other tasks. Is that how we want to present -it, 'synchronous but non-blocking'? +* Reader - An I/O source, reads bytes into a buffer +* Writer - An I/O sink, writes bytes from a buffer +* Stream - Typical I/O sources like files and sockets are both Readers and Writers, + and are collectively referred to a `streams`. +* Decorator - A Reader or Writer that composes with others to add additional capabilities + such as encoding or decoding + +# Blocking and synchrony + +When discussing I/O you often hear the terms 'synchronous' and +'asynchronous', along with 'blocking' and 'non-blocking' compared and +contrasted. A synchronous I/O interface performs each I/O operation to +completion before proceeding to the next. Synchronous interfaces are +usually used in imperative style as a sequence of commands. An +asynchronous interface allows multiple I/O requests to be issued +simultaneously, without waiting for each to complete before proceeding +to the next. + +Asynchronous interfaces are used to achieve 'non-blocking' I/O. In +traditional single-threaded systems, performing a synchronous I/O +operation means that the program stops all activity (it 'blocks') +until the I/O is complete. Blocking is bad for performance when +there are other computations that could be done. + +Asynchronous interfaces are most often associated with the callback +(continuation-passing) style popularised by node.js. Such systems rely +on all computations being run inside an event loop which maintains a +list of all pending I/O events; when one completes the registered +callback is run and the code that made the I/O request continiues. +Such interfaces achieve non-blocking at the expense of being more +difficult to reason about. + +Rust's I/O interface is synchronous - easy to read - and non-blocking by default. + +Remember that Rust tasks are 'green threads', lightweight threads that +are multiplexed onto a single operating system thread. If that system +thread blocks then no other task may proceed. Rust tasks are +relatively cheap to create, so as long as other tasks are free to +execute then non-blocking code may be written by simply creating a new +task. + +When discussing blocking in regards to Rust's I/O model, we are +concerned with whether performing I/O blocks other Rust tasks from +proceeding. In other words, when a task calls `read`, it must then +wait (or 'sleep', or 'block') until the call to `read` is complete. +During this time, other tasks may or may not be executed, depending on +how `read` is implemented. + + +Rust's default I/O implementation is non-blocking; by cooperating +directly with the task scheduler it arranges to never block progress +of *other* tasks. Under the hood, Rust uses asynchronous I/O via a +per-scheduler (and hence per-thread) event loop. Synchronous I/O +requests are implemented by descheduling the running task and +performing an asynchronous request; the task is only resumed once the +asynchronous request completes. + +For blocking (but possibly more efficient) implementations, look +in the `io::native` module. # Error Handling +I/O is an area where nearly every operation can result in unexpected +errors. It should allow errors to be handled efficiently. +It needs to be convenient to use I/O when you don't care +about dealing with specific errors. + +Rust's I/O employs a combination of techniques to reduce boilerplate +while still providing feedback about errors. The basic strategy: + +* Errors are fatal by default, resulting in task failure +* Errors raise the `io_error` conditon which provides an opportunity to inspect + an IoError object containing details. +* Return values must have a sensible null or zero value which is returned + if a condition is handled successfully. This may be an `Option`, an empty + vector, or other designated error value. +* Common traits are implemented for `Option`, e.g. `impl Reader for Option`, + so that nullable values do not have to be 'unwrapped' before use. + +These features combine in the API to allow for expressions like +`File::new("diary.txt").write_line("met a girl")` without having to +worry about whether "diary.txt" exists or whether the write +succeeds. As written, if either `new` or `write_line` encounters +an error the task will fail. + +If you wanted to handle the error though you might write + + let mut error = None; + do io_error::cond(|e: IoError| { + error = Some(e); + }).in { + File::new("diary.txt").write_line("met a girl"); + } + + if error.is_some() { + println("failed to write my diary"); + } + +XXX: Need better condition handling syntax + +In this case the condition handler will have the opportunity to +inspect the IoError raised by either the call to `new` or the call to +`write_line`, but then execution will continue. + +So what actually happens if `new` encounters an error? To understand +that it's important to know that what `new` returns is not a `File` +but an `Option`. If the file does not open, and the condition +is handled, then `new` will simply return `None`. Because there is an +implementation of `Writer` (the trait required ultimately required for +types to implement `write_line`) there is no need to inspect or unwrap +the `Option` and we simply call `write_line` on it. If `new` +returned a `None` then the followup call to `write_line` will also +raise an error. + +## Concerns about this strategy + +This structure will encourage a programming style that is prone +to errors similar to null pointer dereferences. +In particular code written to ignore errors and expect conditions to be unhandled +will start passing around null or zero objects when wrapped in a condition handler. + +* XXX: How should we use condition handlers that return values? + + +# Issues withi/o scheduler affinity, work stealing, task pinning + # Resource management * `close` vs. RAII -# Paths and URLs +# Paths, URLs and overloaded constructors + + -# std +# Scope + +In scope for core + +* Url? Some I/O things don't belong in core @@ -90,7 +212,12 @@ Some I/O things don't belong in core - http - flate -# XXX +Out of scope + +* Async I/O. We'll probably want it eventually + + +# XXX Questions and issues * Should default constructors take `Path` or `&str`? `Path` makes simple cases verbose. Overloading would be nice. @@ -100,6 +227,7 @@ Some I/O things don't belong in core * fsync * relationship with filesystem querying, Directory, File types etc. * Rename Reader/Writer to ByteReader/Writer, make Reader/Writer generic? +* Can Port and Chan be implementations of a generic Reader/Writer? * Trait for things that are both readers and writers, Stream? * How to handle newline conversion * String conversion @@ -109,6 +237,7 @@ Some I/O things don't belong in core * Do we need `close` at all? dtors might be good enough * How does I/O relate to the Iterator trait? * std::base64 filters +* Using conditions is a big unknown since we don't have much experience with them */ diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs index ab89a4c26a54d..56ed7dc95b6df 100644 --- a/src/libcore/rt/mod.rs +++ b/src/libcore/rt/mod.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +/*! The Rust runtime, including the scheduler and I/O interface */ + #[doc(hidden)]; use libc::c_char; From 354460e53b8de468db77433e97e7cdf809c68ccd Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 23 Apr 2013 20:41:00 -0700 Subject: [PATCH 031/215] Tidy --- src/libcore/rt/uvio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index 54f3276c31752..984ae55399ceb 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -439,7 +439,7 @@ fn test_read_read_read() { do run_in_newsched_task { let addr = next_test_ip4(); static MAX: uint = 500000; - + do spawntask_immediately { unsafe { let io = local_sched::unsafe_borrow_io(); From 34f7255afa4aa80ade1f98b99f0f54cb424b129e Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 23 Apr 2013 22:51:48 -0700 Subject: [PATCH 032/215] mk: reorganize doc build to fix dependencies. #6042 Most of our documentation requires both pandoc and node.js. This simplifies the logic around those checks and fixes an error when building without node.js but with pandoc. --- mk/docs.mk | 71 +++++++++++++++++++++++++----------------------------- 1 file changed, 33 insertions(+), 38 deletions(-) diff --git a/mk/docs.mk b/mk/docs.mk index 6873d433e951f..252f62cf87116 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -16,15 +16,8 @@ DOCS := ###################################################################### -# Pandoc (reference-manual related) +# Docs, from pandoc, rustdoc (which runs pandoc), and node ###################################################################### -ifeq ($(CFG_PANDOC),) - $(info cfg: no pandoc found, omitting doc/rust.pdf) -else - - ifeq ($(CFG_NODE),) - $(info cfg: no node found, omitting doc/tutorial.html) - else doc/rust.css: rust.css @$(call E, cp: $@) @@ -34,6 +27,18 @@ doc/manual.css: manual.css @$(call E, cp: $@) $(Q)cp -a $< $@ 2> /dev/null +ifeq ($(CFG_PANDOC),) + $(info cfg: no pandoc found, omitting docs) + NO_DOCS = 1 +endif + +ifeq ($(CFG_NODE),) + $(info cfg: no node found, omitting docs) + NO_DOCS = 1 +endif + +ifneq ($(NO_DOCS),1) + DOCS += doc/rust.html doc/rust.html: rust.md doc/version_info.html doc/rust.css doc/manual.css @$(call E, pandoc: $@) @@ -47,17 +52,6 @@ doc/rust.html: rust.md doc/version_info.html doc/rust.css doc/manual.css --css=manual.css \ --include-before-body=doc/version_info.html \ --output=$@ - endif - - ifeq ($(CFG_PDFLATEX),) - $(info cfg: no pdflatex found, omitting doc/rust.pdf) - else - ifeq ($(CFG_XETEX),) - $(info cfg: no xetex found, disabling doc/rust.pdf) - else - ifeq ($(CFG_LUATEX),) - $(info cfg: lacking luatex, disabling pdflatex) - else DOCS += doc/rust.pdf doc/rust.tex: rust.md doc/version.md @@ -70,17 +64,6 @@ doc/rust.tex: rust.md doc/version.md --from=markdown --to=latex \ --output=$@ -doc/rust.pdf: doc/rust.tex - @$(call E, pdflatex: $@) - $(Q)$(CFG_PDFLATEX) \ - -interaction=batchmode \ - -output-directory=doc \ - $< - - endif - endif - endif - DOCS += doc/rustpkg.html doc/rustpkg.html: rustpkg.md doc/version_info.html doc/rust.css doc/manual.css @$(call E, pandoc: $@) @@ -95,13 +78,6 @@ doc/rustpkg.html: rustpkg.md doc/version_info.html doc/rust.css doc/manual.css --include-before-body=doc/version_info.html \ --output=$@ -###################################################################### -# Node (tutorial related) -###################################################################### - ifeq ($(CFG_NODE),) - $(info cfg: no node found, omitting doc/tutorial.html) - else - DOCS += doc/tutorial.html doc/tutorial.html: tutorial.md doc/version_info.html doc/rust.css @$(call E, pandoc: $@) @@ -153,9 +129,28 @@ doc/tutorial-tasks.html: tutorial-tasks.md doc/version_info.html doc/rust.css --include-before-body=doc/version_info.html \ --output=$@ + ifeq ($(CFG_PDFLATEX),) + $(info cfg: no pdflatex found, omitting doc/rust.pdf) + else + ifeq ($(CFG_XETEX),) + $(info cfg: no xetex found, disabling doc/rust.pdf) + else + ifeq ($(CFG_LUATEX),) + $(info cfg: lacking luatex, disabling pdflatex) + else + +doc/rust.pdf: doc/rust.tex + @$(call E, pdflatex: $@) + $(Q)$(CFG_PDFLATEX) \ + -interaction=batchmode \ + -output-directory=doc \ + $< + + endif + endif endif -endif +endif # No pandoc / node ###################################################################### # LLnextgen (grammar analysis from refman) From 1962803854bcf7245013f8a1377c0ade845b5c54 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 24 Apr 2013 12:11:33 -0700 Subject: [PATCH 033/215] core: Warning police --- src/libcore/condition.rs | 2 ++ src/libcore/rt/io/file.rs | 2 +- src/libcore/rt/io/net/tcp.rs | 3 --- src/libcore/rt/io/net/udp.rs | 1 - src/libcore/rt/io/net/unix.rs | 1 - src/libcore/rt/local_services.rs | 2 +- src/libcore/rt/test.rs | 2 -- src/libcore/rt/uvio.rs | 3 +-- src/libcore/task/local_data.rs | 1 - 9 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/libcore/condition.rs b/src/libcore/condition.rs index c639239981cab..1240fe03dd54d 100644 --- a/src/libcore/condition.rs +++ b/src/libcore/condition.rs @@ -206,10 +206,12 @@ mod test { fn test_conditions_are_public() { let mut trapped = false; do sadness::cond.trap(|_| { + trapped = true; 0 }).in { sadness::cond.raise(0); } + assert!(trapped); } } } diff --git a/src/libcore/rt/io/file.rs b/src/libcore/rt/io/file.rs index e4fe066a173f4..85dc180452ffc 100644 --- a/src/libcore/rt/io/file.rs +++ b/src/libcore/rt/io/file.rs @@ -11,7 +11,7 @@ use prelude::*; use super::support::PathLike; use super::{Reader, Writer, Seek, Close}; -use super::{IoError, SeekStyle}; +use super::SeekStyle; /// # XXX /// * Ugh, this is ridiculous. What is the best way to represent these options? diff --git a/src/libcore/rt/io/net/tcp.rs b/src/libcore/rt/io/net/tcp.rs index d726bae821c87..c95b4344fe75d 100644 --- a/src/libcore/rt/io/net/tcp.rs +++ b/src/libcore/rt/io/net/tcp.rs @@ -9,7 +9,6 @@ // except according to those terms. use prelude::*; -use super::*; use super::super::*; use super::ip::IpAddr; @@ -51,8 +50,6 @@ impl Listener for TcpListener { #[cfg(test)] mod test { - use super::*; - use rt::test::*; #[test] #[ignore] fn smoke_test() { diff --git a/src/libcore/rt/io/net/udp.rs b/src/libcore/rt/io/net/udp.rs index 8691a697e8888..0cb2978fb1a68 100644 --- a/src/libcore/rt/io/net/udp.rs +++ b/src/libcore/rt/io/net/udp.rs @@ -9,7 +9,6 @@ // except according to those terms. use prelude::*; -use super::*; use super::super::*; use super::ip::IpAddr; diff --git a/src/libcore/rt/io/net/unix.rs b/src/libcore/rt/io/net/unix.rs index bb3db6ec0d502..262816beecc98 100644 --- a/src/libcore/rt/io/net/unix.rs +++ b/src/libcore/rt/io/net/unix.rs @@ -9,7 +9,6 @@ // except according to those terms. use prelude::*; -use super::*; use super::super::*; use super::super::support::PathLike; diff --git a/src/libcore/rt/local_services.rs b/src/libcore/rt/local_services.rs index 8a6277c209417..a03bc6c409f8b 100644 --- a/src/libcore/rt/local_services.rs +++ b/src/libcore/rt/local_services.rs @@ -21,7 +21,7 @@ use prelude::*; use libc::{c_void, uintptr_t}; use cast::transmute; -use super::sched::{Task, local_sched}; +use super::sched::local_sched; use super::local_heap::LocalHeap; pub struct LocalServices { diff --git a/src/libcore/rt/test.rs b/src/libcore/rt/test.rs index f7ba881f84edb..63db705408800 100644 --- a/src/libcore/rt/test.rs +++ b/src/libcore/rt/test.rs @@ -35,7 +35,6 @@ pub fn run_in_newsched_task(f: ~fn()) { /// Test tasks will abort on failure instead of unwinding pub fn spawntask(f: ~fn()) { - use super::*; use super::sched::*; let mut sched = local_sched::take(); @@ -51,7 +50,6 @@ pub fn spawntask(f: ~fn()) { /// Create a new task and run it right now. Aborts on failure pub fn spawntask_immediately(f: ~fn()) { - use super::*; use super::sched::*; let mut sched = local_sched::take(); diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index 984ae55399ceb..94f8c0bf707dd 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -11,7 +11,7 @@ use option::*; use result::*; -use super::io::net::ip::{IpAddr, Ipv4}; // n.b. Ipv4 is used only in tests +use super::io::net::ip::IpAddr; use super::uv::*; use super::rtio::*; use ops::Drop; @@ -21,7 +21,6 @@ use super::sched::{Scheduler, local_sched}; #[cfg(test)] use uint; #[cfg(test)] use unstable::run_in_bare_thread; -#[cfg(test)] use super::sched::Task; #[cfg(test)] use super::test::*; pub struct UvEventLoop { diff --git a/src/libcore/task/local_data.rs b/src/libcore/task/local_data.rs index 65e6893191575..dff5908c04796 100644 --- a/src/libcore/task/local_data.rs +++ b/src/libcore/task/local_data.rs @@ -28,7 +28,6 @@ magic. use prelude::*; use task::local_data_priv::{local_get, local_pop, local_modify, local_set, Handle}; -use task::rt; /** * Indexes a task-local data slot. The function's code pointer is used for From 08659f5acc42e9ed73c85359a2b1f02e5484dbb0 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 24 Apr 2013 12:11:55 -0700 Subject: [PATCH 034/215] core: Turn off rtdebug logging Accidentally left in on at some point --- src/libcore/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index e1276a75e0557..b19a753b71577 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -11,7 +11,7 @@ #[macro_escape]; // Some basic logging -macro_rules! rtdebug ( +macro_rules! rtdebug_ ( ($( $arg:expr),+) => ( { dumb_println(fmt!( $($arg),+ )); @@ -26,7 +26,7 @@ macro_rules! rtdebug ( ) // An alternate version with no output, for turning off logging -macro_rules! rtdebug_ ( +macro_rules! rtdebug ( ($( $arg:expr),+) => ( $(let _ = $arg)*; ) ) From 436657b5f04a6d7504cfc00224c26910569c67eb Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 24 Apr 2013 15:34:02 -0700 Subject: [PATCH 035/215] Rename cleanup_task_local_map_ to cleanup_task_local_map_extern_cb Per pcwalton's suggestion. --- src/libcore/task/local_data_priv.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/task/local_data_priv.rs b/src/libcore/task/local_data_priv.rs index e32d18719bd00..fdf1fa2a53273 100644 --- a/src/libcore/task/local_data_priv.rs +++ b/src/libcore/task/local_data_priv.rs @@ -83,7 +83,7 @@ unsafe fn get_local_map(handle: Handle) -> TaskLocalMap { unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { - extern fn cleanup_task_local_map_(map_ptr: *libc::c_void) { + extern fn cleanup_task_local_map_extern_cb(map_ptr: *libc::c_void) { cleanup_task_local_map(map_ptr); } @@ -97,7 +97,7 @@ unsafe fn get_task_local_map(task: *rust_task) -> TaskLocalMap { // Use reinterpret_cast -- transmute would take map away from us also. rt::rust_set_task_local_data( task, cast::transmute(map)); - rt::rust_task_local_data_atexit(task, cleanup_task_local_map_); + rt::rust_task_local_data_atexit(task, cleanup_task_local_map_extern_cb); // Also need to reference it an extra time to keep it for now. let nonmut = cast::transmute::]>(map); From abc49fdfae0b80acfa010fd6151ff8ffc229c03b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 24 Apr 2013 21:33:03 -0700 Subject: [PATCH 036/215] rt: abort doesn't take an argument --- src/rt/rust_builtin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 2097d8dd93335..8b7b89680fcca 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -909,7 +909,7 @@ rust_begin_unwind(uintptr_t token) { #ifndef __WIN32__ throw token; #else - abort("failing on win32"); + abort(); #endif } From 00ede34fcb4d6de11e49360964565c8e487a678e Mon Sep 17 00:00:00 2001 From: James Miller Date: Mon, 29 Apr 2013 12:57:49 +1200 Subject: [PATCH 037/215] Add `--linker` option to pass flags to the linker --- src/librustc/back/link.rs | 3 + src/librustc/driver/driver.rs | 118 ++++++++++++++++++--------------- src/librustc/driver/session.rs | 2 + 3 files changed, 70 insertions(+), 53 deletions(-) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 8c442f2d5c9f3..aaa425c93348a 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -904,6 +904,9 @@ pub fn link_binary(sess: Session, // extern libraries might live, based on the addl_lib_search_paths cc_args.push_all(rpath::get_rpath_flags(sess, &output)); + // Finally add all the linker arguments provided on the command line + cc_args.push_all(sess.opts.linker_args); + debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" ")); // We run 'cc' here let prog = run::program_output(cc_prog, cc_args); diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index a6c061fee1e8e..fbcbd4461ac10 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -645,9 +645,16 @@ pub fn build_session_options(binary: @~str, Some(s) => s }; - let addl_lib_search_paths = - getopts::opt_strs(matches, ~"L") - .map(|s| Path(*s)); + let addl_lib_search_paths = getopts::opt_strs(matches, ~"L").map(|s| Path(*s)); + + let linker_args = getopts::opt_strs(matches, ~"linker").flat_map( |a| { + let mut args = ~[]; + for str::each_split_char(*a, ',') |arg| { + args.push(str::from_slice(arg)); + } + args + }); + let cfg = parse_cfgspecs(getopts::opt_strs(matches, ~"cfg"), demitter); let test = opt_present(matches, ~"test"); let android_cross_path = getopts::opt_maybe_str( @@ -664,6 +671,7 @@ pub fn build_session_options(binary: @~str, jit: jit, output_type: output_type, addl_lib_search_paths: addl_lib_search_paths, + linker_args: linker_args, maybe_sysroot: sysroot_opt, target_triple: target, target_feature: target_feature, @@ -737,62 +745,66 @@ pub fn parse_pretty(sess: Session, name: &str) -> pp_mode { // rustc command line options pub fn optgroups() -> ~[getopts::groups::OptGroup] { ~[ - optflag(~"", ~"bin", ~"Compile an executable crate (default)"), - optflag(~"c", ~"", ~"Compile and assemble, but do not link"), - optmulti(~"", ~"cfg", ~"Configure the compilation - environment", ~"SPEC"), - optflag(~"", ~"emit-llvm", - ~"Produce an LLVM bitcode file"), - optflag(~"h", ~"help",~"Display this message"), - optmulti(~"L", ~"", ~"Add a directory to the library search path", - ~"PATH"), - optflag(~"", ~"lib", ~"Compile a library crate"), - optflag(~"", ~"ls", ~"List the symbols defined by a library crate"), - optflag(~"", ~"no-trans", - ~"Run all passes except translation; no output"), - optflag(~"O", ~"", ~"Equivalent to --opt-level=2"), - optopt(~"o", ~"", ~"Write output to ", ~"FILENAME"), - optopt(~"", ~"opt-level", - ~"Optimize with possible levels 0-3", ~"LEVEL"), - optopt( ~"", ~"out-dir", - ~"Write output to compiler-chosen filename - in ", ~"DIR"), - optflag(~"", ~"parse-only", - ~"Parse only; do not compile, assemble, or link"), - optflagopt(~"", ~"pretty", - ~"Pretty-print the input instead of compiling; + optflag("", "bin", "Compile an executable crate (default)"), + optflag("c", "", "Compile and assemble, but do not link"), + optmulti("", "cfg", "Configure the compilation + environment", "SPEC"), + optflag("", "emit-llvm", + "Produce an LLVM bitcode file"), + optflag("h", "help","Display this message"), + optmulti("L", "", "Add a directory to the library search path", + "PATH"), + optflag("", "lib", "Compile a library crate"), + optmulti("", "linker", "FLAGS is a comma-separated list of flags + passed to the linker", "FLAGS"), + optflag("", "ls", "List the symbols defined by a library crate"), + optflag("", "no-trans", + "Run all passes except translation; no output"), + optflag("O", "", "Equivalent to --opt-level=2"), + optopt("o", "", "Write output to ", "FILENAME"), + optopt("", "opt-level", + "Optimize with possible levels 0-3", "LEVEL"), + optopt( "", "out-dir", + "Write output to compiler-chosen filename + in ", "DIR"), + optflag("", "parse-only", + "Parse only; do not compile, assemble, or link"), + optflagopt("", "pretty", + "Pretty-print the input instead of compiling; valid types are: normal (un-annotated source), expanded (crates expanded), typed (crates expanded, with type annotations), or identified (fully parenthesized, - AST nodes and blocks with IDs)", ~"TYPE"), - optflag(~"S", ~"", ~"Compile only; do not assemble or link"), - optflag(~"", ~"save-temps", - ~"Write intermediate files (.bc, .opt.bc, .o) + AST nodes and blocks with IDs)", "TYPE"), + optflag("", "print-link-args", "Prints all the arguments that would be + passed to the linker."), + optflag("S", "", "Compile only; do not assemble or link"), + optflag("", "save-temps", + "Write intermediate files (.bc, .opt.bc, .o) in addition to normal output"), - optopt(~"", ~"sysroot", - ~"Override the system root", ~"PATH"), - optflag(~"", ~"test", ~"Build a test harness"), - optopt(~"", ~"target", - ~"Target triple cpu-manufacturer-kernel[-os] + optopt("", "sysroot", + "Override the system root", "PATH"), + optflag("", "test", "Build a test harness"), + optopt("", "target", + "Target triple cpu-manufacturer-kernel[-os] to compile for (see chapter 3.4 of http://www.sourceware.org/autobook/ - for detail)", ~"TRIPLE"), - optopt(~"", ~"target-feature", - ~"Target specific attributes (llc -mattr=help - for detail)", ~"FEATURE"), - optopt(~"", ~"android-cross-path", - ~"The path to the Android NDK", "PATH"), - optmulti(~"W", ~"warn", - ~"Set lint warnings", ~"OPT"), - optmulti(~"A", ~"allow", - ~"Set lint allowed", ~"OPT"), - optmulti(~"D", ~"deny", - ~"Set lint denied", ~"OPT"), - optmulti(~"F", ~"forbid", - ~"Set lint forbidden", ~"OPT"), - optmulti(~"Z", ~"", ~"Set internal debugging options", "FLAG"), - optflag( ~"v", ~"version", - ~"Print version info and exit"), + for detail)", "TRIPLE"), + optopt("", "target-feature", + "Target specific attributes (llc -mattr=help + for detail)", "FEATURE"), + optopt("", "android-cross-path", + "The path to the Android NDK", "PATH"), + optmulti("W", "warn", + "Set lint warnings", "OPT"), + optmulti("A", "allow", + "Set lint allowed", "OPT"), + optmulti("D", "deny", + "Set lint denied", "OPT"), + optmulti("F", "forbid", + "Set lint forbidden", "OPT"), + optmulti("Z", "", "Set internal debugging options", "FLAG"), + optflag( "v", "version", + "Print version info and exit"), ] } diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 55c81e6d17b20..94d1da20f9268 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -122,6 +122,7 @@ pub struct options { jit: bool, output_type: back::link::output_type, addl_lib_search_paths: ~[Path], + linker_args: ~[~str], maybe_sysroot: Option, target_triple: ~str, target_feature: ~str, @@ -299,6 +300,7 @@ pub fn basic_options() -> @options { jit: false, output_type: link::output_type_exe, addl_lib_search_paths: ~[], + linker_args:~[], maybe_sysroot: None, target_triple: host_triple(), target_feature: ~"", From edc11a9f09060b355010b8cc71da45c4f35eadf0 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Wed, 17 Apr 2013 19:36:59 -0700 Subject: [PATCH 038/215] rustc: Suppress derived pattern-match-checking errors typeck::check::_match wasn't suppressing derived errors properly. Fixed it. --- src/librustc/middle/typeck/check/_match.rs | 174 ++++++++++++--------- src/librustc/middle/typeck/infer/mod.rs | 25 +-- src/test/compile-fail/issue-5100.rs | 44 ++++++ 3 files changed, 164 insertions(+), 79 deletions(-) create mode 100644 src/test/compile-fail/issue-5100.rs diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 7f0066a1aa272..7d2fd51cefed7 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -175,11 +175,18 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, kind_name = "structure"; } _ => { - tcx.sess.span_fatal( - pat.span, - fmt!("mismatched types: expected `%s` but found enum or \ - structure", - fcx.infcx().ty_to_str(expected))); + let resolved_expected = + fcx.infcx().ty_to_str(fcx.infcx().resolve_type_vars_if_possible(expected)); + fcx.infcx().type_error_message_str(pat.span, + |actual| { + fmt!("mismatched types: expected `%s` but found %s", + resolved_expected, actual)}, + ~"an enum or structure pattern", + None); + fcx.write_error(pat.id); + kind_name = "[error]"; + arg_types = (copy subpats).get_or_default(~[]).map(|_| + ty::mk_err()); } } @@ -486,74 +493,44 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { } ast::pat_tup(ref elts) => { let s = structure_of(fcx, pat.span, expected); - let ex_elts = match s { - ty::ty_tup(ref elts) => elts, - _ => { - tcx.sess.span_fatal - (pat.span, - fmt!("mismatched types: expected `%s`, found tuple", - fcx.infcx().ty_to_str(expected))); - } - }; let e_count = elts.len(); - if e_count != ex_elts.len() { - tcx.sess.span_fatal - (pat.span, fmt!("mismatched types: expected a tuple \ - with %u fields, found one with %u \ - fields", ex_elts.len(), e_count)); - } - let mut i = 0u; - for elts.each |elt| { - check_pat(pcx, *elt, ex_elts[i]); - i += 1u; + match s { + ty::ty_tup(ref ex_elts) if e_count == ex_elts.len() => { + for elts.eachi |i, elt| { + check_pat(pcx, *elt, ex_elts[i]); + } + fcx.write_ty(pat.id, expected); + } + _ => { + for elts.each |elt| { + check_pat(pcx, *elt, ty::mk_err()); + } + let actual = ty::mk_tup(tcx, elts.map(|pat_var| { + fcx.node_ty(pat_var.id) + })); + // use terr_tuple_size if both types are tuples + let type_error = match s { + ty::ty_tup(ref ex_elts) => + ty::terr_tuple_size(ty::expected_found{expected: ex_elts.len(), + found: e_count}), + _ => ty::terr_mismatch + }; + fcx.infcx().report_mismatched_types(pat.span, + expected, + actual, + &type_error); + fcx.write_error(pat.id); + } } - - fcx.write_ty(pat.id, expected); } ast::pat_box(inner) => { - match structure_of(fcx, pat.span, expected) { - ty::ty_box(e_inner) => { - check_pat(pcx, inner, e_inner.ty); - fcx.write_ty(pat.id, expected); - } - _ => { - tcx.sess.span_fatal( - pat.span, - ~"mismatched types: expected `" + - fcx.infcx().ty_to_str(expected) + - ~"` found box"); - } - } + check_pointer_pat(pcx, At, inner, pat.id, pat.span, expected); } ast::pat_uniq(inner) => { - match structure_of(fcx, pat.span, expected) { - ty::ty_uniq(e_inner) => { - check_pat(pcx, inner, e_inner.ty); - fcx.write_ty(pat.id, expected); - } - _ => { - tcx.sess.span_fatal( - pat.span, - ~"mismatched types: expected `" + - fcx.infcx().ty_to_str(expected) + - ~"` found uniq"); - } - } + check_pointer_pat(pcx, Uniq, inner, pat.id, pat.span, expected); } ast::pat_region(inner) => { - match structure_of(fcx, pat.span, expected) { - ty::ty_rptr(_, e_inner) => { - check_pat(pcx, inner, e_inner.ty); - fcx.write_ty(pat.id, expected); - } - _ => { - tcx.sess.span_fatal( - pat.span, - ~"mismatched types: expected `" + - fcx.infcx().ty_to_str(expected) + - ~"` found borrowed pointer"); - } - } + check_pointer_pat(pcx, Borrowed, inner, pat.id, pat.span, expected); } ast::pat_vec(ref before, slice, ref after) => { let default_region_var = @@ -577,11 +554,25 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { (mt, default_region_var) }, _ => { - tcx.sess.span_fatal( - pat.span, - fmt!("mismatched type: expected `%s` but found vector", - fcx.infcx().ty_to_str(expected)) - ); + for before.each |&elt| { + check_pat(pcx, elt, ty::mk_err()); + } + for slice.each |&elt| { + check_pat(pcx, elt, ty::mk_err()); + } + for after.each |&elt| { + check_pat(pcx, elt, ty::mk_err()); + } + let resolved_expected = + fcx.infcx().ty_to_str(fcx.infcx().resolve_type_vars_if_possible(expected)); + fcx.infcx().type_error_message_str(pat.span, + |actual| { + fmt!("mismatched types: expected `%s` but found %s", + resolved_expected, actual)}, + ~"a vector pattern", + None); + fcx.write_error(pat.id); + return; } }; for before.each |elt| { @@ -605,3 +596,46 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { } } +// Helper function to check @, ~ and & patterns +pub fn check_pointer_pat(pcx: &pat_ctxt, + pointer_kind: PointerKind, + inner: @ast::pat, + pat_id: ast::node_id, + span: span, + expected: ty::t) { + let fcx = pcx.fcx; + let check_inner: &fn(ty::mt) = |e_inner| { + check_pat(pcx, inner, e_inner.ty); + fcx.write_ty(pat_id, expected); + }; + match structure_of(fcx, span, expected) { + ty::ty_box(e_inner) if pointer_kind == At => { + check_inner(e_inner); + } + ty::ty_uniq(e_inner) if pointer_kind == Uniq => { + check_inner(e_inner); + } + ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => { + check_inner(e_inner); + } + _ => { + check_pat(pcx, inner, ty::mk_err()); + let resolved_expected = + fcx.infcx().ty_to_str(fcx.infcx().resolve_type_vars_if_possible(expected)); + fcx.infcx().type_error_message_str(span, |actual| { + fmt!("mismatched types: expected `%s` but found %s", + resolved_expected, actual)}, + fmt!("an %s pattern", match pointer_kind { + At => "@-box", + Uniq => "~-box", + Borrowed => "&-pointer" + }), + None); + fcx.write_error(pat_id); + } + } +} + +#[deriving(Eq)] +enum PointerKind { At, Uniq, Borrowed } + diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 7b5a93d4cad88..8f709e7cd5af1 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -749,25 +749,32 @@ pub impl InferCtxt { } } - fn type_error_message(@mut self, sp: span, mk_msg: &fn(~str) -> ~str, - actual_ty: ty::t, err: Option<&ty::type_err>) { - let actual_ty = self.resolve_type_vars_if_possible(actual_ty); - // Don't report an error if actual type is ty_err. - if ty::type_is_error(actual_ty) { - return; - } + fn type_error_message_str(@mut self, sp: span, mk_msg: &fn(~str) -> ~str, + actual_ty: ~str, err: Option<&ty::type_err>) { let error_str = err.map_default(~"", |t_err| fmt!(" (%s)", ty::type_err_to_str(self.tcx, *t_err))); self.tcx.sess.span_err(sp, - fmt!("%s%s", mk_msg(self.ty_to_str(actual_ty)), - error_str)); + fmt!("%s%s", mk_msg(actual_ty), error_str)); for err.each |err| { ty::note_and_explain_type_err(self.tcx, *err) } } + fn type_error_message(@mut self, sp: span, mk_msg: &fn(~str) -> ~str, + actual_ty: ty::t, err: Option<&ty::type_err>) { + let actual_ty = self.resolve_type_vars_if_possible(actual_ty); + + // Don't report an error if actual type is ty_err. + if ty::type_is_error(actual_ty) { + return; + } + + self.type_error_message_str(sp, mk_msg, self.ty_to_str(actual_ty), + err); + } + fn report_mismatched_types(@mut self, sp: span, e: ty::t, a: ty::t, err: &ty::type_err) { let resolved_expected = diff --git a/src/test/compile-fail/issue-5100.rs b/src/test/compile-fail/issue-5100.rs new file mode 100644 index 0000000000000..dbfdb38f7211f --- /dev/null +++ b/src/test/compile-fail/issue-5100.rs @@ -0,0 +1,44 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +enum A { B, C } + +fn main() { + match (true, false) { + B => (), //~ ERROR expected `(bool,bool)` but found an enum or structure pattern + _ => () + } + + match (true, false) { + (true, false, false) => () //~ ERROR mismatched types: expected `(bool,bool)` but found `(bool,bool,bool)` (expected a tuple with 2 elements but found one with 3 elements) + } + + match (true, false) { + @(true, false) => () //~ ERROR mismatched types: expected `(bool,bool)` but found an @-box pattern + } + + match (true, false) { + ~(true, false) => () //~ ERROR mismatched types: expected `(bool,bool)` but found a ~-box pattern + } + + match (true, false) { + &(true, false) => () //~ ERROR mismatched types: expected `(bool,bool)` but found an &-pointer pattern + } + + + let v = [('a', 'b') //~ ERROR expected function but found `(char,char)` + ('c', 'd'), + ('e', 'f')]; + + for v.each |&(x,y)| {} // should be OK + + // Make sure none of the errors above were fatal + let x: char = true; //~ ERROR expected `char` but found `bool` +} From e75203ce82357f6d0f81d5644e77d3c2efe53fcb Mon Sep 17 00:00:00 2001 From: James Miller Date: Mon, 29 Apr 2013 14:54:41 +1200 Subject: [PATCH 039/215] Adds '--print-link-args' that outputs linker arguments that would be used --- src/librustc/back/link.rs | 176 ++++++++++++++++++--------------- src/librustc/driver/driver.rs | 13 ++- src/librustc/driver/session.rs | 5 + 3 files changed, 114 insertions(+), 80 deletions(-) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index aaa425c93348a..adaffe5873dab 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -747,6 +747,71 @@ pub fn link_binary(sess: Session, obj_filename: &Path, out_filename: &Path, lm: LinkMeta) { + // In the future, FreeBSD will use clang as default compiler. + // It would be flexible to use cc (system's default C compiler) + // instead of hard-coded gcc. + // For win32, there is no cc command, + // so we add a condition to make it use gcc. + let cc_prog: ~str = if sess.targ_cfg.os == session::os_android { + match &sess.opts.android_cross_path { + &Some(copy path) => { + fmt!("%s/bin/arm-linux-androideabi-gcc", path) + } + &None => { + sess.fatal(~"need Android NDK path for linking \ + (--android-cross-path)") + } + } + } else if sess.targ_cfg.os == session::os_win32 { ~"gcc" } + else { ~"cc" }; + // The invocations of cc share some flags across platforms + + + let output = if *sess.building_library { + let long_libname = output_dll_filename(sess.targ_cfg.os, lm); + debug!("link_meta.name: %s", lm.name); + debug!("long_libname: %s", long_libname); + debug!("out_filename: %s", out_filename.to_str()); + debug!("dirname(out_filename): %s", out_filename.dir_path().to_str()); + + out_filename.dir_path().push(long_libname) + } else { + /*bad*/copy *out_filename + }; + + debug!("output: %s", output.to_str()); + let mut cc_args = link_args(sess, obj_filename, out_filename, lm); + debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" ")); + // We run 'cc' here + let prog = run::program_output(cc_prog, cc_args); + if 0 != prog.status { + sess.err(fmt!("linking with `%s` failed with code %d", + cc_prog, prog.status)); + sess.note(fmt!("%s arguments: %s", + cc_prog, str::connect(cc_args, ~" "))); + sess.note(prog.err + prog.out); + sess.abort_if_errors(); + } + + // Clean up on Darwin + if sess.targ_cfg.os == session::os_macos { + run::run_program(~"dsymutil", ~[output.to_str()]); + } + + // Remove the temporary object file if we aren't saving temps + if !sess.opts.save_temps { + if ! os::remove_file(obj_filename) { + sess.warn(fmt!("failed to delete object file `%s`", + obj_filename.to_str())); + } + } +} + +pub fn link_args(sess: Session, + obj_filename: &Path, + out_filename: &Path, + lm:LinkMeta) -> ~[~str] { + // Converts a library file-stem into a cc -l argument fn unlib(config: @session::config, stem: ~str) -> ~str { if stem.starts_with("lib") && @@ -757,48 +822,23 @@ pub fn link_binary(sess: Session, } } + let output = if *sess.building_library { let long_libname = output_dll_filename(sess.targ_cfg.os, lm); - debug!("link_meta.name: %s", lm.name); - debug!("long_libname: %s", long_libname); - debug!("out_filename: %s", out_filename.to_str()); - debug!("dirname(out_filename): %s", out_filename.dir_path().to_str()); - out_filename.dir_path().push(long_libname) } else { /*bad*/copy *out_filename }; - debug!("output: %s", output.to_str()); - // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. let stage: ~str = ~"-L" + sess.filesearch.get_target_lib_path().to_str(); - // In the future, FreeBSD will use clang as default compiler. - // It would be flexible to use cc (system's default C compiler) - // instead of hard-coded gcc. - // For win32, there is no cc command, - // so we add a condition to make it use gcc. - let cc_prog: ~str = if sess.targ_cfg.os == session::os_android { - match &sess.opts.android_cross_path { - &Some(copy path) => { - fmt!("%s/bin/arm-linux-androideabi-gcc", path) - } - &None => { - sess.fatal(~"need Android NDK path for linking \ - (--android-cross-path)") - } - } - } else if sess.targ_cfg.os == session::os_win32 { ~"gcc" } - else { ~"cc" }; - // The invocations of cc share some flags across platforms + let mut args = vec::append(~[stage], sess.targ_cfg.target_strs.cc_args); - let mut cc_args = - vec::append(~[stage], sess.targ_cfg.target_strs.cc_args); - cc_args.push(~"-o"); - cc_args.push(output.to_str()); - cc_args.push(obj_filename.to_str()); + args.push(~"-o"); + args.push(output.to_str()); + args.push(obj_filename.to_str()); let lib_cmd; let os = sess.targ_cfg.os; @@ -813,23 +853,23 @@ pub fn link_binary(sess: Session, let cstore = sess.cstore; for cstore::get_used_crate_files(cstore).each |cratepath| { if cratepath.filetype() == Some(~".rlib") { - cc_args.push(cratepath.to_str()); + args.push(cratepath.to_str()); loop; } let dir = cratepath.dirname(); - if dir != ~"" { cc_args.push(~"-L" + dir); } + if dir != ~"" { args.push(~"-L" + dir); } let libarg = unlib(sess.targ_cfg, cratepath.filestem().get()); - cc_args.push(~"-l" + libarg); + args.push(~"-l" + libarg); } let ula = cstore::get_used_link_args(cstore); - for ula.each |arg| { cc_args.push(/*bad*/copy *arg); } + for ula.each |arg| { args.push(/*bad*/copy *arg); } // Add all the link args for external crates. do cstore::iter_crate_data(cstore) |crate_num, _| { let link_args = csearch::get_link_args_for_crate(cstore, crate_num); do vec::consume(link_args) |_, link_arg| { - cc_args.push(link_arg); + args.push(link_arg); } } @@ -842,20 +882,20 @@ pub fn link_binary(sess: Session, // forces to make sure that library can be found at runtime. for sess.opts.addl_lib_search_paths.each |path| { - cc_args.push(~"-L" + path.to_str()); + args.push(~"-L" + path.to_str()); } // The names of the extern libraries let used_libs = cstore::get_used_libraries(cstore); - for used_libs.each |l| { cc_args.push(~"-l" + *l); } + for used_libs.each |l| { args.push(~"-l" + *l); } if *sess.building_library { - cc_args.push(lib_cmd); + args.push(lib_cmd); // On mac we need to tell the linker to let this library // be rpathed if sess.targ_cfg.os == session::os_macos { - cc_args.push(~"-Wl,-install_name,@rpath/" + args.push(~"-Wl,-install_name,@rpath/" + output.filename().get()); } } @@ -863,27 +903,27 @@ pub fn link_binary(sess: Session, // On linux librt and libdl are an indirect dependencies via rustrt, // and binutils 2.22+ won't add them automatically if sess.targ_cfg.os == session::os_linux { - cc_args.push_all(~[~"-lrt", ~"-ldl"]); + args.push_all(~[~"-lrt", ~"-ldl"]); // LLVM implements the `frem` instruction as a call to `fmod`, // which lives in libm. Similar to above, on some linuxes we // have to be explicit about linking to it. See #2510 - cc_args.push(~"-lm"); + args.push(~"-lm"); } else if sess.targ_cfg.os == session::os_android { - cc_args.push_all(~[~"-ldl", ~"-llog", ~"-lsupc++", + args.push_all(~[~"-ldl", ~"-llog", ~"-lsupc++", ~"-lgnustl_shared"]); - cc_args.push(~"-lm"); + args.push(~"-lm"); } if sess.targ_cfg.os == session::os_freebsd { - cc_args.push_all(~[~"-pthread", ~"-lrt", - ~"-L/usr/local/lib", ~"-lexecinfo", - ~"-L/usr/local/lib/gcc46", - ~"-L/usr/local/lib/gcc44", ~"-lstdc++", - ~"-Wl,-z,origin", - ~"-Wl,-rpath,/usr/local/lib/gcc46", - ~"-Wl,-rpath,/usr/local/lib/gcc44"]); + args.push_all(~[~"-pthread", ~"-lrt", + ~"-L/usr/local/lib", ~"-lexecinfo", + ~"-L/usr/local/lib/gcc46", + ~"-L/usr/local/lib/gcc44", ~"-lstdc++", + ~"-Wl,-z,origin", + ~"-Wl,-rpath,/usr/local/lib/gcc46", + ~"-Wl,-rpath,/usr/local/lib/gcc44"]); } // OS X 10.6 introduced 'compact unwind info', which is produced by the @@ -891,47 +931,25 @@ pub fn link_binary(sess: Session, // understand how to unwind our __morestack frame, so we have to turn it // off. This has impacted some other projects like GHC. if sess.targ_cfg.os == session::os_macos { - cc_args.push(~"-Wl,-no_compact_unwind"); + args.push(~"-Wl,-no_compact_unwind"); } // Stack growth requires statically linking a __morestack function - cc_args.push(~"-lmorestack"); + args.push(~"-lmorestack"); // Always want the runtime linked in - cc_args.push(~"-lrustrt"); + args.push(~"-lrustrt"); // FIXME (#2397): At some point we want to rpath our guesses as to where // extern libraries might live, based on the addl_lib_search_paths - cc_args.push_all(rpath::get_rpath_flags(sess, &output)); + args.push_all(rpath::get_rpath_flags(sess, &output)); // Finally add all the linker arguments provided on the command line - cc_args.push_all(sess.opts.linker_args); - - debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" ")); - // We run 'cc' here - let prog = run::program_output(cc_prog, cc_args); - if 0 != prog.status { - sess.err(fmt!("linking with `%s` failed with code %d", - cc_prog, prog.status)); - sess.note(fmt!("%s arguments: %s", - cc_prog, str::connect(cc_args, ~" "))); - sess.note(prog.err + prog.out); - sess.abort_if_errors(); - } + args.push_all(sess.opts.linker_args); - // Clean up on Darwin - if sess.targ_cfg.os == session::os_macos { - run::run_program(~"dsymutil", ~[output.to_str()]); - } - - // Remove the temporary object file if we aren't saving temps - if !sess.opts.save_temps { - if ! os::remove_file(obj_filename) { - sess.warn(fmt!("failed to delete object file `%s`", - obj_filename.to_str())); - } - } + return args; } + // // Local Variables: // mode: rust diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index fbcbd4461ac10..102b663161096 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -234,7 +234,6 @@ pub fn compile_rest(sess: Session, let rp_set = time(time_passes, ~"region parameterization inference", || middle::region::determine_rp_in_crate(sess, ast_map, def_map, crate)); - let outputs = outputs.get(); let (llmod, link_meta) = { @@ -309,6 +308,11 @@ pub fn compile_rest(sess: Session, }; + if (sess.opts.output_info & session::out_link_args) > 0 { + io::println(str::connect(link::link_args(sess, + &outputs.obj_filename, &outputs.out_filename, link_meta), " ")); + } + // NB: Android hack if sess.targ_cfg.arch == abi::Arm && (sess.opts.output_type == link::output_type_object || @@ -659,6 +663,12 @@ pub fn build_session_options(binary: @~str, let test = opt_present(matches, ~"test"); let android_cross_path = getopts::opt_maybe_str( matches, ~"android-cross-path"); + + let mut output_info = 0; + if opt_present(matches, "print-link-args") { + output_info |= session::out_link_args; + } + let sopts = @session::options { crate_type: crate_type, is_static: static, @@ -681,6 +691,7 @@ pub fn build_session_options(binary: @~str, parse_only: parse_only, no_trans: no_trans, debugging_opts: debugging_opts, + output_info: output_info, android_cross_path: android_cross_path }; return sopts; diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 94d1da20f9268..19b99f46b5ed5 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -100,6 +100,9 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { ] } +// Information output flags +pub static out_link_args : uint = 1 << 0; + #[deriving(Eq)] pub enum OptLevel { No, // -O0 @@ -136,6 +139,7 @@ pub struct options { parse_only: bool, no_trans: bool, debugging_opts: uint, + output_info: uint, android_cross_path: Option<~str> } @@ -310,6 +314,7 @@ pub fn basic_options() -> @options { parse_only: false, no_trans: false, debugging_opts: 0u, + output_info: 0u, android_cross_path: None } } From c1fdace588034ae76f7ccb920ddadd9c2722a5cd Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 29 Apr 2013 13:35:32 -0700 Subject: [PATCH 040/215] core: Replace uses of 'drop' in task module with 'finally'. #5379 --- src/libcore/task/mod.rs | 77 +++++++++++------------------------------ 1 file changed, 21 insertions(+), 56 deletions(-) diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 2163a0e325f13..c093dfd2644a1 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -42,6 +42,7 @@ use result; use task::rt::{task_id, sched_id, rust_task}; use util; use util::replace; +use unstable::finally::Finally; #[cfg(test)] use comm::SharedChan; @@ -591,48 +592,24 @@ pub fn get_scheduler() -> Scheduler { * ~~~ */ pub unsafe fn unkillable(f: &fn() -> U) -> U { - struct AllowFailure { - t: *rust_task, - drop { - unsafe { - rt::rust_task_allow_kill(self.t); - } - } - } - - fn AllowFailure(t: *rust_task) -> AllowFailure{ - AllowFailure { - t: t - } - } - let t = rt::rust_get_task(); - let _allow_failure = AllowFailure(t); - rt::rust_task_inhibit_kill(t); - f() + do (|| { + rt::rust_task_inhibit_kill(t); + f() + }).finally { + rt::rust_task_allow_kill(t); + } } /// The inverse of unkillable. Only ever to be used nested in unkillable(). pub unsafe fn rekillable(f: &fn() -> U) -> U { - struct DisallowFailure { - t: *rust_task, - drop { - unsafe { - rt::rust_task_inhibit_kill(self.t); - } - } - } - - fn DisallowFailure(t: *rust_task) -> DisallowFailure { - DisallowFailure { - t: t - } - } - let t = rt::rust_get_task(); - let _allow_failure = DisallowFailure(t); - rt::rust_task_allow_kill(t); - f() + do (|| { + rt::rust_task_allow_kill(t); + f() + }).finally { + rt::rust_task_inhibit_kill(t); + } } /** @@ -640,27 +617,15 @@ pub unsafe fn rekillable(f: &fn() -> U) -> U { * For use with exclusive ARCs, which use pthread mutexes directly. */ pub unsafe fn atomically(f: &fn() -> U) -> U { - struct DeferInterrupts { - t: *rust_task, - drop { - unsafe { - rt::rust_task_allow_yield(self.t); - rt::rust_task_allow_kill(self.t); - } - } - } - - fn DeferInterrupts(t: *rust_task) -> DeferInterrupts { - DeferInterrupts { - t: t - } - } - let t = rt::rust_get_task(); - let _interrupts = DeferInterrupts(t); - rt::rust_task_inhibit_kill(t); - rt::rust_task_inhibit_yield(t); - f() + do (|| { + rt::rust_task_inhibit_kill(t); + rt::rust_task_inhibit_yield(t); + f() + }).finally { + rt::rust_task_allow_yield(t); + rt::rust_task_allow_kill(t); + } } #[test] #[should_fail] #[ignore(cfg(windows))] From d8024e2c3b89b3ad517b76a5495f2bcb2d6a7690 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Mon, 29 Apr 2013 14:23:22 -0700 Subject: [PATCH 041/215] rustc: Change At to Managed and Uniq to Owned --- src/librustc/middle/typeck/check/_match.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 7d2fd51cefed7..e73cf440d4071 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -524,10 +524,10 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { } } ast::pat_box(inner) => { - check_pointer_pat(pcx, At, inner, pat.id, pat.span, expected); + check_pointer_pat(pcx, Managed, inner, pat.id, pat.span, expected); } ast::pat_uniq(inner) => { - check_pointer_pat(pcx, Uniq, inner, pat.id, pat.span, expected); + check_pointer_pat(pcx, Owned, inner, pat.id, pat.span, expected); } ast::pat_region(inner) => { check_pointer_pat(pcx, Borrowed, inner, pat.id, pat.span, expected); @@ -609,10 +609,10 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, fcx.write_ty(pat_id, expected); }; match structure_of(fcx, span, expected) { - ty::ty_box(e_inner) if pointer_kind == At => { + ty::ty_box(e_inner) if pointer_kind == Managed => { check_inner(e_inner); } - ty::ty_uniq(e_inner) if pointer_kind == Uniq => { + ty::ty_uniq(e_inner) if pointer_kind == Owned => { check_inner(e_inner); } ty::ty_rptr(_, e_inner) if pointer_kind == Borrowed => { @@ -626,8 +626,8 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, fmt!("mismatched types: expected `%s` but found %s", resolved_expected, actual)}, fmt!("an %s pattern", match pointer_kind { - At => "@-box", - Uniq => "~-box", + Managed => "@-box", + Owned => "~-box", Borrowed => "&-pointer" }), None); @@ -637,5 +637,5 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, } #[deriving(Eq)] -enum PointerKind { At, Uniq, Borrowed } +enum PointerKind { Managed, Owned, Borrowed } From 6818e241b49c03c0fe0994dbe8340e2d8f482f09 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 29 Apr 2013 16:44:21 -0700 Subject: [PATCH 042/215] core: Turn off the local heap in newsched in stage0 to work around windows bustage core won't compile in stage0 without. --- src/libcore/unstable/lang.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index bf3bf5adc0ac5..cb3f399f5919a 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -90,6 +90,14 @@ pub unsafe fn exchange_free(ptr: *c_char) { #[lang="malloc"] #[inline(always)] +#[cfg(stage0)] // For some reason this isn't working on windows in stage0 +pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { + return rustrt::rust_upcall_malloc_noswitch(td, size); +} + +#[lang="malloc"] +#[inline(always)] +#[cfg(not(stage0))] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { match context() { OldTaskContext => { @@ -110,6 +118,17 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { // problem occurs, call exit instead. #[lang="free"] #[inline(always)] +#[cfg(stage0)] +pub unsafe fn local_free(ptr: *c_char) { + rustrt::rust_upcall_free_noswitch(ptr); +} + +// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from +// inside a landing pad may corrupt the state of the exception handler. If a +// problem occurs, call exit instead. +#[lang="free"] +#[inline(always)] +#[cfg(not(stage0))] pub unsafe fn local_free(ptr: *c_char) { match context() { OldTaskContext => { From 9ddcf1cdd3f90366858c7e2746aedd726b477ea3 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 29 Apr 2013 17:11:20 -0700 Subject: [PATCH 043/215] test: Remove run-pass/too-much-recursion.rs I don't understand how this is still passing on the bots. This condition should trigger an abort now. --- src/test/run-pass/too-much-recursion.rs | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 src/test/run-pass/too-much-recursion.rs diff --git a/src/test/run-pass/too-much-recursion.rs b/src/test/run-pass/too-much-recursion.rs deleted file mode 100644 index adccc786926dc..0000000000000 --- a/src/test/run-pass/too-much-recursion.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-win32 -// error-pattern:ran out of stack - -// Test that the task fails after hitting the recursion limit, but -// that it doesn't bring down the whole proc - -pub fn main() { - do task::spawn_unlinked { - fn f() { f() }; - f(); - }; -} From c2b8f98917597dd719ad93b25dcf000aeaa6d5d0 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Mon, 29 Apr 2013 19:48:28 -0700 Subject: [PATCH 044/215] librustc: Fix drop finalizer not running for newtype structs. --- src/librustc/middle/trans/base.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index efa10dfc2aa34..892a8da367c9f 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2071,6 +2071,7 @@ pub fn trans_tuple_struct(ccx: @CrateContext, let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys); let repr = adt::represent_type(ccx, tup_ty); + adt::trans_start_init(bcx, repr, fcx.llretptr.get(), 0); for fields.eachi |i, field| { let lldestptr = adt::trans_field_ptr(bcx, From 849f8142a244ae08c06ed190c234aa809a68f6c0 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Mon, 29 Apr 2013 20:46:54 -0700 Subject: [PATCH 045/215] rustc / test: Fix error message --- src/librustc/middle/typeck/check/_match.rs | 8 ++++---- src/test/compile-fail/alt-vec-mismatch-2.rs | 2 +- src/test/compile-fail/alt-vec-mismatch.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index e73cf440d4071..5ff7105712183 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -625,10 +625,10 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, fcx.infcx().type_error_message_str(span, |actual| { fmt!("mismatched types: expected `%s` but found %s", resolved_expected, actual)}, - fmt!("an %s pattern", match pointer_kind { - Managed => "@-box", - Owned => "~-box", - Borrowed => "&-pointer" + fmt!("%s pattern", match pointer_kind { + Managed => "an @-box", + Owned => "a ~-box", + Borrowed => "an &-pointer" }), None); fcx.write_error(pat_id); diff --git a/src/test/compile-fail/alt-vec-mismatch-2.rs b/src/test/compile-fail/alt-vec-mismatch-2.rs index 9e8fb84951d30..bef18cc666ae6 100644 --- a/src/test/compile-fail/alt-vec-mismatch-2.rs +++ b/src/test/compile-fail/alt-vec-mismatch-2.rs @@ -1,5 +1,5 @@ fn main() { match () { - [()] => { } //~ ERROR mismatched type: expected `()` but found vector + [()] => { } //~ ERROR mismatched type: expected `()` but found a vector pattern } } diff --git a/src/test/compile-fail/alt-vec-mismatch.rs b/src/test/compile-fail/alt-vec-mismatch.rs index ef4d92ea4913b..1f6822cfd2ce5 100644 --- a/src/test/compile-fail/alt-vec-mismatch.rs +++ b/src/test/compile-fail/alt-vec-mismatch.rs @@ -1,6 +1,6 @@ fn main() { match ~"foo" { - ['f', 'o', .._] => { } //~ ERROR mismatched type: expected `~str` but found vector + ['f', 'o', .._] => { } //~ ERROR mismatched type: expected `~str` but found a vector pattern _ => { } } } From 2deefbe847e68c8fa749ae59d7e84e1a80eba452 Mon Sep 17 00:00:00 2001 From: James Miller Date: Tue, 30 Apr 2013 20:05:16 +1200 Subject: [PATCH 046/215] Change flags to -Z print-link-args and --link-args --- src/librustc/driver/driver.rs | 14 +++----------- src/librustc/driver/session.rs | 7 ++----- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 102b663161096..0a91c29d89071 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -308,7 +308,7 @@ pub fn compile_rest(sess: Session, }; - if (sess.opts.output_info & session::out_link_args) > 0 { + if (sess.opts.debugging_opts & session::print_link_args) != 0 { io::println(str::connect(link::link_args(sess, &outputs.obj_filename, &outputs.out_filename, link_meta), " ")); } @@ -651,7 +651,7 @@ pub fn build_session_options(binary: @~str, let addl_lib_search_paths = getopts::opt_strs(matches, ~"L").map(|s| Path(*s)); - let linker_args = getopts::opt_strs(matches, ~"linker").flat_map( |a| { + let linker_args = getopts::opt_strs(matches, ~"link-args").flat_map( |a| { let mut args = ~[]; for str::each_split_char(*a, ',') |arg| { args.push(str::from_slice(arg)); @@ -664,11 +664,6 @@ pub fn build_session_options(binary: @~str, let android_cross_path = getopts::opt_maybe_str( matches, ~"android-cross-path"); - let mut output_info = 0; - if opt_present(matches, "print-link-args") { - output_info |= session::out_link_args; - } - let sopts = @session::options { crate_type: crate_type, is_static: static, @@ -691,7 +686,6 @@ pub fn build_session_options(binary: @~str, parse_only: parse_only, no_trans: no_trans, debugging_opts: debugging_opts, - output_info: output_info, android_cross_path: android_cross_path }; return sopts; @@ -766,7 +760,7 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] { optmulti("L", "", "Add a directory to the library search path", "PATH"), optflag("", "lib", "Compile a library crate"), - optmulti("", "linker", "FLAGS is a comma-separated list of flags + optmulti("", "link-args", "FLAGS is a comma-separated list of flags passed to the linker", "FLAGS"), optflag("", "ls", "List the symbols defined by a library crate"), optflag("", "no-trans", @@ -787,8 +781,6 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] { typed (crates expanded, with type annotations), or identified (fully parenthesized, AST nodes and blocks with IDs)", "TYPE"), - optflag("", "print-link-args", "Prints all the arguments that would be - passed to the linker."), optflag("S", "", "Compile only; do not assemble or link"), optflag("", "save-temps", "Write intermediate files (.bc, .opt.bc, .o) diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 19b99f46b5ed5..ff623049f758d 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -63,6 +63,7 @@ pub static jit: uint = 1 << 19; pub static debug_info: uint = 1 << 20; pub static extra_debug_info: uint = 1 << 21; pub static static: uint = 1 << 22; +pub static print_link_args: uint = 1 << 23; pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { ~[(~"verbose", ~"in general, enable more debug printouts", verbose), @@ -90,6 +91,7 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { (~"no-opt", ~"do not optimize, even if -O is passed", no_opt), (~"no-monomorphic-collapse", ~"do not collapse template instantiations", no_monomorphic_collapse), + (~"print-link-args", ~"Print the arguments passed to the linker", print_link_args), (~"gc", ~"Garbage collect shared data (experimental)", gc), (~"jit", ~"Execute using JIT (experimental)", jit), (~"extra-debug-info", ~"Extra debugging info (experimental)", @@ -100,9 +102,6 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { ] } -// Information output flags -pub static out_link_args : uint = 1 << 0; - #[deriving(Eq)] pub enum OptLevel { No, // -O0 @@ -139,7 +138,6 @@ pub struct options { parse_only: bool, no_trans: bool, debugging_opts: uint, - output_info: uint, android_cross_path: Option<~str> } @@ -314,7 +312,6 @@ pub fn basic_options() -> @options { parse_only: false, no_trans: false, debugging_opts: 0u, - output_info: 0u, android_cross_path: None } } From 84e97d5596fdc665036646f715f4ffd030d9031f Mon Sep 17 00:00:00 2001 From: Sangeun Kim Date: Tue, 30 Apr 2013 18:39:16 +0900 Subject: [PATCH 047/215] I modified the doc of from_elem, from_fn, I think it returns an owned vector --- src/libcore/vec.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 86767dc5bad85..081efe48e1eb5 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -137,9 +137,9 @@ pub fn uniq_len(v: &const ~[T]) -> uint { } /** - * Creates and initializes an immutable vector. + * Creates and initializes an owned vector. * - * Creates an immutable vector of size `n_elts` and initializes the elements + * Creates an owned vector of size `n_elts` and initializes the elements * to the value returned by the function `op`. */ pub fn from_fn(n_elts: uint, op: old_iter::InitOp) -> ~[T] { @@ -159,9 +159,9 @@ pub fn from_fn(n_elts: uint, op: old_iter::InitOp) -> ~[T] { } /** - * Creates and initializes an immutable vector. + * Creates and initializes an owned vector. * - * Creates an immutable vector of size `n_elts` and initializes the elements + * Creates an owned vector of size `n_elts` and initializes the elements * to the value `t`. */ pub fn from_elem(n_elts: uint, t: T) -> ~[T] { From 202b8dcdc420d8b109fbd5260ea2e2be0a5b7faf Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 17 Apr 2013 18:05:17 -0400 Subject: [PATCH 048/215] adapt to snapshot --- src/libcore/container.rs | 36 ----- src/libcore/hashmap.rs | 168 ------------------------ src/libcore/option.rs | 104 --------------- src/libcore/reflect.rs | 33 +---- src/libcore/repr.rs | 110 +--------------- src/libcore/result.rs | 7 - src/libcore/rt/mod.rs | 21 --- src/libcore/rt/rtio.rs | 5 - src/libcore/rt/uvio.rs | 16 --- src/libcore/trie.rs | 95 -------------- src/libcore/tuple.rs | 28 ---- src/libcore/unstable/lang.rs | 26 ---- src/libcore/vec.rs | 217 ------------------------------- src/librustc/middle/astencode.rs | 104 --------------- src/librustc/rustc.rc | 1 + src/libstd/arena.rs | 56 -------- src/libstd/deque.rs | 122 ----------------- src/libstd/ebml.rs | 18 --- src/libstd/future.rs | 29 ----- src/libstd/json.rs | 48 ------- src/libstd/priority_queue.rs | 16 --- src/libstd/serialize.rs | 10 -- src/libstd/smallintmap.rs | 77 ----------- src/libsyntax/ext/base.rs | 11 -- src/libsyntax/opt_vec.rs | 9 -- 25 files changed, 3 insertions(+), 1364 deletions(-) diff --git a/src/libcore/container.rs b/src/libcore/container.rs index 88c78aebfc5c7..00ea4a9322111 100644 --- a/src/libcore/container.rs +++ b/src/libcore/container.rs @@ -25,42 +25,6 @@ pub trait Mutable: Container { fn clear(&mut self); } -#[cfg(stage0)] -pub trait Map: Mutable { - /// Return true if the map contains a value for the specified key - fn contains_key(&self, key: &K) -> bool; - - // Visits all keys and values - fn each(&self, f: &fn(&K, &V) -> bool); - - /// Visit all keys - fn each_key(&self, f: &fn(&K) -> bool); - - /// Visit all values - fn each_value(&self, f: &fn(&V) -> bool); - - /// Iterate over the map and mutate the contained values - fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool); - - /// Return a reference to the value corresponding to the key - fn find(&self, key: &K) -> Option<&'self V>; - - /// Return a mutable reference to the value corresponding to the key - fn find_mut(&mut self, key: &K) -> Option<&'self mut V>; - - /// Insert a key-value pair into the map. An existing value for a - /// key is replaced by the new value. Return true if the key did - /// not already exist in the map. - fn insert(&mut self, key: K, value: V) -> bool; - - /// Remove a key-value pair from the map. Return true if the key - /// was present in the map, otherwise false. - fn remove(&mut self, key: &K) -> bool; -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub trait Map: Mutable { /// Return true if the map contains a value for the specified key fn contains_key(&self, key: &K) -> bool; diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index 41f4f34dc1971..ad1994a92d2bb 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -184,18 +184,6 @@ priv impl HashMap { } } - #[cfg(stage0)] - #[inline(always)] - fn value_for_bucket(&self, idx: uint) -> &'self V { - match self.buckets[idx] { - Some(ref bkt) => &bkt.value, - None => fail!(~"HashMap::find: internal logic error"), - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn value_for_bucket<'a>(&'a self, idx: uint) -> &'a V { match self.buckets[idx] { @@ -204,18 +192,6 @@ priv impl HashMap { } } - #[cfg(stage0)] - #[inline(always)] - fn mut_value_for_bucket(&mut self, idx: uint) -> &'self mut V { - match self.buckets[idx] { - Some(ref mut bkt) => &mut bkt.value, - None => unreachable() - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn mut_value_for_bucket<'a>(&'a mut self, idx: uint) -> &'a mut V { match self.buckets[idx] { @@ -329,21 +305,6 @@ impl Map for HashMap { } /// Visit all key-value pairs - #[cfg(stage0)] - fn each(&self, blk: &fn(&'self K, &'self V) -> bool) { - for uint::range(0, self.buckets.len()) |i| { - for self.buckets[i].each |bucket| { - if !blk(&bucket.key, &bucket.value) { - return; - } - } - } - } - - /// Visit all key-value pairs - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each<'a>(&'a self, blk: &fn(&'a K, &'a V) -> bool) { for uint::range(0, self.buckets.len()) |i| { for self.buckets[i].each |bucket| { @@ -360,15 +321,6 @@ impl Map for HashMap { } /// Visit all values - #[cfg(stage0)] - fn each_value(&self, blk: &fn(v: &V) -> bool) { - self.each(|_, v| blk(v)) - } - - /// Visit all values - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each_value<'a>(&'a self, blk: &fn(v: &'a V) -> bool) { self.each(|_, v| blk(v)) } @@ -386,18 +338,6 @@ impl Map for HashMap { } /// Return a reference to the value corresponding to the key - #[cfg(stage0)] - fn find(&self, k: &K) -> Option<&'self V> { - match self.bucket_for_key(k) { - FoundEntry(idx) => Some(self.value_for_bucket(idx)), - TableFull | FoundHole(_) => None, - } - } - - /// Return a reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find<'a>(&'a self, k: &K) -> Option<&'a V> { match self.bucket_for_key(k) { FoundEntry(idx) => Some(self.value_for_bucket(idx)), @@ -406,21 +346,6 @@ impl Map for HashMap { } /// Return a mutable reference to the value corresponding to the key - #[cfg(stage0)] - fn find_mut(&mut self, k: &K) -> Option<&'self mut V> { - let idx = match self.bucket_for_key(k) { - FoundEntry(idx) => idx, - TableFull | FoundHole(_) => return None - }; - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker - Some(::cast::transmute_mut_region(self.mut_value_for_bucket(idx))) - } - } - - /// Return a mutable reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find_mut<'a>(&'a mut self, k: &K) -> Option<&'a mut V> { let idx = match self.bucket_for_key(k) { FoundEntry(idx) => idx, @@ -503,40 +428,6 @@ pub impl HashMap { /// Return the value corresponding to the key in the map, or insert /// and return the value if it doesn't exist. - #[cfg(stage0)] - fn find_or_insert(&mut self, k: K, v: V) -> &'self V { - if self.size >= self.resize_at { - // n.b.: We could also do this after searching, so - // that we do not resize if this call to insert is - // simply going to update a key in place. My sense - // though is that it's worse to have to search through - // buckets to find the right spot twice than to just - // resize in this corner case. - self.expand(); - } - - let hash = k.hash_keyed(self.k0, self.k1) as uint; - let idx = match self.bucket_for_key_with_hash(hash, &k) { - TableFull => fail!(~"Internal logic error"), - FoundEntry(idx) => idx, - FoundHole(idx) => { - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); - self.size += 1; - idx - }, - }; - - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker - ::cast::transmute_region(self.value_for_bucket(idx)) - } - } - - /// Return the value corresponding to the key in the map, or insert - /// and return the value if it doesn't exist. - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a V { if self.size >= self.resize_at { // n.b.: We could also do this after searching, so @@ -567,41 +458,6 @@ pub impl HashMap { /// Return the value corresponding to the key in the map, or create, /// insert, and return a new value if it doesn't exist. - #[cfg(stage0)] - fn find_or_insert_with(&mut self, k: K, f: &fn(&K) -> V) -> &'self V { - if self.size >= self.resize_at { - // n.b.: We could also do this after searching, so - // that we do not resize if this call to insert is - // simply going to update a key in place. My sense - // though is that it's worse to have to search through - // buckets to find the right spot twice than to just - // resize in this corner case. - self.expand(); - } - - let hash = k.hash_keyed(self.k0, self.k1) as uint; - let idx = match self.bucket_for_key_with_hash(hash, &k) { - TableFull => fail!(~"Internal logic error"), - FoundEntry(idx) => idx, - FoundHole(idx) => { - let v = f(&k); - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); - self.size += 1; - idx - }, - }; - - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker - ::cast::transmute_region(self.value_for_bucket(idx)) - } - } - - /// Return the value corresponding to the key in the map, or create, - /// insert, and return a new value if it doesn't exist. - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V) -> &'a V { if self.size >= self.resize_at { // n.b.: We could also do this after searching, so @@ -647,17 +503,6 @@ pub impl HashMap { } } - #[cfg(stage0)] - fn get(&self, k: &K) -> &'self V { - match self.find(k) { - Some(v) => v, - None => fail!(fmt!("No entry found for key: %?", k)), - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get<'a>(&'a self, k: &K) -> &'a V { match self.find(k) { Some(v) => v, @@ -676,19 +521,6 @@ pub impl HashMap { /// Return the value corresponding to the key in the map, using /// equivalence - #[cfg(stage0)] - fn find_equiv>(&self, k: &Q) -> Option<&'self V> { - match self.bucket_for_key_equiv(k) { - FoundEntry(idx) => Some(self.value_for_bucket(idx)), - TableFull | FoundHole(_) => None, - } - } - - /// Return the value corresponding to the key in the map, using - /// equivalence - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find_equiv<'a, Q:Hash + Equiv>(&'a self, k: &Q) -> Option<&'a V> { match self.bucket_for_key_equiv(k) { FoundEntry(idx) => Some(self.value_for_bucket(idx)), diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 17192b4257b16..5abf376ddde65 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -100,16 +100,6 @@ impl> Add, Option> for Option { impl BaseIter for Option { /// Performs an operation on the contained value by reference - #[cfg(stage0)] - #[inline(always)] - fn each(&self, f: &fn(x: &'self T) -> bool) { - match *self { None => (), Some(ref t) => { f(t); } } - } - - /// Performs an operation on the contained value by reference - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn each<'a>(&'a self, f: &fn(x: &'a T) -> bool) { match *self { None => (), Some(ref t) => { f(t); } } @@ -122,15 +112,6 @@ impl BaseIter for Option { } impl MutableIter for Option { - #[cfg(stage0)] - #[inline(always)] - fn each_mut(&mut self, f: &fn(&'self mut T) -> bool) { - match *self { None => (), Some(ref mut t) => { f(t); } } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn each_mut<'a>(&'a mut self, f: &fn(&'a mut T) -> bool) { match *self { None => (), Some(ref mut t) => { f(t); } } @@ -200,35 +181,12 @@ pub impl Option { * Update an optional value by optionally running its content by reference * through a function that returns an option. */ - #[cfg(stage0)] - #[inline(always)] - fn chain_ref(&self, f: &fn(x: &'self T) -> Option) -> Option { - match *self { Some(ref x) => f(x), None => None } - } - - /** - * Update an optional value by optionally running its content by reference - * through a function that returns an option. - */ - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn chain_ref<'a, U>(&'a self, f: &fn(x: &'a T) -> Option) -> Option { match *self { Some(ref x) => f(x), None => None } } /// Maps a `some` value from one type to another by reference - #[cfg(stage0)] - #[inline(always)] - fn map(&self, f: &fn(&'self T) -> U) -> Option { - match *self { Some(ref x) => Some(f(x)), None => None } - } - - /// Maps a `some` value from one type to another by reference - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn map<'a, U>(&self, f: &fn(&'a T) -> U) -> Option { match *self { Some(ref x) => Some(f(x)), None => None } @@ -242,16 +200,6 @@ pub impl Option { } /// Applies a function to the contained value or returns a default - #[cfg(stage0)] - #[inline(always)] - fn map_default(&self, def: U, f: &fn(&'self T) -> U) -> U { - match *self { None => def, Some(ref t) => f(t) } - } - - /// Applies a function to the contained value or returns a default - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn map_default<'a, U>(&'a self, def: U, f: &fn(&'a T) -> U) -> U { match *self { None => def, Some(ref t) => f(t) } @@ -295,32 +243,6 @@ pub impl Option { case explicitly. */ #[inline(always)] - #[cfg(stage0)] - fn get_ref(&self) -> &'self T { - match *self { - Some(ref x) => x, - None => fail!(~"option::get_ref none") - } - } - - /** - Gets an immutable reference to the value inside an option. - - # Failure - - Fails if the value equals `None` - - # Safety note - - In general, because this function may fail, its use is discouraged - (calling `get` on `None` is akin to dereferencing a null pointer). - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get_ref<'a>(&'a self) -> &'a T { match *self { Some(ref x) => x, @@ -343,32 +265,6 @@ pub impl Option { case explicitly. */ #[inline(always)] - #[cfg(stage0)] - fn get_mut_ref(&mut self) -> &'self mut T { - match *self { - Some(ref mut x) => x, - None => fail!(~"option::get_mut_ref none") - } - } - - /** - Gets a mutable reference to the value inside an option. - - # Failure - - Fails if the value equals `None` - - # Safety note - - In general, because this function may fail, its use is discouraged - (calling `get` on `None` is akin to dereferencing a null pointer). - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get_mut_ref<'a>(&'a mut self) -> &'a mut T { match *self { Some(ref mut x) => x, diff --git a/src/libcore/reflect.rs b/src/libcore/reflect.rs index 9a0526b4351ba..47de360f58995 100644 --- a/src/libcore/reflect.rs +++ b/src/libcore/reflect.rs @@ -15,7 +15,7 @@ Runtime type reflection */ use intrinsic::{TyDesc, TyVisitor}; -#[cfg(not(stage0))] use intrinsic::Opaque; +use intrinsic::Opaque; use libc::c_void; use sys; use vec; @@ -394,17 +394,6 @@ impl TyVisitor for MovePtrAdaptor { true } - #[cfg(stage0)] - fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint) - -> bool { - self.align(align); - if ! self.inner.visit_enter_enum(n_variants, sz, align) { - return false; - } - true - } - - #[cfg(not(stage0))] fn visit_enter_enum(&self, n_variants: uint, get_disr: extern unsafe fn(ptr: *Opaque) -> int, sz: uint, align: uint) @@ -428,15 +417,6 @@ impl TyVisitor for MovePtrAdaptor { true } - #[cfg(stage0)] - fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { - unsafe { self.align((*inner).align); } - if ! self.inner.visit_enum_variant_field(i, inner) { return false; } - unsafe { self.bump((*inner).size); } - true - } - - #[cfg(not(stage0))] fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool { self.inner.push_ptr(); self.bump(offset); @@ -457,17 +437,6 @@ impl TyVisitor for MovePtrAdaptor { true } - #[cfg(stage0)] - fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint) - -> bool { - if ! self.inner.visit_leave_enum(n_variants, sz, align) { - return false; - } - self.bump(sz); - true - } - - #[cfg(not(stage0))] fn visit_leave_enum(&self, n_variants: uint, get_disr: extern unsafe fn(ptr: *Opaque) -> int, sz: uint, align: uint) -> bool { diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs index 03e44e00d8831..2d6412b0cc832 100644 --- a/src/libcore/repr.rs +++ b/src/libcore/repr.rs @@ -18,7 +18,7 @@ use cast::transmute; use char; use intrinsic; use intrinsic::{TyDesc, TyVisitor, visit_tydesc}; -#[cfg(not(stage0))] use intrinsic::Opaque; +use intrinsic::Opaque; use io::{Writer, WriterUtil}; use libc::c_void; use managed; @@ -138,14 +138,6 @@ impl Repr for char { // New implementation using reflect::MovePtr -#[cfg(stage0)] -enum VariantState { - Degenerate, - TagMatch, - TagMismatch, -} - -#[cfg(not(stage0))] enum VariantState { SearchingFor(int), Matched, @@ -190,18 +182,6 @@ pub impl ReprVisitor { true } - #[cfg(stage0)] #[inline(always)] - fn bump(&self, sz: uint) { - do self.move_ptr() |p| { - ((p as uint) + sz) as *c_void - }; - } - - #[cfg(stage0)] #[inline(always)] - fn bump_past(&self) { - self.bump(sys::size_of::()); - } - #[inline(always)] fn visit_inner(&self, inner: *TyDesc) -> bool { self.visit_ptr_inner(self.ptr, inner) @@ -467,18 +447,6 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_enter_enum(&self, n_variants: uint, - _sz: uint, _align: uint) -> bool { - if n_variants == 1 { - self.var_stk.push(Degenerate) - } else { - self.var_stk.push(TagMatch) - } - true - } - - #[cfg(not(stage0))] fn visit_enter_enum(&self, _n_variants: uint, get_disr: extern unsafe fn(ptr: *Opaque) -> int, _sz: uint, _align: uint) -> bool { @@ -487,40 +455,6 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_enter_enum_variant(&self, _variant: uint, - disr_val: int, - n_fields: uint, - name: &str) -> bool { - let mut write = false; - match self.var_stk.pop() { - Degenerate => { - write = true; - self.var_stk.push(Degenerate); - } - TagMatch | TagMismatch => { - do self.get::() |t| { - if disr_val == *t { - write = true; - self.var_stk.push(TagMatch); - } else { - self.var_stk.push(TagMismatch); - } - }; - self.bump_past::(); - } - } - - if write { - self.writer.write_str(name); - if n_fields > 0 { - self.writer.write_char('('); - } - } - true - } - - #[cfg(not(stage0))] fn visit_enter_enum_variant(&self, _variant: uint, disr_val: int, n_fields: uint, @@ -549,23 +483,6 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { - match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { - Degenerate | TagMatch => { - if i != 0 { - self.writer.write_str(", "); - } - if ! self.visit_inner(inner) { - return false; - } - } - TagMismatch => () - } - true - } - - #[cfg(not(stage0))] fn visit_enum_variant_field(&self, i: uint, _offset: uint, inner: *TyDesc) -> bool { match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { Matched => { @@ -581,23 +498,6 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_leave_enum_variant(&self, _variant: uint, - _disr_val: int, - n_fields: uint, - _name: &str) -> bool { - match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { - Degenerate | TagMatch => { - if n_fields > 0 { - self.writer.write_char(')'); - } - } - TagMismatch => () - } - true - } - - #[cfg(not(stage0))] fn visit_leave_enum_variant(&self, _variant: uint, _disr_val: int, n_fields: uint, @@ -613,14 +513,6 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_leave_enum(&self, _n_variants: uint, - _sz: uint, _align: uint) -> bool { - self.var_stk.pop(); - true - } - - #[cfg(not(stage0))] fn visit_leave_enum(&self, _n_variants: uint, _get_disr: extern unsafe fn(ptr: *Opaque) -> int, _sz: uint, _align: uint) -> bool { diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 9171c5167bc7b..17cc07c660d1a 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -226,13 +226,6 @@ pub fn map_err(res: &Result, op: &fn(&E) -> F) } pub impl Result { - #[cfg(stage0)] - #[inline(always)] - fn get_ref(&self) -> &'self T { get_ref(self) } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn get_ref<'a>(&'a self) -> &'a T { get_ref(self) } diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs index e93e0c6fc6cc9..e77ec82637e4b 100644 --- a/src/libcore/rt/mod.rs +++ b/src/libcore/rt/mod.rs @@ -49,27 +49,6 @@ mod context; mod thread; pub mod env; -#[cfg(stage0)] -pub fn start(main: *u8, _argc: int, _argv: *c_char, _crate_map: *u8) -> int { - use self::sched::{Scheduler, Task}; - use self::uvio::UvEventLoop; - - let loop_ = ~UvEventLoop::new(); - let mut sched = ~Scheduler::new(loop_); - let main_task = ~do Task::new(&mut sched.stack_pool) { - // XXX: Can't call a C function pointer from Rust yet - unsafe { rust_call_nullary_fn(main) }; - }; - sched.task_queue.push_back(main_task); - sched.run(); - return 0; - - extern { - fn rust_call_nullary_fn(f: *u8); - } -} - -#[cfg(not(stage0))] pub fn start(main: *u8, _argc: int, _argv: **c_char, _crate_map: *u8) -> int { use self::sched::{Scheduler, Task}; use self::uvio::UvEventLoop; diff --git a/src/libcore/rt/rtio.rs b/src/libcore/rt/rtio.rs index 66eb79ba6ae4e..fd64438c61b46 100644 --- a/src/libcore/rt/rtio.rs +++ b/src/libcore/rt/rtio.rs @@ -24,11 +24,6 @@ pub trait EventLoop { fn run(&mut self); fn callback(&mut self, ~fn()); /// The asynchronous I/O services. Not all event loops may provide one - #[cfg(stage0)] - fn io(&mut self) -> Option<&'self mut IoFactoryObject>; - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject>; } diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index abdd8d6619a8a..fba91dd7d8ab9 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -69,14 +69,6 @@ impl EventLoop for UvEventLoop { } } - #[cfg(stage0)] - fn io(&mut self) -> Option<&'self mut IoFactoryObject> { - Some(&mut self.uvio) - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject> { Some(&mut self.uvio) } @@ -99,14 +91,6 @@ fn test_callback_run_once() { pub struct UvIoFactory(Loop); pub impl UvIoFactory { - #[cfg(stage0)] - fn uv_loop(&mut self) -> &'self mut Loop { - match self { &UvIoFactory(ref mut ptr) => ptr } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn uv_loop<'a>(&'a mut self) -> &'a mut Loop { match self { &UvIoFactory(ref mut ptr) => ptr } } diff --git a/src/libcore/trie.rs b/src/libcore/trie.rs index f4e9ddbdd90a1..f0756be994432 100644 --- a/src/libcore/trie.rs +++ b/src/libcore/trie.rs @@ -56,16 +56,6 @@ impl Map for TrieMap { /// Visit all key-value pairs in order #[inline(always)] - #[cfg(stage0)] - fn each(&self, f: &fn(&uint, &'self T) -> bool) { - self.root.each(f); - } - - /// Visit all key-value pairs in order - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) { self.root.each(f); } @@ -78,16 +68,6 @@ impl Map for TrieMap { /// Visit all values in order #[inline(always)] - #[cfg(stage0)] - fn each_value(&self, f: &fn(&T) -> bool) { - self.each(|_, v| f(v)) - } - - /// Visit all values in order - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each_value<'a>(&'a self, f: &fn(&'a T) -> bool) { self.each(|_, v| f(v)) } @@ -99,31 +79,6 @@ impl Map for TrieMap { } /// Return a reference to the value corresponding to the key - #[cfg(stage0)] - #[inline(hint)] - fn find(&self, key: &uint) -> Option<&'self T> { - let mut node: &'self TrieNode = &self.root; - let mut idx = 0; - loop { - match node.children[chunk(*key, idx)] { - Internal(ref x) => node = &**x, - External(stored, ref value) => { - if stored == *key { - return Some(value) - } else { - return None - } - } - Nothing => return None - } - idx += 1; - } - } - - /// Return a reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(hint)] fn find<'a>(&'a self, key: &uint) -> Option<&'a T> { let mut node: &'a TrieNode = &self.root; @@ -145,16 +100,6 @@ impl Map for TrieMap { } /// Return a mutable reference to the value corresponding to the key - #[cfg(stage0)] - #[inline(always)] - fn find_mut(&mut self, key: &uint) -> Option<&'self mut T> { - find_mut(&mut self.root.children[chunk(*key, 0)], *key, 1) - } - - /// Return a mutable reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn find_mut<'a>(&'a mut self, key: &uint) -> Option<&'a mut T> { find_mut(&mut self.root.children[chunk(*key, 0)], *key, 1) @@ -193,16 +138,6 @@ pub impl TrieMap { /// Visit all key-value pairs in reverse order #[inline(always)] - #[cfg(stage0)] - fn each_reverse(&self, f: &fn(&uint, &'self T) -> bool) { - self.root.each_reverse(f); - } - - /// Visit all key-value pairs in reverse order - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) { self.root.each_reverse(f); } @@ -298,21 +233,6 @@ impl TrieNode { } impl TrieNode { - #[cfg(stage0)] - fn each(&self, f: &fn(&uint, &'self T) -> bool) -> bool { - for uint::range(0, self.children.len()) |idx| { - match self.children[idx] { - Internal(ref x) => if !x.each(f) { return false }, - External(k, ref v) => if !f(&k, v) { return false }, - Nothing => () - } - } - true - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { for uint::range(0, self.children.len()) |idx| { match self.children[idx] { @@ -324,21 +244,6 @@ impl TrieNode { true } - #[cfg(stage0)] - fn each_reverse(&self, f: &fn(&uint, &'self T) -> bool) -> bool { - for uint::range_rev(self.children.len(), 0) |idx| { - match self.children[idx - 1] { - Internal(ref x) => if !x.each_reverse(f) { return false }, - External(k, ref v) => if !f(&k, v) { return false }, - Nothing => () - } - } - true - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { for uint::range_rev(self.children.len(), 0) |idx| { match self.children[idx - 1] { diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index a2b6f0eb1a714..6da22657906dd 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -56,39 +56,11 @@ impl Clone for (T, U) { } } -#[cfg(stage0)] -pub trait ImmutableTuple { - fn first_ref(&self) -> &'self T; - fn second_ref(&self) -> &'self U; -} - -#[cfg(stage0)] -impl ImmutableTuple for (T, U) { - #[inline(always)] - fn first_ref(&self) -> &'self T { - match *self { - (ref t, _) => t, - } - } - #[inline(always)] - fn second_ref(&self) -> &'self U { - match *self { - (_, ref u) => u, - } - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub trait ImmutableTuple { fn first_ref<'a>(&'a self) -> &'a T; fn second_ref<'a>(&'a self) -> &'a U; } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl ImmutableTuple for (T, U) { #[inline(always)] fn first_ref<'a>(&'a self) -> &'a T { diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 611862a79e7e0..de0542afc399a 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -135,32 +135,6 @@ pub unsafe fn strdup_uniq(ptr: *c_uchar, len: uint) -> ~str { } #[lang="start"] -#[cfg(stage0)] -pub fn start(main: *u8, argc: int, argv: *c_char, - crate_map: *u8) -> int { - use libc::getenv; - use rt::start; - - unsafe { - let use_old_rt = do str::as_c_str("RUST_NEWRT") |s| { - getenv(s).is_null() - }; - if use_old_rt { - return rust_start(main as *c_void, argc as c_int, argv, - crate_map as *c_void) as int; - } else { - return start(main, argc, argv, crate_map); - } - } - - extern { - fn rust_start(main: *c_void, argc: c_int, argv: *c_char, - crate_map: *c_void) -> c_int; - } -} - -#[lang="start"] -#[cfg(not(stage0))] pub fn start(main: *u8, argc: int, argv: **c_char, crate_map: *u8) -> int { use libc::getenv; diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 86767dc5bad85..94f866643532c 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -1566,16 +1566,6 @@ pub fn each_permutation(v: &[T], put: &fn(ts: &[T]) -> bool) { } } -// see doc below -#[cfg(stage0)] // XXX: lifetimes! -pub fn windowed(n: uint, v: &[T], it: &fn(&[T]) -> bool) { - assert!(1u <= n); - if n > v.len() { return; } - for uint::range(0, v.len() - n + 1) |i| { - if !it(v.slice(i, i+n)) { return } - } -} - /** * Iterate over all contiguous windows of length `n` of the vector `v`. * @@ -1590,9 +1580,6 @@ pub fn windowed(n: uint, v: &[T], it: &fn(&[T]) -> bool) { * ~~~ * */ -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub fn windowed<'r, T>(n: uint, v: &'r [T], it: &fn(&'r [T]) -> bool) { assert!(1u <= n); if n > v.len() { return; } @@ -1854,150 +1841,6 @@ impl<'self,T:Copy> CopyableVector for &'self const [T] { } } -#[cfg(stage0)] -pub trait ImmutableVector { - fn slice(&self, start: uint, end: uint) -> &'self [T]; - fn head(&self) -> &'self T; - fn head_opt(&self) -> Option<&'self T>; - fn tail(&self) -> &'self [T]; - fn tailn(&self, n: uint) -> &'self [T]; - fn init(&self) -> &'self [T]; - fn initn(&self, n: uint) -> &'self [T]; - fn last(&self) -> &'self T; - fn last_opt(&self) -> Option<&'self T>; - fn each_reverse(&self, blk: &fn(&T) -> bool); - fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool); - fn foldr(&self, z: U, p: &fn(t: &T, u: U) -> U) -> U; - fn map(&self, f: &fn(t: &T) -> U) -> ~[U]; - fn mapi(&self, f: &fn(uint, t: &T) -> U) -> ~[U]; - fn map_r(&self, f: &fn(x: &T) -> U) -> ~[U]; - fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool; - fn flat_map(&self, f: &fn(t: &T) -> ~[U]) -> ~[U]; - fn filter_mapped(&self, f: &fn(t: &T) -> Option) -> ~[U]; - unsafe fn unsafe_ref(&self, index: uint) -> *T; -} - -/// Extension methods for vectors -#[cfg(stage0)] -impl<'self,T> ImmutableVector for &'self [T] { - /// Return a slice that points into another slice. - #[inline] - fn slice(&self, start: uint, end: uint) -> &'self [T] { - slice(*self, start, end) - } - - /// Returns the first element of a vector, failing if the vector is empty. - #[inline] - fn head(&self) -> &'self T { head(*self) } - - /// Returns the first element of a vector - #[inline] - fn head_opt(&self) -> Option<&'self T> { head_opt(*self) } - - /// Returns all but the first element of a vector - #[inline] - fn tail(&self) -> &'self [T] { tail(*self) } - - /// Returns all but the first `n' elements of a vector - #[inline] - fn tailn(&self, n: uint) -> &'self [T] { tailn(*self, n) } - - /// Returns all but the last elemnt of a vector - #[inline] - fn init(&self) -> &'self [T] { init(*self) } - - /// Returns all but the last `n' elemnts of a vector - #[inline] - fn initn(&self, n: uint) -> &'self [T] { initn(*self, n) } - - /// Returns the last element of a `v`, failing if the vector is empty. - #[inline] - fn last(&self) -> &'self T { last(*self) } - - /// Returns the last element of a `v`, failing if the vector is empty. - #[inline] - fn last_opt(&self) -> Option<&'self T> { last_opt(*self) } - - /// Iterates over a vector's elements in reverse. - #[inline] - fn each_reverse(&self, blk: &fn(&T) -> bool) { - each_reverse(*self, blk) - } - - /// Iterates over a vector's elements and indices in reverse. - #[inline] - fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool) { - eachi_reverse(*self, blk) - } - - /// Reduce a vector from right to left - #[inline] - fn foldr(&self, z: U, p: &fn(t: &T, u: U) -> U) -> U { - foldr(*self, z, p) - } - - /// Apply a function to each element of a vector and return the results - #[inline] - fn map(&self, f: &fn(t: &T) -> U) -> ~[U] { map(*self, f) } - - /** - * Apply a function to the index and value of each element in the vector - * and return the results - */ - fn mapi(&self, f: &fn(uint, t: &T) -> U) -> ~[U] { - mapi(*self, f) - } - - #[inline] - fn map_r(&self, f: &fn(x: &T) -> U) -> ~[U] { - let mut r = ~[]; - let mut i = 0; - while i < self.len() { - r.push(f(&self[i])); - i += 1; - } - r - } - - /** - * Returns true if the function returns true for all elements. - * - * If the vector is empty, true is returned. - */ - fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool { - alli(*self, f) - } - /** - * Apply a function to each element of a vector and return a concatenation - * of each result vector - */ - #[inline] - fn flat_map(&self, f: &fn(t: &T) -> ~[U]) -> ~[U] { - flat_map(*self, f) - } - /** - * Apply a function to each element of a vector and return the results - * - * If function `f` returns `none` then that element is excluded from - * the resulting vector. - */ - #[inline] - fn filter_mapped(&self, f: &fn(t: &T) -> Option) -> ~[U] { - filter_mapped(*self, f) - } - - /// Returns a pointer to the element at the given index, without doing - /// bounds checking. - #[inline(always)] - unsafe fn unsafe_ref(&self, index: uint) -> *T { - let (ptr, _): (*T, uint) = transmute(*self); - ptr.offset(index) - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub trait ImmutableVector<'self, T> { fn slice(&self, start: uint, end: uint) -> &'self [T]; fn iter(self) -> VecIterator<'self, T>; @@ -2022,9 +1865,6 @@ pub trait ImmutableVector<'self, T> { } /// Extension methods for vectors -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl<'self,T> ImmutableVector<'self, T> for &'self [T] { /// Return a slice that points into another slice. #[inline] @@ -2634,17 +2474,6 @@ pub mod bytes { // ___________________________________________________________________________ // ITERATION TRAIT METHODS -#[cfg(stage0)] -impl<'self,A> old_iter::BaseIter for &'self [A] { - #[inline(always)] - fn each(&self, blk: &fn(v: &'self A) -> bool) { each(*self, blk) } - #[inline(always)] - fn size_hint(&self) -> Option { Some(self.len()) } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl<'self,A> old_iter::BaseIter for &'self [A] { #[inline(always)] fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { each(*self, blk) } @@ -2653,18 +2482,6 @@ impl<'self,A> old_iter::BaseIter for &'self [A] { } // FIXME(#4148): This should be redundant -#[cfg(stage0)] -impl old_iter::BaseIter for ~[A] { - #[inline(always)] - fn each(&self, blk: &fn(v: &'self A) -> bool) { each(*self, blk) } - #[inline(always)] - fn size_hint(&self) -> Option { Some(self.len()) } -} - -// FIXME(#4148): This should be redundant -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl old_iter::BaseIter for ~[A] { #[inline(always)] fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { each(*self, blk) } @@ -2673,18 +2490,6 @@ impl old_iter::BaseIter for ~[A] { } // FIXME(#4148): This should be redundant -#[cfg(stage0)] -impl old_iter::BaseIter for @[A] { - #[inline(always)] - fn each(&self, blk: &fn(v: &'self A) -> bool) { each(*self, blk) } - #[inline(always)] - fn size_hint(&self) -> Option { Some(self.len()) } -} - -// FIXME(#4148): This should be redundant -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl old_iter::BaseIter for @[A] { #[inline(always)] fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { each(*self, blk) } @@ -2692,17 +2497,6 @@ impl old_iter::BaseIter for @[A] { fn size_hint(&self) -> Option { Some(self.len()) } } -#[cfg(stage0)] -impl<'self,A> old_iter::MutableIter for &'self mut [A] { - #[inline(always)] - fn each_mut(&mut self, blk: &fn(v: &'self mut A) -> bool) { - each_mut(*self, blk) - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl<'self,A> old_iter::MutableIter for &'self mut [A] { #[inline(always)] fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) { @@ -2711,17 +2505,6 @@ impl<'self,A> old_iter::MutableIter for &'self mut [A] { } // FIXME(#4148): This should be redundant -#[cfg(stage0)] -impl old_iter::MutableIter for ~[A] { - #[inline(always)] - fn each_mut(&mut self, blk: &fn(v: &'self mut A) -> bool) { - each_mut(*self, blk) - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl old_iter::MutableIter for ~[A] { #[inline(always)] fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index c7c9c110586c7..c65521228fa87 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -557,29 +557,6 @@ trait read_method_map_entry_helper { -> method_map_entry; } -#[cfg(stage0)] -fn encode_method_map_entry(ecx: @e::EncodeContext, - ebml_w: &writer::Encoder, - mme: method_map_entry) { - do ebml_w.emit_struct("method_map_entry", 3) { - do ebml_w.emit_field(~"self_arg", 0u) { - ebml_w.emit_arg(ecx, mme.self_arg); - } - do ebml_w.emit_field(~"explicit_self", 2u) { - mme.explicit_self.encode(ebml_w); - } - do ebml_w.emit_field(~"origin", 1u) { - mme.origin.encode(ebml_w); - } - do ebml_w.emit_field(~"self_mode", 3) { - mme.self_mode.encode(ebml_w); - } - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] fn encode_method_map_entry(ecx: @e::EncodeContext, ebml_w: &writer::Encoder, mme: method_map_entry) { @@ -600,34 +577,6 @@ fn encode_method_map_entry(ecx: @e::EncodeContext, } impl read_method_map_entry_helper for reader::Decoder { - #[cfg(stage0)] - fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) - -> method_map_entry { - do self.read_struct("method_map_entry", 3) { - method_map_entry { - self_arg: self.read_field(~"self_arg", 0u, || { - self.read_arg(xcx) - }), - explicit_self: self.read_field(~"explicit_self", 2u, || { - let self_type: ast::self_ty_ = Decodable::decode(self); - self_type - }), - origin: self.read_field(~"origin", 1u, || { - let method_origin: method_origin = - Decodable::decode(self); - method_origin.tr(xcx) - }), - self_mode: self.read_field(~"self_mode", 3, || { - let self_mode: ty::SelfMode = Decodable::decode(self); - self_mode - }), - } - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) -> method_map_entry { do self.read_struct("method_map_entry", 3) { @@ -841,33 +790,6 @@ impl ebml_writer_helpers for writer::Encoder { } } - #[cfg(stage0)] - fn emit_tpbt(&self, ecx: @e::EncodeContext, - tpbt: ty::ty_param_bounds_and_ty) { - do self.emit_struct("ty_param_bounds_and_ty", 2) { - do self.emit_field(~"generics", 0) { - do self.emit_struct("Generics", 2) { - do self.emit_field(~"type_param_defs", 0) { - do self.emit_from_vec(*tpbt.generics.type_param_defs) - |type_param_def| - { - self.emit_type_param_def(ecx, type_param_def); - } - } - do self.emit_field(~"region_param", 1) { - tpbt.generics.region_param.encode(self); - } - } - } - do self.emit_field(~"ty", 1) { - self.emit_ty(ecx, tpbt.ty); - } - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn emit_tpbt(&self, ecx: @e::EncodeContext, tpbt: ty::ty_param_bounds_and_ty) { do self.emit_struct("ty_param_bounds_and_ty", 2) { @@ -1126,32 +1048,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } - #[cfg(stage0)] - fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) - -> ty::ty_param_bounds_and_ty - { - do self.read_struct("ty_param_bounds_and_ty", 2) { - ty::ty_param_bounds_and_ty { - generics: do self.read_struct("Generics", 2) { - ty::Generics { - type_param_defs: self.read_field("type_param_defs", 0, || { - @self.read_to_vec(|| self.read_type_param_def(xcx)) - }), - region_param: self.read_field(~"region_param", 1, || { - Decodable::decode(self) - }) - } - }, - ty: self.read_field(~"ty", 1, || { - self.read_ty(xcx) - }) - } - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) -> ty::ty_param_bounds_and_ty { diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 54c51cf2e487a..9e34d5c6177e6 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -85,6 +85,7 @@ pub mod middle { pub mod lint; #[path = "borrowck/mod.rs"] pub mod borrowck; + pub mod dataflow; pub mod mem_categorization; pub mod liveness; pub mod kind; diff --git a/src/libstd/arena.rs b/src/libstd/arena.rs index 8e2c734504512..e714af5fa1890 100644 --- a/src/libstd/arena.rs +++ b/src/libstd/arena.rs @@ -201,21 +201,6 @@ pub impl Arena { } #[inline(always)] - #[cfg(stage0)] - priv fn alloc_pod(&self, op: &fn() -> T) -> &'self T { - unsafe { - let tydesc = sys::get_type_desc::(); - let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align); - let ptr: *mut T = transmute(ptr); - rusti::move_val_init(&mut (*ptr), op()); - return transmute(ptr); - } - } - - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] priv fn alloc_pod<'a, T>(&'a self, op: &fn() -> T) -> &'a T { unsafe { let tydesc = sys::get_type_desc::(); @@ -261,31 +246,6 @@ pub impl Arena { } #[inline(always)] - #[cfg(stage0)] - priv fn alloc_nonpod(&self, op: &fn() -> T) -> &'self T { - unsafe { - let tydesc = sys::get_type_desc::(); - let (ty_ptr, ptr) = - self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align); - let ty_ptr: *mut uint = transmute(ty_ptr); - let ptr: *mut T = transmute(ptr); - // Write in our tydesc along with a bit indicating that it - // has *not* been initialized yet. - *ty_ptr = transmute(tydesc); - // Actually initialize it - rusti::move_val_init(&mut(*ptr), op()); - // Now that we are done, update the tydesc to indicate that - // the object is there. - *ty_ptr = bitpack_tydesc_ptr(tydesc, true); - - return transmute(ptr); - } - } - - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] priv fn alloc_nonpod<'a, T>(&'a self, op: &fn() -> T) -> &'a T { unsafe { let tydesc = sys::get_type_desc::(); @@ -308,22 +268,6 @@ pub impl Arena { // The external interface #[inline(always)] - #[cfg(stage0)] - fn alloc(&self, op: &fn() -> T) -> &'self T { - unsafe { - if !rusti::needs_drop::() { - self.alloc_pod(op) - } else { - self.alloc_nonpod(op) - } - } - } - - // The external interface - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn alloc<'a, T>(&'a self, op: &fn() -> T) -> &'a T { unsafe { if !rusti::needs_drop::() { diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs index 5d52bb7c0810b..64d708e0b2e89 100644 --- a/src/libstd/deque.rs +++ b/src/libstd/deque.rs @@ -37,128 +37,6 @@ impl Mutable for Deque { } } -#[cfg(stage0)] -pub impl Deque { - /// Create an empty Deque - fn new() -> Deque { - Deque{nelts: 0, lo: 0, hi: 0, - elts: vec::from_fn(initial_capacity, |_| None)} - } - - /// Return a reference to the first element in the deque - /// - /// Fails if the deque is empty - #[cfg(stage0)] - fn peek_front(&self) -> &'self T { get(self.elts, self.lo) } - - /// Return a reference to the first element in the deque - /// - /// Fails if the deque is empty - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn peek_front<'a>(&'a self) -> &'a T { get(self.elts, self.lo) } - - /// Return a reference to the last element in the deque - /// - /// Fails if the deque is empty - #[cfg(stage0)] - fn peek_back(&self) -> &'self T { get(self.elts, self.hi - 1u) } - - /// Return a reference to the last element in the deque - /// - /// Fails if the deque is empty - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn peek_back<'a>(&'a self) -> &'a T { get(self.elts, self.hi - 1u) } - - /// Retrieve an element in the deque by index - /// - /// Fails if there is no element with the given index - #[cfg(stage0)] - fn get(&self, i: int) -> &'self T { - let idx = (self.lo + (i as uint)) % self.elts.len(); - get(self.elts, idx) - } - - /// Retrieve an element in the deque by index - /// - /// Fails if there is no element with the given index - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn get<'a>(&'a self, i: int) -> &'a T { - let idx = (self.lo + (i as uint)) % self.elts.len(); - get(self.elts, idx) - } - - /// Iterate over the elements in the deque - fn each(&self, f: &fn(&T) -> bool) { - self.eachi(|_i, e| f(e)) - } - - /// Iterate over the elements in the deque by index - fn eachi(&self, f: &fn(uint, &T) -> bool) { - for uint::range(0, self.nelts) |i| { - if !f(i, self.get(i as int)) { return; } - } - } - - /// Remove and return the first element in the deque - /// - /// Fails if the deque is empty - fn pop_front(&mut self) -> T { - let result = self.elts[self.lo].swap_unwrap(); - self.lo = (self.lo + 1u) % self.elts.len(); - self.nelts -= 1u; - result - } - - /// Remove and return the last element in the deque - /// - /// Fails if the deque is empty - fn pop_back(&mut self) -> T { - if self.hi == 0u { - self.hi = self.elts.len() - 1u; - } else { self.hi -= 1u; } - let result = self.elts[self.hi].swap_unwrap(); - self.elts[self.hi] = None; - self.nelts -= 1u; - result - } - - /// Prepend an element to the deque - fn add_front(&mut self, t: T) { - let oldlo = self.lo; - if self.lo == 0u { - self.lo = self.elts.len() - 1u; - } else { self.lo -= 1u; } - if self.lo == self.hi { - self.elts = grow(self.nelts, oldlo, self.elts); - self.lo = self.elts.len() - 1u; - self.hi = self.nelts; - } - self.elts[self.lo] = Some(t); - self.nelts += 1u; - } - - /// Append an element to the deque - fn add_back(&mut self, t: T) { - if self.lo == self.hi && self.nelts != 0u { - self.elts = grow(self.nelts, self.lo, self.elts); - self.lo = 0u; - self.hi = self.nelts; - } - self.elts[self.hi] = Some(t); - self.hi = (self.hi + 1u) % self.elts.len(); - self.nelts += 1u; - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub impl Deque { /// Create an empty Deque fn new() -> Deque { diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index 2598e96a141e2..9b89036eee51b 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -400,16 +400,6 @@ pub mod reader { f() } - #[cfg(stage0)] - fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { - debug!("read_field(name=%?, idx=%u)", name, idx); - self._check_label(name); - f() - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn read_struct_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { debug!("read_struct_field(name=%?, idx=%u)", name, idx); self._check_label(name); @@ -714,14 +704,6 @@ pub mod writer { } fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) { f() } - #[cfg(stage0)] - fn emit_field(&self, name: &str, _idx: uint, f: &fn()) { - self._emit_label(name); - f() - } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn emit_struct_field(&self, name: &str, _idx: uint, f: &fn()) { self._emit_label(name); f() diff --git a/src/libstd/future.rs b/src/libstd/future.rs index f59abfa81ca10..c3fc16bdf70ba 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -54,35 +54,6 @@ pub impl Future { } pub impl Future { - #[cfg(stage0)] - fn get_ref(&self) -> &'self A { - /*! - * Executes the future's closure and then returns a borrowed - * pointer to the result. The borrowed pointer lasts as long as - * the future. - */ - unsafe { - match self.state { - Forced(ref mut v) => { return cast::transmute(v); } - Evaluating => fail!(~"Recursive forcing of future!"), - Pending(_) => {} - } - - let mut state = Evaluating; - self.state <-> state; - match state { - Forced(_) | Evaluating => fail!(~"Logic error."), - Pending(f) => { - self.state = Forced(f()); - self.get_ref() - } - } - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get_ref<'a>(&'a self) -> &'a A { /*! * Executes the future's closure and then returns a borrowed diff --git a/src/libstd/json.rs b/src/libstd/json.rs index 7353bec7333c5..5d5b0bd952f18 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -143,16 +143,6 @@ impl serialize::Encoder for Encoder { f(); self.wr.write_char('}'); } - #[cfg(stage0)] - fn emit_field(&self, name: &str, idx: uint, f: &fn()) { - if idx != 0 { self.wr.write_char(','); } - self.wr.write_str(escape_str(name)); - self.wr.write_char(':'); - f(); - } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn emit_struct_field(&self, name: &str, idx: uint, f: &fn()) { if idx != 0 { self.wr.write_char(','); } self.wr.write_str(escape_str(name)); @@ -289,21 +279,6 @@ impl serialize::Encoder for PrettyEncoder { self.wr.write_char('}'); } } - #[cfg(stage0)] - fn emit_field(&self, name: &str, idx: uint, f: &fn()) { - if idx == 0 { - self.wr.write_char('\n'); - } else { - self.wr.write_str(",\n"); - } - self.wr.write_str(spaces(self.indent)); - self.wr.write_str(escape_str(name)); - self.wr.write_str(": "); - f(); - } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn emit_struct_field(&self, name: &str, idx: uint, f: &fn()) { if idx == 0 { self.wr.write_char('\n'); @@ -901,29 +876,6 @@ impl serialize::Decoder for Decoder { value } - #[cfg(stage0)] - fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { - debug!("read_field(name=%?, idx=%u)", name, idx); - match self.stack.pop() { - Object(obj) => { - let mut obj = obj; - let value = match obj.pop(&name.to_owned()) { - None => fail!(fmt!("no such field: %s", name)), - Some(json) => { - self.stack.push(json); - f() - } - }; - self.stack.push(Object(obj)); - value - } - value => fail!(fmt!("not an object: %?", value)) - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn read_struct_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { debug!("read_struct_field(name=%?, idx=%u)", name, idx); match self.stack.pop() { diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index 47af3576c9062..33fe1cfff8e59 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -45,25 +45,9 @@ impl Mutable for PriorityQueue { pub impl PriorityQueue { /// Returns the greatest item in the queue - fails if empty - #[cfg(stage0)] - fn top(&self) -> &'self T { &self.data[0] } - - /// Returns the greatest item in the queue - fails if empty - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn top<'a>(&'a self) -> &'a T { &self.data[0] } /// Returns the greatest item in the queue - None if empty - #[cfg(stage0)] - fn maybe_top(&self) -> Option<&'self T> { - if self.is_empty() { None } else { Some(self.top()) } - } - - /// Returns the greatest item in the queue - None if empty - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn maybe_top<'a>(&'a self) -> Option<&'a T> { if self.is_empty() { None } else { Some(self.top()) } } diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index 1ad581ba993e4..032df4c819cdd 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -55,11 +55,6 @@ pub trait Encoder { fn emit_enum_struct_variant_field(&self, f_name: &str, f_idx: uint, f: &fn()); fn emit_struct(&self, name: &str, len: uint, f: &fn()); - #[cfg(stage0)] - fn emit_field(&self, f_name: &str, f_idx: uint, f: &fn()); - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn emit_struct_field(&self, f_name: &str, f_idx: uint, f: &fn()); fn emit_tuple(&self, len: uint, f: &fn()); @@ -111,11 +106,6 @@ pub trait Decoder { fn read_enum_struct_variant_field(&self, &f_name: &str, f_idx: uint, f: &fn() -> T) -> T; fn read_struct(&self, s_name: &str, len: uint, f: &fn() -> T) -> T; - #[cfg(stage0)] - fn read_field(&self, f_name: &str, f_idx: uint, f: &fn() -> T) -> T; - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn read_struct_field(&self, f_name: &str, f_idx: uint, f: &fn() -> T) -> T; fn read_tuple(&self, f: &fn(uint) -> T) -> T; diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs index fb17d4e50900c..1b72300a178ba 100644 --- a/src/libstd/smallintmap.rs +++ b/src/libstd/smallintmap.rs @@ -50,20 +50,6 @@ impl Map for SmallIntMap { } /// Visit all key-value pairs in order - #[cfg(stage0)] - fn each(&self, it: &fn(&uint, &'self V) -> bool) { - for uint::range(0, self.v.len()) |i| { - match self.v[i] { - Some(ref elt) => if !it(&i, elt) { break }, - None => () - } - } - } - - /// Visit all key-value pairs in order - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each<'a>(&'a self, it: &fn(&uint, &'a V) -> bool) { for uint::range(0, self.v.len()) |i| { match self.v[i] { @@ -79,15 +65,6 @@ impl Map for SmallIntMap { } /// Visit all values in order - #[cfg(stage0)] - fn each_value(&self, blk: &fn(value: &V) -> bool) { - self.each(|_, v| blk(v)) - } - - /// Visit all values in order - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each_value<'a>(&'a self, blk: &fn(value: &'a V) -> bool) { self.each(|_, v| blk(v)) } @@ -103,22 +80,6 @@ impl Map for SmallIntMap { } /// Return a reference to the value corresponding to the key - #[cfg(stage0)] - fn find(&self, key: &uint) -> Option<&'self V> { - if *key < self.v.len() { - match self.v[*key] { - Some(ref value) => Some(value), - None => None - } - } else { - None - } - } - - /// Return a reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find<'a>(&'a self, key: &uint) -> Option<&'a V> { if *key < self.v.len() { match self.v[*key] { @@ -131,22 +92,6 @@ impl Map for SmallIntMap { } /// Return a mutable reference to the value corresponding to the key - #[cfg(stage0)] - fn find_mut(&mut self, key: &uint) -> Option<&'self mut V> { - if *key < self.v.len() { - match self.v[*key] { - Some(ref mut value) => Some(value), - None => None - } - } else { - None - } - } - - /// Return a mutable reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find_mut<'a>(&'a mut self, key: &uint) -> Option<&'a mut V> { if *key < self.v.len() { match self.v[*key] { @@ -188,20 +133,6 @@ pub impl SmallIntMap { fn new() -> SmallIntMap { SmallIntMap{v: ~[]} } /// Visit all key-value pairs in reverse order - #[cfg(stage0)] - fn each_reverse(&self, it: &fn(uint, &'self V) -> bool) { - for uint::range_rev(self.v.len(), 0) |i| { - match self.v[i - 1] { - Some(ref elt) => if !it(i - 1, elt) { break }, - None => () - } - } - } - - /// Visit all key-value pairs in reverse order - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) { for uint::range_rev(self.v.len(), 0) |i| { match self.v[i - 1] { @@ -211,14 +142,6 @@ pub impl SmallIntMap { } } - #[cfg(stage0)] - fn get(&self, key: &uint) -> &'self V { - self.find(key).expect("key not present") - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get<'a>(&'a self, key: &uint) -> &'a V { self.find(key).expect("key not present") } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 2d6d74b5c1e32..5bad9ecae3ed7 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -451,17 +451,6 @@ impl MapChain{ // ugh: can't get this to compile with mut because of the // lack of flow sensitivity. - #[cfg(stage0)] - fn get_map(&self) -> &'self HashMap { - match *self { - BaseMapChain (~ref map) => map, - ConsMapChain (~ref map,_) => map - } - } - - // ugh: can't get this to compile with mut because of the - // lack of flow sensitivity. - #[cfg(not(stage0))] fn get_map<'a>(&'a self) -> &'a HashMap { match *self { BaseMapChain (~ref map) => map, diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index 6cf7bba600ec0..600ab964e5238 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -61,15 +61,6 @@ impl OptVec { } } - #[cfg(stage0)] - fn get(&self, i: uint) -> &'self T { - match *self { - Empty => fail!(fmt!("Invalid index %u", i)), - Vec(ref v) => &v[i] - } - } - - #[cfg(not(stage0))] fn get<'a>(&'a self, i: uint) -> &'a T { match *self { Empty => fail!(fmt!("Invalid index %u", i)), From b5a7e8b35322869b1cf51bd1b35a86e9e721da54 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 22 Apr 2013 18:09:23 -0400 Subject: [PATCH 049/215] desnapshot --- src/libcore/core.rc | 3 --- src/libcore/num/f32.rs | 16 ++-------------- src/libcore/num/f64.rs | 12 ++---------- src/libcore/num/float.rs | 15 ++------------- src/libcore/num/int-template.rs | 14 -------------- src/libcore/num/num.rs | 28 ++-------------------------- src/libcore/num/strconv.rs | 9 --------- src/libcore/num/uint-template.rs | 14 -------------- src/libcore/ops.rs | 12 ------------ src/libcore/prelude.rs | 3 --- src/libcore/repr.rs | 1 - src/libcore/rt/io/mod.rs | 3 --- src/libstd/std.rc | 3 --- 13 files changed, 8 insertions(+), 125 deletions(-) diff --git a/src/libcore/core.rc b/src/libcore/core.rc index f9a56f613d542..f6e4056f3d0fc 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -75,9 +75,6 @@ they contained the following prologue: pub use kinds::{Const, Copy, Owned, Durable}; pub use ops::{Drop}; -#[cfg(stage0)] -pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not}; -#[cfg(not(stage0))] pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Shl, Shr, Index}; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index e687f482fa98c..6398127a5faff 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -278,24 +278,12 @@ impl Mul for f32 { #[inline(always)] fn mul(&self, other: &f32) -> f32 { *self * *other } } - -#[cfg(stage0,notest)] -impl Div for f32 { - #[inline(always)] - fn div(&self, other: &f32) -> f32 { *self / *other } -} -#[cfg(not(stage0),notest)] +#[cfg(notest)] impl Quot for f32 { #[inline(always)] fn quot(&self, other: &f32) -> f32 { *self / *other } } - -#[cfg(stage0,notest)] -impl Modulo for f32 { - #[inline(always)] - fn modulo(&self, other: &f32) -> f32 { *self % *other } -} -#[cfg(not(stage0),notest)] +#[cfg(notest)] impl Rem for f32 { #[inline(always)] fn rem(&self, other: &f32) -> f32 { *self % *other } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index d00e6ae2c0d79..013f3c5095e2a 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -296,20 +296,12 @@ impl Sub for f64 { impl Mul for f64 { fn mul(&self, other: &f64) -> f64 { *self * *other } } -#[cfg(stage0,notest)] -impl Div for f64 { - fn div(&self, other: &f64) -> f64 { *self / *other } -} -#[cfg(not(stage0),notest)] +#[cfg(notest)] impl Quot for f64 { #[inline(always)] fn quot(&self, other: &f64) -> f64 { *self / *other } } -#[cfg(stage0,notest)] -impl Modulo for f64 { - fn modulo(&self, other: &f64) -> f64 { *self % *other } -} -#[cfg(not(stage0),notest)] +#[cfg(notest)] impl Rem for f64 { #[inline(always)] fn rem(&self, other: &f64) -> f64 { *self % *other } diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 3aa8848cdbed2..496ad4ec176b7 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -691,23 +691,12 @@ impl Mul for float { #[inline(always)] fn mul(&self, other: &float) -> float { *self * *other } } - -#[cfg(stage0,notest)] -impl Div for float { - #[inline(always)] - fn div(&self, other: &float) -> float { *self / *other } -} -#[cfg(not(stage0),notest)] +#[cfg(notest)] impl Quot for float { #[inline(always)] fn quot(&self, other: &float) -> float { *self / *other } } -#[cfg(stage0,notest)] -impl Modulo for float { - #[inline(always)] - fn modulo(&self, other: &float) -> float { *self % *other } -} -#[cfg(not(stage0),notest)] +#[cfg(notest)] impl Rem for float { #[inline(always)] fn rem(&self, other: &float) -> float { *self % *other } diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index ec38a32c039d6..85489755fc7a9 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -200,13 +200,6 @@ impl Mul for T { #[inline(always)] fn mul(&self, other: &T) -> T { *self * *other } } - -#[cfg(stage0,notest)] -impl Div for T { - #[inline(always)] - fn div(&self, other: &T) -> T { *self / *other } -} -#[cfg(not(stage0),notest)] impl Quot for T { /// /// Returns the integer quotient, truncated towards 0. As this behaviour reflects @@ -229,13 +222,6 @@ impl Quot for T { #[inline(always)] fn quot(&self, other: &T) -> T { *self / *other } } - -#[cfg(stage0,notest)] -impl Modulo for T { - #[inline(always)] - fn modulo(&self, other: &T) -> T { *self % *other } -} -#[cfg(not(stage0),notest)] impl Rem for T { /// /// Returns the integer remainder after division, satisfying: diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 3e43ebfef1222..de7597fa821d6 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -10,13 +10,6 @@ //! An interface for numeric types use cmp::{Eq, Ord}; -#[cfg(stage0)] -use ops::{Add, Sub, Mul, Neg}; -#[cfg(stage0)] -use Quot = ops::Div; -#[cfg(stage0)] -use Rem = ops::Modulo; -#[cfg(not(stage0))] use ops::{Add, Sub, Mul, Quot, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use option::Option; @@ -391,25 +384,8 @@ pub fn pow_with_uint+Mul>( total } -/// Helper function for testing numeric operations -#[cfg(stage0,test)] -pub fn test_num(ten: T, two: T) { - assert_eq!(ten.add(&two), cast(12)); - assert_eq!(ten.sub(&two), cast(8)); - assert_eq!(ten.mul(&two), cast(20)); - assert_eq!(ten.div(&two), cast(5)); - assert_eq!(ten.modulo(&two), cast(0)); - - assert_eq!(ten.add(&two), ten + two); - assert_eq!(ten.sub(&two), ten - two); - assert_eq!(ten.mul(&two), ten * two); - assert_eq!(ten.div(&two), ten / two); - assert_eq!(ten.modulo(&two), ten % two); -} -#[cfg(stage1,test)] -#[cfg(stage2,test)] -#[cfg(stage3,test)] -pub fn test_num(ten: T, two: T) { +#[cfg(test)] +fn test_num(ten: T, two: T) { assert_eq!(ten.add(&two), cast(12)); assert_eq!(ten.sub(&two), cast(8)); assert_eq!(ten.mul(&two), cast(20)); diff --git a/src/libcore/num/strconv.rs b/src/libcore/num/strconv.rs index 2f3cd92dac09e..004789e7fc1ca 100644 --- a/src/libcore/num/strconv.rs +++ b/src/libcore/num/strconv.rs @@ -9,15 +9,6 @@ // except according to those terms. use core::cmp::{Ord, Eq}; -#[cfg(stage0)] -use ops::{Add, Sub, Mul, Neg}; -#[cfg(stage0)] -use Quot = ops::Div; -#[cfg(stage0)] -use Rem = ops::Modulo; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] use ops::{Add, Sub, Mul, Quot, Rem, Neg}; use option::{None, Option, Some}; use char; diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index 3dfdd22c42dc1..f975226cde63b 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -165,24 +165,10 @@ impl Mul for T { #[inline(always)] fn mul(&self, other: &T) -> T { *self * *other } } - -#[cfg(stage0,notest)] -impl Div for T { - #[inline(always)] - fn div(&self, other: &T) -> T { *self / *other } -} -#[cfg(not(stage0),notest)] impl Quot for T { #[inline(always)] fn quot(&self, other: &T) -> T { *self / *other } } - -#[cfg(stage0,notest)] -impl Modulo for T { - #[inline(always)] - fn modulo(&self, other: &T) -> T { *self % *other } -} -#[cfg(not(stage0),notest)] impl Rem for T { #[inline(always)] fn rem(&self, other: &T) -> T { *self % *other } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 1aa7aada05c88..18dcf34e49bfb 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -30,24 +30,12 @@ pub trait Mul { fn mul(&self, rhs: &RHS) -> Result; } -#[lang="div"] -#[cfg(stage0)] -pub trait Div { - fn div(&self, rhs: &RHS) -> Result; -} #[lang="quot"] -#[cfg(not(stage0))] pub trait Quot { fn quot(&self, rhs: &RHS) -> Result; } -#[lang="modulo"] -#[cfg(stage0)] -pub trait Modulo { - fn modulo(&self, rhs: &RHS) -> Result; -} #[lang="rem"] -#[cfg(not(stage0))] pub trait Rem { fn rem(&self, rhs: &RHS) -> Result; } diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 9a2e480ce6e54..318725d2822a5 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -14,9 +14,6 @@ pub use either::{Either, Left, Right}; pub use kinds::{Const, Copy, Owned, Durable}; -#[cfg(stage0)] -pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not}; -#[cfg(not(stage0))] pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Drop}; diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs index 2d6412b0cc832..abcb727809eea 100644 --- a/src/libcore/repr.rs +++ b/src/libcore/repr.rs @@ -23,7 +23,6 @@ use io::{Writer, WriterUtil}; use libc::c_void; use managed; use ptr; -#[cfg(stage0)] use sys; use reflect; use reflect::{MovePtr, align}; use to_str::ToStr; diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs index b035532144c44..cb00b02d9d1b6 100644 --- a/src/libcore/rt/io/mod.rs +++ b/src/libcore/rt/io/mod.rs @@ -125,18 +125,15 @@ pub mod file; pub mod net; /// Readers and Writers for memory buffers and strings. -#[cfg(not(stage0))] // XXX Using unsnapshotted features pub mod mem; /// Non-blocking access to stdin, stdout, stderr pub mod stdio; /// Basic stream compression. XXX: Belongs with other flate code -#[cfg(not(stage0))] // XXX Using unsnapshotted features pub mod flate; /// Interop between byte streams and pipes. Not sure where it belongs -#[cfg(not(stage0))] // XXX " pub mod comm_adapters; /// Extension traits diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 0a5348d79760e..40db9f89d0fd7 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -91,13 +91,10 @@ pub mod cmp; pub mod base64; pub mod rl; pub mod workcache; -#[cfg(not(stage0))] #[path="num/bigint.rs"] pub mod bigint; -#[cfg(not(stage0))] #[path="num/rational.rs"] pub mod rational; -#[cfg(not(stage0))] #[path="num/complex.rs"] pub mod complex; pub mod stats; From a896440ca1b93cc5dc6edd827ea2ae89602bfa9e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 15 Mar 2013 15:24:24 -0400 Subject: [PATCH 050/215] new borrow checker (mass squash) --- src/libcore/cleanup.rs | 40 +- src/libcore/io.rs | 14 +- src/libcore/rt/sched/mod.rs | 2 +- src/libcore/str.rs | 12 - src/libcore/to_bytes.rs | 2 +- src/libcore/unstable/lang.rs | 47 +- src/libcore/vec.rs | 11 +- src/librustc/driver/driver.rs | 21 +- src/librustc/driver/session.rs | 8 + src/librustc/front/test.rs | 5 +- src/librustc/metadata/decoder.rs | 4 +- src/librustc/metadata/tydecode.rs | 3 + src/librustc/metadata/tyencode.rs | 48 +- src/librustc/middle/astencode.rs | 43 +- src/librustc/middle/borrowck/check_loans.rs | 1063 ++++++++--------- src/librustc/middle/borrowck/doc.rs | 750 ++++++++++++ src/librustc/middle/borrowck/gather_loans.rs | 643 ---------- .../middle/borrowck/gather_loans/lifetime.rs | 322 +++++ .../middle/borrowck/gather_loans/mod.rs | 710 +++++++++++ .../borrowck/gather_loans/restrictions.rs | 251 ++++ src/librustc/middle/borrowck/loan.rs | 312 ----- src/librustc/middle/borrowck/mod.rs | 861 ++++++------- src/librustc/middle/borrowck/preserve.rs | 409 ------- src/librustc/middle/const_eval.rs | 2 - src/librustc/middle/dataflow.rs | 1009 ++++++++++++++++ src/librustc/middle/kind.rs | 8 +- src/librustc/middle/lang_items.rs | 66 +- src/librustc/middle/liveness.rs | 105 +- src/librustc/middle/mem_categorization.rs | 546 ++++----- src/librustc/middle/moves.rs | 28 +- src/librustc/middle/region.rs | 318 ++--- src/librustc/middle/resolve.rs | 12 +- src/librustc/middle/trans/_match.rs | 7 +- src/librustc/middle/trans/base.rs | 109 +- src/librustc/middle/trans/callee.rs | 2 - src/librustc/middle/trans/common.rs | 9 +- src/librustc/middle/trans/consts.rs | 11 +- src/librustc/middle/trans/datum.rs | 7 +- src/librustc/middle/trans/expr.rs | 54 +- src/librustc/middle/trans/inline.rs | 39 +- src/librustc/middle/trans/meth.rs | 5 + src/librustc/middle/trans/monomorphize.rs | 4 + src/librustc/middle/trans/reachable.rs | 58 +- src/librustc/middle/ty.rs | 100 +- src/librustc/middle/typeck/check/_match.rs | 6 +- src/librustc/middle/typeck/check/method.rs | 47 +- src/librustc/middle/typeck/check/mod.rs | 54 +- src/librustc/middle/typeck/check/regionck.rs | 571 +++++---- .../middle/typeck/check/regionmanip.rs | 3 +- src/librustc/middle/typeck/check/writeback.rs | 29 +- src/librustc/middle/typeck/coherence.rs | 12 +- src/librustc/middle/typeck/infer/coercion.rs | 48 +- src/librustc/middle/typeck/infer/mod.rs | 81 +- .../middle/typeck/infer/region_inference.rs | 253 ++-- src/librustc/middle/typeck/infer/unify.rs | 35 +- src/librustc/util/ppaux.rs | 17 +- src/libstd/arc.rs | 12 +- src/libstd/bitv.rs | 14 +- src/libstd/net_tcp.rs | 6 +- src/libstd/serialize.rs | 15 - src/libstd/sort.rs | 70 +- src/libstd/std.rc | 1 - src/libsyntax/ast_map.rs | 69 +- src/libsyntax/ast_util.rs | 24 +- src/libsyntax/codemap.rs | 4 +- src/libsyntax/ext/base.rs | 108 +- src/libsyntax/ext/expand.rs | 3 + src/libsyntax/ext/pipes/liveness.rs | 4 +- src/libsyntax/ext/pipes/proto.rs | 18 +- src/libsyntax/print/pp.rs | 4 +- src/libsyntax/print/pprust.rs | 8 +- src/libsyntax/util/interner.rs | 4 +- src/libsyntax/visit.rs | 6 + .../compile-fail/access-mode-in-closures.rs | 2 +- .../arc-rw-read-mode-shouldnt-escape.rs | 1 + .../arc-rw-write-mode-shouldnt-escape.rs | 1 + .../attempted-access-non-fatal.rs | 4 +- .../compile-fail/borrowck-addr-of-upvar.rs | 4 +- .../compile-fail/borrowck-assign-comp-idx.rs | 10 +- src/test/compile-fail/borrowck-assign-comp.rs | 18 +- .../borrowck-assign-to-constants.rs | 4 +- .../compile-fail/borrowck-assign-to-enum.rs | 2 +- .../borrowck-assign-to-subfield.rs | 2 +- ... => borrowck-auto-mut-ref-to-immut-var.rs} | 10 +- .../compile-fail/borrowck-autoref-3261.rs | 4 +- .../borrowck-bad-nested-calls-free.rs | 43 + .../borrowck-bad-nested-calls-move.rs | 43 + .../borrowck-borrow-from-owned-ptr.rs | 70 +- .../borrowck-borrow-from-stack-variable.rs | 67 +- .../borrowck-borrowed-uniq-rvalue-2.rs | 3 +- .../borrowck-borrowed-uniq-rvalue.rs | 2 +- ...borrowck-call-method-from-mut-aliasable.rs | 8 +- ...k-imm-ref-to-mut-rec-field-issue-3162-c.rs | 4 +- .../borrowck-insert-during-each.rs | 4 +- .../compile-fail/borrowck-issue-2657-1.rs | 4 +- .../compile-fail/borrowck-issue-2657-2.rs | 2 +- .../compile-fail/borrowck-lend-flow-if.rs | 52 + .../compile-fail/borrowck-lend-flow-loop.rs | 164 +++ .../compile-fail/borrowck-lend-flow-match.rs | 60 + src/test/compile-fail/borrowck-lend-flow.rs | 93 +- .../borrowck-loan-blocks-move-cc.rs | 8 +- .../compile-fail/borrowck-loan-blocks-move.rs | 4 +- .../borrowck-loan-blocks-mut-uniq.rs | 4 +- ...borrowck-loan-local-as-both-mut-and-imm.rs | 4 +- .../borrowck-loan-rcvr-overloaded-op.rs | 6 +- src/test/compile-fail/borrowck-loan-rcvr.rs | 24 +- .../compile-fail/borrowck-loan-vec-content.rs | 4 +- .../compile-fail/borrowck-move-by-capture.rs | 2 +- .../borrowck-mut-addr-of-imm-var.rs | 2 +- .../compile-fail/borrowck-mut-boxed-vec.rs | 4 +- .../compile-fail/borrowck-mut-deref-comp.rs | 4 +- .../borrowck-mut-slice-of-imm-vec.rs | 2 +- .../borrowck-no-cycle-in-exchange-heap.rs | 4 +- .../borrowck-pat-by-value-binding.rs | 11 +- src/test/compile-fail/borrowck-pat-enum.rs | 14 +- .../borrowck-pat-reassign-binding.rs | 11 +- ...borrowck-pat-reassign-sometimes-binding.rs | 26 - .../borrowck-reborrow-from-mut.rs | 22 +- .../compile-fail/borrowck-ref-into-rvalue.rs | 8 +- .../compile-fail/borrowck-ref-mut-of-imm.rs | 2 +- .../compile-fail/borrowck-unary-move-2.rs | 2 +- src/test/compile-fail/borrowck-unary-move.rs | 4 +- .../compile-fail/borrowck-uniq-via-box.rs | 55 - .../compile-fail/borrowck-uniq-via-lend.rs | 8 +- .../compile-fail/borrowck-uniq-via-ref.rs | 7 +- .../borrowck-vec-pattern-element-loan.rs | 12 +- .../borrowck-vec-pattern-loan-from-mut.rs | 2 +- .../borrowck-vec-pattern-move-tail.rs | 5 +- .../borrowck-vec-pattern-nesting.rs | 4 +- .../borrowck-vec-pattern-tail-element-loan.rs | 4 +- .../borrowck-wg-borrow-mut-to-imm-fail-2.rs | 4 +- .../borrowck-wg-borrow-mut-to-imm-fail-3.rs | 4 +- .../borrowck-wg-borrow-mut-to-imm-fail.rs | 4 +- .../compile-fail/borrowck-wg-move-base-2.rs | 2 +- src/test/compile-fail/fn-variance-3.rs | 2 +- .../compile-fail/immut-function-arguments.rs | 4 +- src/test/compile-fail/index_message.rs | 2 +- src/test/compile-fail/issue-1896-1.rs | 4 +- src/test/compile-fail/issue-2149.rs | 1 - src/test/compile-fail/issue-2151.rs | 3 +- src/test/compile-fail/issue-2590.rs | 2 +- src/test/compile-fail/issue-3044.rs | 1 - src/test/compile-fail/issue-511.rs | 2 +- .../kindck-owned-trait-contains.rs | 3 + src/test/compile-fail/lambda-mutate-nested.rs | 2 +- src/test/compile-fail/lambda-mutate.rs | 2 +- .../moves-based-on-type-block-bad.rs | 2 +- ...type-move-out-of-closure-env-issue-1965.rs | 2 +- .../compile-fail/mutable-class-fields-2.rs | 3 +- src/test/compile-fail/mutable-class-fields.rs | 5 +- .../compile-fail/mutable-huh-ptr-assign.rs | 2 +- src/test/compile-fail/regions-addr-of-arg.rs | 2 +- .../compile-fail/regions-creating-enums.rs | 4 +- .../compile-fail/regions-creating-enums4.rs | 3 +- .../compile-fail/regions-escape-bound-fn.rs | 2 +- .../regions-escape-loop-via-variable.rs | 2 +- .../regions-escape-loop-via-vec.rs | 4 +- .../regions-escape-via-trait-or-not.rs | 7 +- .../regions-infer-borrow-scope-too-big.rs | 2 +- .../regions-infer-borrow-scope-within-loop.rs | 2 +- src/test/compile-fail/regions-nested-fns-2.rs | 2 +- src/test/compile-fail/regions-nested-fns.rs | 2 +- .../compile-fail/regions-ret-borrowed-1.rs | 1 + src/test/compile-fail/regions-ret-borrowed.rs | 1 + src/test/compile-fail/regions-ret.rs | 2 +- .../regions-var-type-out-of-scope.rs | 2 +- src/test/compile-fail/swap-no-lval.rs | 4 +- .../compile-fail/writing-to-immutable-vec.rs | 6 +- .../borrowck-nested-calls.rs} | 24 +- .../run-pass/coerce-reborrow-mut-vec-rcvr.rs | 6 +- src/test/run-pass/issue-2735-2.rs | 18 +- src/test/run-pass/issue-2735-3.rs | 18 +- 172 files changed, 6449 insertions(+), 4277 deletions(-) create mode 100644 src/librustc/middle/borrowck/doc.rs delete mode 100644 src/librustc/middle/borrowck/gather_loans.rs create mode 100644 src/librustc/middle/borrowck/gather_loans/lifetime.rs create mode 100644 src/librustc/middle/borrowck/gather_loans/mod.rs create mode 100644 src/librustc/middle/borrowck/gather_loans/restrictions.rs delete mode 100644 src/librustc/middle/borrowck/loan.rs delete mode 100644 src/librustc/middle/borrowck/preserve.rs create mode 100644 src/librustc/middle/dataflow.rs rename src/test/compile-fail/{auto-ref-borrowck-failure.rs => borrowck-auto-mut-ref-to-immut-var.rs} (81%) create mode 100644 src/test/compile-fail/borrowck-bad-nested-calls-free.rs create mode 100644 src/test/compile-fail/borrowck-bad-nested-calls-move.rs create mode 100644 src/test/compile-fail/borrowck-lend-flow-if.rs create mode 100644 src/test/compile-fail/borrowck-lend-flow-loop.rs create mode 100644 src/test/compile-fail/borrowck-lend-flow-match.rs delete mode 100644 src/test/compile-fail/borrowck-pat-reassign-sometimes-binding.rs delete mode 100644 src/test/compile-fail/borrowck-uniq-via-box.rs rename src/test/{compile-fail/issue-4500.rs => run-pass/borrowck-nested-calls.rs} (51%) diff --git a/src/libcore/cleanup.rs b/src/libcore/cleanup.rs index a07c6b4811b6c..1dfe1b22dc4fb 100644 --- a/src/libcore/cleanup.rs +++ b/src/libcore/cleanup.rs @@ -126,14 +126,17 @@ struct AnnihilateStats { n_bytes_freed: uint } -unsafe fn each_live_alloc(f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) { +unsafe fn each_live_alloc(read_next_before: bool, + f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) { + //! Walks the internal list of allocations + use managed; let task: *Task = transmute(rustrt::rust_get_task()); let box = (*task).boxed_region.live_allocs; let mut box: *mut BoxRepr = transmute(copy box); while box != mut_null() { - let next = transmute(copy (*box).header.next); + let next_before = transmute(copy (*box).header.next); let uniq = (*box).header.ref_count == managed::raw::RC_MANAGED_UNIQUE; @@ -141,7 +144,11 @@ unsafe fn each_live_alloc(f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) { break } - box = next + if read_next_before { + box = next_before; + } else { + box = transmute(copy (*box).header.next); + } } } @@ -159,7 +166,7 @@ fn debug_mem() -> bool { #[cfg(notest)] #[lang="annihilate"] pub unsafe fn annihilate() { - use unstable::lang::local_free; + use unstable::lang::{local_free, debug_ptr}; use io::WriterUtil; use io; use libc; @@ -173,27 +180,46 @@ pub unsafe fn annihilate() { }; // Pass 1: Make all boxes immortal. - for each_live_alloc |box, uniq| { + // + // In this pass, nothing gets freed, so it does not matter whether + // we read the next field before or after the callback. + for each_live_alloc(true) |box, uniq| { stats.n_total_boxes += 1; if uniq { + debug_ptr("Managed-uniq: ", &*box); stats.n_unique_boxes += 1; } else { + debug_ptr("Immortalizing: ", &*box); (*box).header.ref_count = managed::raw::RC_IMMORTAL; } } // Pass 2: Drop all boxes. - for each_live_alloc |box, uniq| { + // + // In this pass, unique-managed boxes may get freed, but not + // managed boxes, so we must read the `next` field *after* the + // callback, as the original value may have been freed. + for each_live_alloc(false) |box, uniq| { if !uniq { + debug_ptr("Invoking tydesc/glue on: ", &*box); let tydesc: *TypeDesc = transmute(copy (*box).header.type_desc); let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0)); + debug_ptr("Box data: ", &(*box).data); + debug_ptr("Type descriptor: ", tydesc); drop_glue(to_unsafe_ptr(&tydesc), transmute(&(*box).data)); + debug_ptr("Dropped ", &*box); } } // Pass 3: Free all boxes. - for each_live_alloc |box, uniq| { + // + // In this pass, managed boxes may get freed (but not + // unique-managed boxes, though I think that none of those are + // left), so we must read the `next` field before, since it will + // not be valid after. + for each_live_alloc(true) |box, uniq| { if !uniq { + debug_ptr("About to free: ", &*box); stats.n_bytes_freed += (*((*box).header.type_desc)).size + sys::size_of::(); diff --git a/src/libcore/io.rs b/src/libcore/io.rs index 35ffd88c8f477..217ea1a9982c1 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -1022,7 +1022,7 @@ pub enum WriterType { Screen, File } pub trait Writer { /// Write all of the given bytes. - fn write(&self, v: &const [u8]); + fn write(&self, v: &[u8]); /// Move the current position within the stream. The second parameter /// determines the position that the first parameter is relative to. @@ -1039,7 +1039,7 @@ pub trait Writer { } impl Writer for @Writer { - fn write(&self, v: &const [u8]) { self.write(v) } + fn write(&self, v: &[u8]) { self.write(v) } fn seek(&self, a: int, b: SeekStyle) { self.seek(a, b) } fn tell(&self) -> uint { self.tell() } fn flush(&self) -> int { self.flush() } @@ -1047,7 +1047,7 @@ impl Writer for @Writer { } impl Writer for Wrapper { - fn write(&self, bs: &const [u8]) { self.base.write(bs); } + fn write(&self, bs: &[u8]) { self.base.write(bs); } fn seek(&self, off: int, style: SeekStyle) { self.base.seek(off, style); } fn tell(&self) -> uint { self.base.tell() } fn flush(&self) -> int { self.base.flush() } @@ -1055,7 +1055,7 @@ impl Writer for Wrapper { } impl Writer for *libc::FILE { - fn write(&self, v: &const [u8]) { + fn write(&self, v: &[u8]) { unsafe { do vec::as_const_buf(v) |vbuf, len| { let nout = libc::fwrite(vbuf as *c_void, @@ -1105,7 +1105,7 @@ pub fn FILE_writer(f: *libc::FILE, cleanup: bool) -> @Writer { } impl Writer for fd_t { - fn write(&self, v: &const [u8]) { + fn write(&self, v: &[u8]) { unsafe { let mut count = 0u; do vec::as_const_buf(v) |vbuf, len| { @@ -1262,7 +1262,7 @@ pub fn u64_to_be_bytes(n: u64, size: uint, } } -pub fn u64_from_be_bytes(data: &const [u8], +pub fn u64_from_be_bytes(data: &[u8], start: uint, size: uint) -> u64 { @@ -1497,7 +1497,7 @@ pub struct BytesWriter { } impl Writer for BytesWriter { - fn write(&self, v: &const [u8]) { + fn write(&self, v: &[u8]) { let v_len = v.len(); let bytes_len = vec::uniq_len(&const self.bytes); diff --git a/src/libcore/rt/sched/mod.rs b/src/libcore/rt/sched/mod.rs index 28946281628b1..a2132676c1a03 100644 --- a/src/libcore/rt/sched/mod.rs +++ b/src/libcore/rt/sched/mod.rs @@ -304,7 +304,7 @@ pub impl Scheduler { unsafe { let last_task = transmute::, Option<&mut Task>>(last_task); let last_task_context = match last_task { - Some(ref t) => Some(&mut t.saved_context), None => None + Some(t) => Some(&mut t.saved_context), None => None }; let next_task_context = match self.current_task { Some(ref mut t) => Some(&mut t.saved_context), None => None diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 064bffa00561f..f4430ca669fb1 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -2356,9 +2356,6 @@ pub trait StrSlice<'self> { fn any(&self, it: &fn(char) -> bool) -> bool; fn contains<'a>(&self, needle: &'a str) -> bool; fn contains_char(&self, needle: char) -> bool; - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn char_iter(&self) -> StrCharIterator<'self>; fn each(&self, it: &fn(u8) -> bool); fn eachi(&self, it: &fn(uint, u8) -> bool); @@ -2420,9 +2417,6 @@ impl<'self> StrSlice<'self> for &'self str { contains_char(*self, needle) } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline] fn char_iter(&self) -> StrCharIterator<'self> { StrCharIterator { @@ -2615,17 +2609,11 @@ impl Clone for ~str { } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub struct StrCharIterator<'self> { priv index: uint, priv string: &'self str, } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl<'self> Iterator for StrCharIterator<'self> { #[inline] fn next(&mut self) -> Option { diff --git a/src/libcore/to_bytes.rs b/src/libcore/to_bytes.rs index 7b4b6994e50a5..63dcf0f44dc3b 100644 --- a/src/libcore/to_bytes.rs +++ b/src/libcore/to_bytes.rs @@ -19,7 +19,7 @@ use io::Writer; use option::{None, Option, Some}; use str; -pub type Cb<'self> = &'self fn(buf: &const [u8]) -> bool; +pub type Cb<'self> = &'self fn(buf: &[u8]) -> bool; /** * A trait to implement in order to make a type hashable; diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index de0542afc399a..cf71b01aeaeeb 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -11,7 +11,7 @@ //! Runtime calls emitted by the compiler. use cast::transmute; -use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int}; +use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int, STDERR_FILENO}; use managed::raw::BoxRepr; use str; use sys; @@ -74,7 +74,44 @@ pub fn fail_borrowed() { #[lang="exchange_malloc"] #[inline(always)] pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { - transmute(exchange_alloc::malloc(transmute(td), transmute(size))) + let result = transmute(exchange_alloc::malloc(transmute(td), transmute(size))); + debug_ptr("exchange_malloc: ", result); + return result; +} + +/// Because this code is so perf. sensitive, use a static constant so that +/// debug printouts are compiled out most of the time. +static ENABLE_DEBUG_PTR: bool = false; + +#[inline] +pub fn debug_ptr(tag: &'static str, p: *T) { + //! A useful debugging function that prints a pointer + tag + newline + //! without allocating memory. + + if ENABLE_DEBUG_PTR && ::rt::env::get().debug_mem { + debug_ptr_slow(tag, p); + } + + fn debug_ptr_slow(tag: &'static str, p: *T) { + use io; + let dbg = STDERR_FILENO as io::fd_t; + let letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', + '9', 'a', 'b', 'c', 'd', 'e', 'f']; + dbg.write_str(tag); + + static uint_nibbles: uint = ::uint::bytes << 1; + let mut buffer = [0_u8, ..uint_nibbles+1]; + let mut i = p as uint; + let mut c = uint_nibbles; + while c > 0 { + c -= 1; + buffer[c] = letters[i & 0xF] as u8; + i >>= 4; + } + dbg.write(buffer.slice(0, uint_nibbles)); + + dbg.write_str("\n"); + } } // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from @@ -83,13 +120,16 @@ pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { #[lang="exchange_free"] #[inline(always)] pub unsafe fn exchange_free(ptr: *c_char) { + debug_ptr("exchange_free: ", ptr); exchange_alloc::free(transmute(ptr)) } #[lang="malloc"] #[inline(always)] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { - return rustrt::rust_upcall_malloc_noswitch(td, size); + let result = rustrt::rust_upcall_malloc_noswitch(td, size); + debug_ptr("local_malloc: ", result); + return result; } // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from @@ -98,6 +138,7 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { #[lang="free"] #[inline(always)] pub unsafe fn local_free(ptr: *c_char) { + debug_ptr("local_free: ", ptr); rustrt::rust_upcall_free_noswitch(ptr); } diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 94f866643532c..2f9488d1bc7a7 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -19,9 +19,6 @@ use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; use clone::Clone; use old_iter::BaseIter; use old_iter; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] use iterator::Iterator; use kinds::Copy; use libc; @@ -1824,7 +1821,7 @@ pub trait CopyableVector { } /// Extension methods for vectors -impl<'self,T:Copy> CopyableVector for &'self const [T] { +impl<'self,T:Copy> CopyableVector for &'self [T] { /// Returns a copy of `v`. #[inline] fn to_owned(&self) -> ~[T] { @@ -2710,18 +2707,12 @@ impl Clone for ~[A] { } // could be implemented with &[T] with .slice(), but this avoids bounds checks -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub struct VecIterator<'self, T> { priv ptr: *T, priv end: *T, priv lifetime: &'self T // FIXME: #5922 } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl<'self, T> Iterator<&'self T> for VecIterator<'self, T> { #[inline] fn next(&mut self) -> Option<&'self T> { diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 2e64c0c45bffe..e899b1abc2648 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -263,7 +263,7 @@ pub fn compile_rest(sess: Session, middle::check_loop::check_crate(ty_cx, crate)); let middle::moves::MoveMaps {moves_map, variable_moves_map, - capture_map} = + moved_variables_set, capture_map} = time(time_passes, ~"compute moves", || middle::moves::compute_moves(ty_cx, method_map, crate)); @@ -271,20 +271,19 @@ pub fn compile_rest(sess: Session, middle::check_match::check_crate(ty_cx, method_map, moves_map, crate)); - let last_use_map = - time(time_passes, ~"liveness checking", || - middle::liveness::check_crate(ty_cx, method_map, - variable_moves_map, - capture_map, crate)); + time(time_passes, ~"liveness checking", || + middle::liveness::check_crate(ty_cx, method_map, + variable_moves_map, + capture_map, crate)); - let (root_map, mutbl_map, write_guard_map) = + let (root_map, write_guard_map) = time(time_passes, ~"borrow checking", || middle::borrowck::check_crate(ty_cx, method_map, - moves_map, capture_map, - crate)); + moves_map, moved_variables_set, + capture_map, crate)); time(time_passes, ~"kind checking", || - kind::check_crate(ty_cx, method_map, last_use_map, crate)); + kind::check_crate(ty_cx, method_map, crate)); time(time_passes, ~"lint checking", || lint::check_crate(ty_cx, crate)); @@ -292,9 +291,7 @@ pub fn compile_rest(sess: Session, if upto == cu_no_trans { return (crate, Some(ty_cx)); } let maps = astencode::Maps { - mutbl_map: mutbl_map, root_map: root_map, - last_use_map: last_use_map, method_map: method_map, vtable_map: vtable_map, write_guard_map: write_guard_map, diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 55c81e6d17b20..fff97d2436af3 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -173,15 +173,19 @@ pub type Session = @Session_; pub impl Session_ { fn span_fatal(@self, sp: span, msg: ~str) -> ! { + debug!("span_fatal invoked: %s", msg); self.span_diagnostic.span_fatal(sp, msg) } fn fatal(@self, msg: ~str) -> ! { + debug!("fatal invoked: %s", msg); self.span_diagnostic.handler().fatal(msg) } fn span_err(@self, sp: span, msg: ~str) { + debug!("span_err invoked: %s", msg); self.span_diagnostic.span_err(sp, msg) } fn err(@self, msg: ~str) { + debug!("err invoked: %s", msg); self.span_diagnostic.handler().err(msg) } fn has_errors(@self) -> bool { @@ -191,15 +195,19 @@ pub impl Session_ { self.span_diagnostic.handler().abort_if_errors() } fn span_warn(@self, sp: span, msg: ~str) { + debug!("span_warn invoked: %s", msg); self.span_diagnostic.span_warn(sp, msg) } fn warn(@self, msg: ~str) { + debug!("warn invoked: %s", msg); self.span_diagnostic.handler().warn(msg) } fn span_note(@self, sp: span, msg: ~str) { + debug!("span_note invoked: %s", msg); self.span_diagnostic.span_note(sp, msg) } fn note(@self, msg: ~str) { + debug!("note invoked: %s", msg); self.span_diagnostic.handler().note(msg) } fn span_bug(@self, sp: span, msg: ~str) -> ! { diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 02e2a4c8734f8..22bce62336cab 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -69,7 +69,8 @@ fn generate_test_harness(sess: session::Session, testfns: ~[] }; - cx.ext_cx.bt_push(ExpandedFrom(CallInfo { + let ext_cx = cx.ext_cx; + ext_cx.bt_push(ExpandedFrom(CallInfo { call_site: dummy_sp(), callee: NameAndSpan { name: ~"test", @@ -84,7 +85,7 @@ fn generate_test_harness(sess: session::Session, let fold = fold::make_fold(precursor); let res = @fold.fold_crate(&*crate); - cx.ext_cx.bt_pop(); + ext_cx.bt_pop(); return res; } diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index cfe31360d321b..1a94b57279cc4 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -244,8 +244,8 @@ fn doc_transformed_self_ty(doc: ebml::Doc, } } -pub fn item_type(_: ast::def_id, item: ebml::Doc, tcx: ty::ctxt, cdata: cmd) - -> ty::t { +pub fn item_type(_item_id: ast::def_id, item: ebml::Doc, + tcx: ty::ctxt, cdata: cmd) -> ty::t { doc_type(item, tcx, cdata) } diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 011ee115e8c15..963afa08bfe33 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -245,6 +245,9 @@ fn parse_region(st: @mut PState) -> ty::Region { 't' => { ty::re_static } + 'e' => { + ty::re_static + } _ => fail!(~"parse_region: bad input") } } diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 763b1984b81c8..fdba3ac4f00ab 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -71,30 +71,29 @@ pub fn enc_ty(w: @io::Writer, cx: @ctxt, t: ty::t) { w.write_str(result_str); } ac_use_abbrevs(abbrevs) => { - match abbrevs.find(&t) { - Some(a) => { w.write_str(*a.s); return; } - None => { - let pos = w.tell(); - enc_sty(w, cx, /*bad*/copy ty::get(t).sty); - let end = w.tell(); - let len = end - pos; - fn estimate_sz(u: uint) -> uint { - let mut n = u; - let mut len = 0u; - while n != 0u { len += 1u; n = n >> 4u; } - return len; - } - let abbrev_len = 3u + estimate_sz(pos) + estimate_sz(len); - if abbrev_len < len { - // I.e. it's actually an abbreviation. - let s = ~"#" + uint::to_str_radix(pos, 16u) + ~":" + - uint::to_str_radix(len, 16u) + ~"#"; - let a = ty_abbrev { pos: pos, len: len, s: @s }; - abbrevs.insert(t, a); - } - return; + match abbrevs.find(&t) { + Some(a) => { w.write_str(*a.s); return; } + None => {} } - } + let pos = w.tell(); + enc_sty(w, cx, /*bad*/copy ty::get(t).sty); + let end = w.tell(); + let len = end - pos; + fn estimate_sz(u: uint) -> uint { + let mut n = u; + let mut len = 0u; + while n != 0u { len += 1u; n = n >> 4u; } + return len; + } + let abbrev_len = 3u + estimate_sz(pos) + estimate_sz(len); + if abbrev_len < len { + // I.e. it's actually an abbreviation. + let s = ~"#" + uint::to_str_radix(pos, 16u) + ~":" + + uint::to_str_radix(len, 16u) + ~"#"; + let a = ty_abbrev { pos: pos, len: len, s: @s }; + abbrevs.insert(t, a); + } + return; } } } @@ -152,6 +151,9 @@ fn enc_region(w: @io::Writer, cx: @ctxt, r: ty::Region) { ty::re_static => { w.write_char('t'); } + ty::re_empty => { + w.write_char('e'); + } ty::re_infer(_) => { // these should not crop up after typeck cx.diag.handler().bug(~"Cannot encode region variables"); diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index c65521228fa87..7a3bdce875da2 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -44,9 +44,7 @@ use writer = std::ebml::writer; // Auxiliary maps of things to be encoded pub struct Maps { - mutbl_map: middle::borrowck::mutbl_map, root_map: middle::borrowck::root_map, - last_use_map: middle::liveness::last_use_map, method_map: middle::typeck::method_map, vtable_map: middle::typeck::vtable_map, write_guard_map: middle::borrowck::write_guard_map, @@ -151,7 +149,7 @@ pub fn decode_inlined_item(cdata: @cstore::crate_metadata, fn reserve_id_range(sess: Session, from_id_range: ast_util::id_range) -> ast_util::id_range { // Handle the case of an empty range: - if ast_util::empty(from_id_range) { return from_id_range; } + if from_id_range.empty() { return from_id_range; } let cnt = from_id_range.max - from_id_range.min; let to_id_min = sess.parse_sess.next_id; let to_id_max = sess.parse_sess.next_id + cnt; @@ -162,7 +160,6 @@ fn reserve_id_range(sess: Session, pub impl ExtendedDecodeContext { fn tr_id(&self, id: ast::node_id) -> ast::node_id { /*! - * * Translates an internal id, meaning a node id that is known * to refer to some part of the item currently being inlined, * such as a local variable or argument. All naked node-ids @@ -173,12 +170,11 @@ pub impl ExtendedDecodeContext { */ // from_id_range should be non-empty - assert!(!ast_util::empty(self.from_id_range)); + assert!(!self.from_id_range.empty()); (id - self.from_id_range.min + self.to_id_range.min) } fn tr_def_id(&self, did: ast::def_id) -> ast::def_id { /*! - * * Translates an EXTERNAL def-id, converting the crate number * from the one used in the encoded data to the current crate * numbers.. By external, I mean that it be translated to a @@ -203,7 +199,6 @@ pub impl ExtendedDecodeContext { } fn tr_intern_def_id(&self, did: ast::def_id) -> ast::def_id { /*! - * * Translates an INTERNAL def-id, meaning a def-id that is * known to refer to some part of the item currently being * inlined. In that case, we want to convert the def-id to @@ -461,11 +456,7 @@ impl tr for ty::AutoAdjustment { impl tr for ty::AutoRef { fn tr(&self, xcx: @ExtendedDecodeContext) -> ty::AutoRef { - ty::AutoRef { - kind: self.kind, - region: self.region.tr(xcx), - mutbl: self.mutbl, - } + self.map_region(|r| r.tr(xcx)) } } @@ -474,7 +465,7 @@ impl tr for ty::Region { match *self { ty::re_bound(br) => ty::re_bound(br.tr(xcx)), ty::re_scope(id) => ty::re_scope(xcx.tr_id(id)), - ty::re_static | ty::re_infer(*) => *self, + ty::re_empty | ty::re_static | ty::re_infer(*) => *self, ty::re_free(ref fr) => { ty::re_free(ty::FreeRegion {scope_id: xcx.tr_id(fr.scope_id), bound_region: fr.bound_region.tr(xcx)}) @@ -914,23 +905,6 @@ fn encode_side_tables_for_id(ecx: @e::EncodeContext, } } - if maps.mutbl_map.contains(&id) { - do ebml_w.tag(c::tag_table_mutbl) { - ebml_w.id(id); - } - } - - for maps.last_use_map.find(&id).each |&m| { - do ebml_w.tag(c::tag_table_last_use) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - do ebml_w.emit_from_vec(/*bad*/ copy **m) |id| { - id.encode(ebml_w); - } - } - } - } - for maps.method_map.find(&id).each |&mme| { do ebml_w.tag(c::tag_table_method_map) { ebml_w.id(id); @@ -1108,9 +1082,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, found for id %d (orig %d)", tag, id, id0); - if tag == (c::tag_table_mutbl as uint) { - dcx.maps.mutbl_map.insert(id); - } else if tag == (c::tag_table_moves_map as uint) { + if tag == (c::tag_table_moves_map as uint) { dcx.maps.moves_map.insert(id); } else { let val_doc = entry_doc.get(c::tag_table_val as uint); @@ -1138,11 +1110,6 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, } else if tag == (c::tag_table_param_defs as uint) { let bounds = val_dsr.read_type_param_def(xcx); dcx.tcx.ty_param_defs.insert(id, bounds); - } else if tag == (c::tag_table_last_use as uint) { - let ids = val_dsr.read_to_vec(|| { - xcx.tr_id(val_dsr.read_int()) - }); - dcx.maps.last_use_map.insert(id, @mut ids); } else if tag == (c::tag_table_method_map as uint) { dcx.maps.method_map.insert( id, diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 07b6c80d4201c..56eb57009ca08 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -18,284 +18,143 @@ // 4. moves do not affect things loaned out in any way use middle::moves; -use middle::typeck::check::PurityState; -use middle::borrowck::{Loan, bckerr, BorrowckCtxt, inherent_mutability}; -use middle::borrowck::{ReqMaps, root_map_key, save_and_restore_managed}; -use middle::borrowck::{MoveError, MoveOk, MoveFromIllegalCmt}; -use middle::borrowck::{MoveWhileBorrowed}; -use middle::mem_categorization::{cat_arg, cat_comp, cat_deref}; -use middle::mem_categorization::{cat_local, cat_rvalue, cat_self}; -use middle::mem_categorization::{cat_special, cmt, gc_ptr, loan_path, lp_arg}; -use middle::mem_categorization::{lp_comp, lp_deref, lp_local}; +use middle::borrowck::*; +use mc = middle::mem_categorization; use middle::ty; -use util::ppaux::ty_to_str; - +use util::ppaux::Repr; use core::hashmap::HashSet; -use core::util::with; -use syntax::ast::m_mutbl; +use syntax::ast::{m_mutbl, m_imm, m_const}; use syntax::ast; use syntax::ast_util; -use syntax::codemap::span; -use syntax::print::pprust; use syntax::visit; +use syntax::codemap::span; -struct CheckLoanCtxt { +struct CheckLoanCtxt<'self> { bccx: @BorrowckCtxt, - req_maps: ReqMaps, - - reported: HashSet, - - declared_purity: @mut PurityState, - fn_args: @mut @~[ast::node_id] -} - -// if we are enforcing purity, why are we doing so? -#[deriving(Eq)] -enum purity_cause { - // enforcing purity because fn was declared pure: - pc_pure_fn, - - // enforce purity because we need to guarantee the - // validity of some alias; `bckerr` describes the - // reason we needed to enforce purity. - pc_cmt(bckerr) -} - -// if we're not pure, why? -#[deriving(Eq)] -enum impurity_cause { - // some surrounding block was marked as 'unsafe' - pc_unsafe, - - // nothing was unsafe, and nothing was pure - pc_default, + dfcx: &'self LoanDataFlow, + all_loans: &'self [Loan], + reported: @mut HashSet, } pub fn check_loans(bccx: @BorrowckCtxt, - req_maps: ReqMaps, - crate: @ast::crate) { + dfcx: &LoanDataFlow, + all_loans: &[Loan], + body: &ast::blk) { + debug!("check_loans(body id=%?)", body.node.id); + let clcx = @mut CheckLoanCtxt { bccx: bccx, - req_maps: req_maps, - reported: HashSet::new(), - declared_purity: @mut PurityState::function(ast::impure_fn, 0), - fn_args: @mut @~[] + dfcx: dfcx, + all_loans: all_loans, + reported: @mut HashSet::new(), }; + let vt = visit::mk_vt(@visit::Visitor {visit_expr: check_loans_in_expr, visit_local: check_loans_in_local, visit_block: check_loans_in_block, + visit_pat: check_loans_in_pat, visit_fn: check_loans_in_fn, .. *visit::default_visitor()}); - visit::visit_crate(crate, clcx, vt); + (vt.visit_block)(body, clcx, vt); } -#[deriving(Eq)] -enum assignment_type { - at_straight_up, - at_swap +enum MoveError { + MoveOk, + MoveFromIllegalCmt(mc::cmt), + MoveWhileBorrowed(/*loan*/@LoanPath, /*loan*/span) } -pub impl assignment_type { - fn checked_by_liveness(&self) -> bool { - // the liveness pass guarantees that immutable local variables - // are only assigned once; but it doesn't consider &mut - match *self { - at_straight_up => true, - at_swap => true - } - } - fn ing_form(&self, desc: ~str) -> ~str { - match *self { - at_straight_up => ~"assigning to " + desc, - at_swap => ~"swapping to and from " + desc - } - } -} - -pub impl CheckLoanCtxt { +pub impl<'self> CheckLoanCtxt<'self> { fn tcx(&self) -> ty::ctxt { self.bccx.tcx } - fn purity(&mut self, scope_id: ast::node_id) - -> Either + fn each_issued_loan(&self, + scope_id: ast::node_id, + op: &fn(&Loan) -> bool) { - let default_purity = match self.declared_purity.purity { - // an unsafe declaration overrides all - ast::unsafe_fn => return Right(pc_unsafe), - - // otherwise, remember what was declared as the - // default, but we must scan for requirements - // imposed by the borrow check - ast::pure_fn => Left(pc_pure_fn), - ast::extern_fn | ast::impure_fn => Right(pc_default) - }; - - // scan to see if this scope or any enclosing scope requires - // purity. if so, that overrides the declaration. - - let mut scope_id = scope_id; - loop { - match self.req_maps.pure_map.find(&scope_id) { - None => (), - Some(e) => return Left(pc_cmt(*e)) - } - - match self.tcx().region_maps.opt_encl_scope(scope_id) { - None => return default_purity, - Some(next_scope_id) => scope_id = next_scope_id + //! Iterates over each loan that that has been issued + //! on entrance to `scope_id`, regardless of whether it is + //! actually *in scope* at that point. Sometimes loans + //! are issued for future scopes and thus they may have been + //! *issued* but not yet be in effect. + + for self.dfcx.each_bit_on_entry(scope_id) |loan_index| { + let loan = &self.all_loans[loan_index]; + if !op(loan) { + return; } } } - fn walk_loans(&self, - mut scope_id: ast::node_id, - f: &fn(v: &Loan) -> bool) { - - loop { - for self.req_maps.req_loan_map.find(&scope_id).each |loans| { - for loans.each |loan| { - if !f(loan) { return; } - } - } - - match self.tcx().region_maps.opt_encl_scope(scope_id) { - None => return, - Some(next_scope_id) => scope_id = next_scope_id, - } - } - } - - fn walk_loans_of(&mut self, - scope_id: ast::node_id, - lp: @loan_path, - f: &fn(v: &Loan) -> bool) { - for self.walk_loans(scope_id) |loan| { - if loan.lp == lp { - if !f(loan) { return; } - } - } - } + fn each_in_scope_loan(&self, + scope_id: ast::node_id, + op: &fn(&Loan) -> bool) + { + //! Like `each_issued_loan()`, but only considers loans that are + //! currently in scope. - // when we are in a pure context, we check each call to ensure - // that the function which is invoked is itself pure. - // - // note: we take opt_expr and expr_id separately because for - // overloaded operators the callee has an id but no expr. - // annoying. - fn check_pure_callee_or_arg(&mut self, - pc: Either, - opt_expr: Option<@ast::expr>, - callee_id: ast::node_id, - callee_span: span) { - let tcx = self.tcx(); - - debug!("check_pure_callee_or_arg(pc=%?, expr=%?, \ - callee_id=%d, ty=%s)", - pc, - opt_expr.map(|e| pprust::expr_to_str(*e, tcx.sess.intr()) ), - callee_id, - ty_to_str(self.tcx(), ty::node_id_to_type(tcx, callee_id))); - - // Purity rules: an expr B is a legal callee or argument to a - // call within a pure function A if at least one of the - // following holds: - // - // (a) A was declared pure and B is one of its arguments; - // (b) B is a stack closure; - // (c) B is a pure fn; - // (d) B is not a fn. - - match opt_expr { - Some(expr) => { - match expr.node { - ast::expr_path(_) if pc == Left(pc_pure_fn) => { - let def = *self.tcx().def_map.get(&expr.id); - let did = ast_util::def_id_of_def(def); - let is_fn_arg = - did.crate == ast::local_crate && - (*self.fn_args).contains(&(did.node)); - if is_fn_arg { return; } // case (a) above - } - ast::expr_fn_block(*) | ast::expr_loop_body(*) | - ast::expr_do_body(*) => { - if self.is_stack_closure(expr.id) { - // case (b) above + let region_maps = self.tcx().region_maps; + for self.each_issued_loan(scope_id) |loan| { + if region_maps.is_subscope_of(scope_id, loan.kill_scope) { + if !op(loan) { return; } - } - _ => () } - } - None => () } + } - let callee_ty = ty::node_id_to_type(tcx, callee_id); - match ty::get(callee_ty).sty { - ty::ty_bare_fn(ty::BareFnTy {purity: purity, _}) | - ty::ty_closure(ty::ClosureTy {purity: purity, _}) => { - match purity { - ast::pure_fn => return, // case (c) above - ast::impure_fn | ast::unsafe_fn | ast::extern_fn => { - self.report_purity_error( - pc, callee_span, - fmt!("access to %s function", - purity.to_str())); + fn each_in_scope_restriction(&self, + scope_id: ast::node_id, + loan_path: @LoanPath, + op: &fn(&Loan, &Restriction) -> bool) + { + //! Iterates through all the in-scope restrictions for the + //! given `loan_path` + + for self.each_in_scope_loan(scope_id) |loan| { + for loan.restrictions.each |restr| { + if restr.loan_path == loan_path { + if !op(loan, restr) { + return; } } } - _ => return, // case (d) above } } - // True if the expression with the given `id` is a stack closure. - // The expression must be an expr_fn_block(*) - fn is_stack_closure(&mut self, id: ast::node_id) -> bool { - let fn_ty = ty::node_id_to_type(self.tcx(), id); - match ty::get(fn_ty).sty { - ty::ty_closure(ty::ClosureTy {sigil: ast::BorrowedSigil, - _}) => true, - _ => false - } - } + fn loans_generated_by(&self, scope_id: ast::node_id) -> ~[uint] { + //! Returns a vector of the loans that are generated as + //! we encounter `scope_id`. - fn is_allowed_pure_arg(&mut self, expr: @ast::expr) -> bool { - return match expr.node { - ast::expr_path(_) => { - let def = *self.tcx().def_map.get(&expr.id); - let did = ast_util::def_id_of_def(def); - did.crate == ast::local_crate && - (*self.fn_args).contains(&(did.node)) - } - ast::expr_fn_block(*) => self.is_stack_closure(expr.id), - _ => false, - }; + let mut result = ~[]; + for self.dfcx.each_gen_bit(scope_id) |loan_index| { + result.push(loan_index); + } + return result; } fn check_for_conflicting_loans(&mut self, scope_id: ast::node_id) { - debug!("check_for_conflicting_loans(scope_id=%?)", scope_id); + //! Checks to see whether any of the loans that are issued + //! by `scope_id` conflict with loans that have already been + //! issued when we enter `scope_id` (for example, we do not + //! permit two `&mut` borrows of the same variable). - let new_loans = match self.req_maps.req_loan_map.find(&scope_id) { - None => return, - Some(&loans) => loans - }; - let new_loans: &mut ~[Loan] = new_loans; - - debug!("new_loans has length %?", new_loans.len()); + debug!("check_for_conflicting_loans(scope_id=%?)", scope_id); - let par_scope_id = self.tcx().region_maps.encl_scope(scope_id); - for self.walk_loans(par_scope_id) |old_loan| { - debug!("old_loan=%?", self.bccx.loan_to_repr(old_loan)); + let new_loan_indices = self.loans_generated_by(scope_id); + debug!("new_loan_indices = %?", new_loan_indices); - for new_loans.each |new_loan| { - self.report_error_if_loans_conflict(old_loan, new_loan); + for self.each_issued_loan(scope_id) |issued_loan| { + for new_loan_indices.each |&new_loan_index| { + let new_loan = &self.all_loans[new_loan_index]; + self.report_error_if_loans_conflict(issued_loan, new_loan); } } - let len = new_loans.len(); - for uint::range(0, len) |i| { - let loan_i = new_loans[i]; - for uint::range(i+1, len) |j| { - let loan_j = new_loans[j]; - self.report_error_if_loans_conflict(&loan_i, &loan_j); + for uint::range(0, new_loan_indices.len()) |i| { + let old_loan = &self.all_loans[new_loan_indices[i]]; + for uint::range(i+1, new_loan_indices.len()) |j| { + let new_loan = &self.all_loans[new_loan_indices[j]]; + self.report_error_if_loans_conflict(old_loan, new_loan); } } } @@ -303,219 +162,358 @@ pub impl CheckLoanCtxt { fn report_error_if_loans_conflict(&self, old_loan: &Loan, new_loan: &Loan) { - if old_loan.lp != new_loan.lp { - return; - } + //! Checks whether `old_loan` and `new_loan` can safely be issued + //! simultaneously. + + debug!("report_error_if_loans_conflict(old_loan=%s, new_loan=%s)", + old_loan.repr(self.tcx()), + new_loan.repr(self.tcx())); + + // Should only be called for loans that are in scope at the same time. + let region_maps = self.tcx().region_maps; + assert!(region_maps.scopes_intersect(old_loan.kill_scope, + new_loan.kill_scope)); + + self.report_error_if_loan_conflicts_with_restriction( + old_loan, new_loan, old_loan, new_loan) && + self.report_error_if_loan_conflicts_with_restriction( + new_loan, old_loan, old_loan, new_loan); + } - match (old_loan.kind, new_loan.kind) { - (PartialFreeze, PartialTake) | (PartialTake, PartialFreeze) | - (TotalFreeze, PartialFreeze) | (PartialFreeze, TotalFreeze) | - (Immobile, _) | (_, Immobile) | - (PartialFreeze, PartialFreeze) | - (PartialTake, PartialTake) | - (TotalFreeze, TotalFreeze) => { - /* ok */ - } + fn report_error_if_loan_conflicts_with_restriction(&self, + loan1: &Loan, + loan2: &Loan, + old_loan: &Loan, + new_loan: &Loan) -> bool { + //! Checks whether the restrictions introduced by `loan1` would + //! prohibit `loan2`. Returns false if an error is reported. + + debug!("report_error_if_loan_conflicts_with_restriction(\ + loan1=%s, loan2=%s)", + loan1.repr(self.tcx()), + loan2.repr(self.tcx())); + + // Restrictions that would cause the new loan to be immutable: + let illegal_if = match loan2.mutbl { + m_mutbl => RESTR_ALIAS | RESTR_FREEZE | RESTR_MUTATE, + m_imm => RESTR_ALIAS | RESTR_FREEZE, + m_const => RESTR_ALIAS, + }; + debug!("illegal_if=%?", illegal_if); + + for loan1.restrictions.each |restr| { + if !restr.set.intersects(illegal_if) { loop; } + if restr.loan_path != loan2.loan_path { loop; } - (PartialTake, TotalFreeze) | (TotalFreeze, PartialTake) | - (TotalTake, TotalFreeze) | (TotalFreeze, TotalTake) | - (TotalTake, PartialFreeze) | (PartialFreeze, TotalTake) | - (TotalTake, PartialTake) | (PartialTake, TotalTake) | - (TotalTake, TotalTake) => { - self.bccx.span_err( - new_loan.cmt.span, - fmt!("loan of %s as %s \ - conflicts with prior loan", - self.bccx.cmt_to_str(new_loan.cmt), - self.bccx.loan_kind_to_str(new_loan.kind))); - self.bccx.span_note( - old_loan.cmt.span, - fmt!("prior loan as %s granted here", - self.bccx.loan_kind_to_str(old_loan.kind))); + match (new_loan.mutbl, old_loan.mutbl) { + (m_mutbl, m_mutbl) => { + self.bccx.span_err( + new_loan.span, + fmt!("cannot borrow `%s` as mutable \ + more than once at at a time", + self.bccx.loan_path_to_str(new_loan.loan_path))); + self.bccx.span_note( + old_loan.span, + fmt!("second borrow of `%s` as mutable occurs here", + self.bccx.loan_path_to_str(new_loan.loan_path))); + return false; + } + + _ => { + self.bccx.span_err( + new_loan.span, + fmt!("cannot borrow `%s` as %s because \ + it is also borrowed as %s" + self.bccx.loan_path_to_str(new_loan.loan_path), + self.bccx.mut_to_str(new_loan.mutbl), + self.bccx.mut_to_str(old_loan.mutbl))); + self.bccx.span_note( + old_loan.span, + fmt!("second borrow of `%s` occurs here", + self.bccx.loan_path_to_str(new_loan.loan_path))); + return false; + } } } + + true } - fn is_local_variable(&self, cmt: cmt) -> bool { + fn is_local_variable(&self, cmt: mc::cmt) -> bool { match cmt.cat { - cat_local(_) => true, + mc::cat_local(_) => true, _ => false } } - fn check_assignment(&mut self, at: assignment_type, ex: @ast::expr) { + fn check_assignment(&self, expr: @ast::expr) { // We don't use cat_expr() here because we don't want to treat // auto-ref'd parameters in overloaded operators as rvalues. - let cmt = match self.bccx.tcx.adjustments.find(&ex.id) { - None => self.bccx.cat_expr_unadjusted(ex), - Some(&adj) => self.bccx.cat_expr_autoderefd(ex, adj) + let cmt = match self.bccx.tcx.adjustments.find(&expr.id) { + None => self.bccx.cat_expr_unadjusted(expr), + Some(&adj) => self.bccx.cat_expr_autoderefd(expr, adj) }; - debug!("check_assignment(cmt=%s)", - self.bccx.cmt_to_repr(cmt)); - - if self.is_local_variable(cmt) && at.checked_by_liveness() { - // liveness guarantees that immutable local variables - // are only assigned once - } else { - match cmt.mutbl { - McDeclared | McInherited => { - // Ok, but if this loan is a mutable loan, then mark the - // loan path (if it exists) as being used. This is similar - // to the check performed in loan.rs in issue_loan(). This - // type of use of mutable is different from issuing a loan, - // however. - for cmt.lp.each |lp| { - for lp.node_id().each |&id| { - self.tcx().used_mut_nodes.insert(id); - } - } - } - McReadOnly | McImmutable => { + debug!("check_assignment(cmt=%s)", cmt.repr(self.tcx())); + + // check that the value being assigned is declared as mutable + // and report an error otherwise. + match cmt.mutbl { + mc::McDeclared => { + // OK + } + mc::McInherited => { + // OK, but we may have to add an entry to `used_mut_nodes` + mark_writes_through_upvars_as_used_mut(self, cmt); + } + mc::McReadOnly | mc::McImmutable => { + // Subtle: liveness guarantees that immutable local + // variables are only assigned once, so no need to + // report an error for an assignment to a local + // variable (note also that it is not legal to borrow + // for a local variable before it has been assigned + // for the first time). + if !self.is_local_variable(cmt) { self.bccx.span_err( - ex.span, - at.ing_form(self.bccx.cmt_to_str(cmt))); - return; + expr.span, + fmt!("cannot assign to %s %s" + cmt.mutbl.to_user_str(), + self.bccx.cmt_to_str(cmt))); } + return; } } - // if this is a pure function, only loan-able state can be - // assigned, because it is uniquely tied to this function and - // is not visible from the outside - let purity = self.purity(ex.id); - match purity { - Right(_) => (), - Left(pc_cmt(_)) => { - // Subtle: Issue #3162. If we are enforcing purity - // because there is a reference to aliasable, mutable data - // that we require to be immutable, we can't allow writes - // even to data owned by the current stack frame. This is - // because that aliasable data might have been located on - // the current stack frame, we don't know. - self.report_purity_error( - purity, - ex.span, - at.ing_form(self.bccx.cmt_to_str(cmt))); - } - Left(pc_pure_fn) => { - if cmt.lp.is_none() { - self.report_purity_error( - purity, ex.span, - at.ing_form(self.bccx.cmt_to_str(cmt))); - } - } + if check_for_aliasable_mutable_writes(self, expr, cmt) { + check_for_assignment_to_restricted_or_frozen_location( + self, expr, cmt); } - // check for a conflicting loan as well, except in the case of - // taking a mutable ref. that will create a loan of its own - // which will be checked for compat separately in - // check_for_conflicting_loans() - for cmt.lp.each |lp| { - self.check_for_loan_conflicting_with_assignment( - at, ex, cmt, *lp); - } + fn mark_writes_through_upvars_as_used_mut(self: &CheckLoanCtxt, + cmt: mc::cmt) { + //! If the mutability of the `cmt` being written is inherited + //! from a local variable in another closure, liveness may + //! not have been able to detect that this variable's mutability + //! is important, so we must add the variable to the + //! `used_mut_nodes` table here. This is because liveness + //! does not consider closures. + + let mut passed_upvar = false; + let mut cmt = cmt; + loop { + debug!("mark_writes_through_upvars_as_used_mut(cmt=%s)", + cmt.repr(self.tcx())); + match cmt.cat { + mc::cat_local(id) | + mc::cat_arg(id, _) | + mc::cat_self(id) => { + if passed_upvar { + self.tcx().used_mut_nodes.insert(id); + } + return; + } - self.bccx.add_to_mutbl_map(cmt); + mc::cat_stack_upvar(b) => { + cmt = b; + passed_upvar = true; + } - // Check for and insert write guards as necessary. - self.add_write_guards_if_necessary(cmt); - } + mc::cat_rvalue | + mc::cat_static_item | + mc::cat_implicit_self | + mc::cat_copied_upvar(*) | + mc::cat_deref(_, _, mc::unsafe_ptr(*)) | + mc::cat_deref(_, _, mc::gc_ptr(*)) | + mc::cat_deref(_, _, mc::region_ptr(*)) => { + assert_eq!(cmt.mutbl, mc::McDeclared); + return; + } - fn add_write_guards_if_necessary(&mut self, cmt: cmt) { - match cmt.cat { - cat_deref(base, deref_count, ptr_kind) => { - self.add_write_guards_if_necessary(base); - - match ptr_kind { - gc_ptr(ast::m_mutbl) => { - let key = root_map_key { - id: base.id, - derefs: deref_count - }; - self.bccx.write_guard_map.insert(key); + mc::cat_discr(b, _) | + mc::cat_deref(b, _, mc::uniq_ptr(*)) => { + assert_eq!(cmt.mutbl, mc::McInherited); + cmt = b; + } + + mc::cat_interior(b, _) => { + if cmt.mutbl == mc::McInherited { + cmt = b; + } else { + return; // field declared as mutable or some such + } } - _ => {} } } - cat_comp(base, _) => { - self.add_write_guards_if_necessary(base); - } - _ => {} } - } - fn check_for_loan_conflicting_with_assignment(&mut self, - at: assignment_type, - ex: @ast::expr, - cmt: cmt, - lp: @loan_path) { - for self.walk_loans_of(ex.id, lp) |loan| { - match loan.kind { - Immobile => { /* ok */ } - TotalFreeze | PartialFreeze | - TotalTake | PartialTake => { - self.bccx.span_err( - ex.span, - fmt!("%s prohibited due to outstanding loan", - at.ing_form(self.bccx.cmt_to_str(cmt)))); - self.bccx.span_note( - loan.cmt.span, - fmt!("loan of %s granted here", - self.bccx.cmt_to_str(loan.cmt))); - return; + fn check_for_aliasable_mutable_writes(self: &CheckLoanCtxt, + expr: @ast::expr, + cmt: mc::cmt) -> bool { + //! Safety checks related to writes to aliasable, mutable locations + + let guarantor = cmt.guarantor(); + match guarantor.cat { + mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) => { + // Statically prohibit writes to `&mut` when aliasable + + match b.freely_aliasable() { + None => {} + Some(cause) => { + self.bccx.report_aliasability_violation( + expr.span, + MutabilityViolation, + cause); + } + } } + + mc::cat_deref(base, deref_count, mc::gc_ptr(ast::m_mutbl)) => { + // Dynamically check writes to `@mut` + + let key = root_map_key { + id: base.id, + derefs: deref_count + }; + self.bccx.write_guard_map.insert(key); + } + + _ => {} } - } - // Subtle: if the mutability of the component being assigned - // is inherited from the thing that the component is embedded - // within, then we have to check whether that thing has been - // loaned out as immutable! An example: - // let mut x = {f: Some(3)}; - // let y = &x; // x loaned out as immutable - // x.f = none; // changes type of y.f, which appears to be imm - match *lp { - lp_comp(lp_base, ck) if inherent_mutability(ck) != m_mutbl => { - self.check_for_loan_conflicting_with_assignment( - at, ex, cmt, lp_base); - } - lp_comp(*) | lp_self | lp_local(*) | lp_arg(*) | lp_deref(*) => () + return true; // no errors reported } - } - fn report_purity_error(&mut self, pc: Either, - sp: span, msg: ~str) { - match pc { - Right(pc_default) => { fail!(~"pc_default should be filtered sooner") } - Right(pc_unsafe) => { - // this error was prevented by being marked as unsafe, so flag the - // definition as having contributed to the validity of the program - let def = self.declared_purity.def; - debug!("flagging %? as a used unsafe source", def); - self.tcx().used_unsafe.insert(def); - } - Left(pc_pure_fn) => { - self.tcx().sess.span_err( - sp, - fmt!("%s prohibited in pure context", msg)); - } - Left(pc_cmt(ref e)) => { - if self.reported.insert((*e).cmt.id) { - self.tcx().sess.span_err( - (*e).cmt.span, - fmt!("illegal borrow unless pure: %s", - self.bccx.bckerr_to_str((*e)))); - self.bccx.note_and_explain_bckerr((*e)); - self.tcx().sess.span_note( - sp, - fmt!("impure due to %s", msg)); + fn check_for_assignment_to_restricted_or_frozen_location( + self: &CheckLoanCtxt, + expr: @ast::expr, + cmt: mc::cmt) -> bool + { + //! Check for assignments that violate the terms of an + //! outstanding loan. + + let loan_path = match opt_loan_path(cmt) { + Some(lp) => lp, + None => { return true; /* no loan path, can't be any loans */ } + }; + + // Start by searching for an assignment to a *restricted* + // location. Here is one example of the kind of error caught + // by this check: + // + // let mut v = ~[1, 2, 3]; + // let p = &v; + // v = ~[4]; + // + // In this case, creating `p` triggers a RESTR_MUTATE + // restriction on the path `v`. + // + // Here is a second, more subtle example: + // + // let mut v = ~[1, 2, 3]; + // let p = &const v[0]; + // v[0] = 4; // OK + // v[1] = 5; // OK + // v = ~[4, 5, 3]; // Error + // + // In this case, `p` is pointing to `v[0]`, and it is a + // `const` pointer in any case. So the first two + // assignments are legal (and would be permitted by this + // check). However, the final assignment (which is + // logically equivalent) is forbidden, because it would + // cause the existing `v` array to be freed, thus + // invalidating `p`. In the code, this error results + // because `gather_loans::restrictions` adds a + // `RESTR_MUTATE` restriction whenever the contents of an + // owned pointer are borrowed, and hence while `v[*]` is not + // restricted from being written, `v` is. + for self.each_in_scope_restriction(expr.id, loan_path) + |loan, restr| + { + if restr.set.intersects(RESTR_MUTATE) { + self.report_illegal_mutation(expr, loan_path, loan); + return false; + } + } + + // The previous code handled assignments to paths that + // have been restricted. This covers paths that have been + // directly lent out and their base paths, but does not + // cover random extensions of those paths. For example, + // the following program is not declared illegal by the + // previous check: + // + // let mut v = ~[1, 2, 3]; + // let p = &v; + // v[0] = 4; // declared error by loop below, not code above + // + // The reason that this passes the previous check whereas + // an assignment like `v = ~[4]` fails is because the assignment + // here is to `v[*]`, and the existing restrictions were issued + // for `v`, not `v[*]`. + // + // So in this loop, we walk back up the loan path so long + // as the mutability of the path is dependent on a super + // path, and check that the super path was not lent out as + // mutable or immutable (a const loan is ok). + // + // Note that we are *not* checking for any and all + // restrictions. We are only interested in the pointers + // that the user created, whereas we add restrictions for + // all kinds of paths that are not directly aliased. If we checked + // for all restrictions, and not just loans, then the following + // valid program would be considered illegal: + // + // let mut v = ~[1, 2, 3]; + // let p = &const v[0]; + // v[1] = 5; // ok + // + // Here the restriction that `v` not be mutated would be misapplied + // to block the subpath `v[1]`. + let full_loan_path = loan_path; + let mut loan_path = loan_path; + loop { + match *loan_path { + // Peel back one layer if `loan_path` has + // inherited mutability + LpExtend(lp_base, mc::McInherited, _) => { + loan_path = lp_base; + } + + // Otherwise stop iterating + LpExtend(_, mc::McDeclared, _) | + LpExtend(_, mc::McImmutable, _) | + LpExtend(_, mc::McReadOnly, _) | + LpVar(_) => { + return true; + } + } + + // Check for a non-const loan of `loan_path` + for self.each_in_scope_loan(expr.id) |loan| { + if loan.loan_path == loan_path && loan.mutbl != m_const { + self.report_illegal_mutation(expr, full_loan_path, loan); + return false; + } + } } - } } } - fn check_move_out_from_expr(@mut self, ex: @ast::expr) { + fn report_illegal_mutation(&self, + expr: @ast::expr, + loan_path: &LoanPath, + loan: &Loan) { + self.bccx.span_err( + expr.span, + fmt!("cannot assign to `%s` because it is borrowed", + self.bccx.loan_path_to_str(loan_path))); + self.bccx.span_note( + loan.span, + fmt!("borrow of `%s` occurs here", + self.bccx.loan_path_to_str(loan_path))); + } + + fn check_move_out_from_expr(&self, ex: @ast::expr) { match ex.node { ast::expr_paren(*) => { /* In the case of an expr_paren(), the expression inside @@ -529,52 +527,57 @@ pub impl CheckLoanCtxt { MoveFromIllegalCmt(_) => { self.bccx.span_err( cmt.span, - fmt!("moving out of %s", + fmt!("cannot move out of %s", self.bccx.cmt_to_str(cmt))); } - MoveWhileBorrowed(_, loan_cmt) => { + MoveWhileBorrowed(loan_path, loan_span) => { self.bccx.span_err( cmt.span, - fmt!("moving out of %s prohibited \ - due to outstanding loan", - self.bccx.cmt_to_str(cmt))); + fmt!("cannot move out of `%s` \ + because it is borrowed", + self.bccx.loan_path_to_str(loan_path))); self.bccx.span_note( - loan_cmt.span, - fmt!("loan of %s granted here", - self.bccx.cmt_to_str(loan_cmt))); + loan_span, + fmt!("borrow of `%s` occurs here", + self.bccx.loan_path_to_str(loan_path))); } } } } } - fn analyze_move_out_from_cmt(&mut self, cmt: cmt) -> MoveError { - debug!("check_move_out_from_cmt(cmt=%s)", - self.bccx.cmt_to_repr(cmt)); + fn analyze_move_out_from_cmt(&self, cmt: mc::cmt) -> MoveError { + debug!("check_move_out_from_cmt(cmt=%s)", cmt.repr(self.tcx())); match cmt.cat { - // Rvalues, locals, and arguments can be moved: - cat_rvalue | cat_local(_) | cat_arg(_) | cat_self(_) => {} - - // We allow moving out of static items because the old code - // did. This seems consistent with permitting moves out of - // rvalues, I guess. - cat_special(sk_static_item) => {} - - cat_deref(_, _, unsafe_ptr) => {} - - // Nothing else. - _ => { - return MoveFromIllegalCmt(cmt); - } + // Rvalues, locals, and arguments can be moved: + mc::cat_rvalue | mc::cat_local(_) | + mc::cat_arg(_, ast::by_copy) | mc::cat_self(_) => {} + + // It seems strange to allow a move out of a static item, + // but what happens in practice is that you have a + // reference to a constant with a type that should be + // moved, like `None::<~int>`. The type of this constant + // is technically `Option<~int>`, which moves, but we know + // that the content of static items will never actually + // contain allocated pointers, so we can just memcpy it. + mc::cat_static_item => {} + + mc::cat_deref(_, _, mc::unsafe_ptr(*)) => {} + + // Nothing else. + _ => { + return MoveFromIllegalCmt(cmt); + } } - self.bccx.add_to_mutbl_map(cmt); + // NOTE inadequare if/when we permit `move a.b` // check for a conflicting loan: - for cmt.lp.each |lp| { - for self.walk_loans_of(cmt.id, *lp) |loan| { - return MoveWhileBorrowed(cmt, loan.cmt); + for opt_loan_path(cmt).each |&lp| { + for self.each_in_scope_restriction(cmt.id, lp) |loan, _| { + // Any restriction prevents moves. + return MoveWhileBorrowed(loan.loan_path, loan.span); } } @@ -582,105 +585,46 @@ pub impl CheckLoanCtxt { } fn check_call(&mut self, - expr: @ast::expr, - callee: Option<@ast::expr>, - callee_id: ast::node_id, - callee_span: span, - args: &[@ast::expr]) { - let pc = self.purity(expr.id); - match pc { - // no purity, no need to check for anything - Right(pc_default) => return, - - // some form of purity, definitely need to check - Left(_) => (), - - // Unsafe trumped. To see if the unsafe is necessary, see what the - // purity would have been without a trump, and if it's some form - // of purity then we need to go ahead with the check - Right(pc_unsafe) => { - match do with(&mut self.declared_purity.purity, - ast::impure_fn) { self.purity(expr.id) } { - Right(pc_unsafe) => fail!(~"unsafe can't trump twice"), - Right(pc_default) => return, - Left(_) => () - } - } - - } - self.check_pure_callee_or_arg( - pc, callee, callee_id, callee_span); - for args.each |arg| { - self.check_pure_callee_or_arg( - pc, Some(*arg), arg.id, arg.span); - } + _expr: @ast::expr, + _callee: Option<@ast::expr>, + _callee_id: ast::node_id, + _callee_span: span, + _args: &[@ast::expr]) + { + // NB: This call to check for conflicting loans is not truly + // necessary, because the callee_id never issues new loans. + // However, I added it for consistency and lest the system + // should change in the future. + // + // FIXME(#5074) nested method calls + // self.check_for_conflicting_loans(callee_id); } } -fn check_loans_in_fn(fk: &visit::fn_kind, - decl: &ast::fn_decl, - body: &ast::blk, - sp: span, - id: ast::node_id, - self: @mut CheckLoanCtxt, - visitor: visit::vt<@mut CheckLoanCtxt>) { - let is_stack_closure = self.is_stack_closure(id); - let fty = ty::node_id_to_type(self.tcx(), id); - - let declared_purity, src; +fn check_loans_in_fn<'a>(fk: &visit::fn_kind, + decl: &ast::fn_decl, + body: &ast::blk, + sp: span, + id: ast::node_id, + self: @mut CheckLoanCtxt<'a>, + visitor: visit::vt<@mut CheckLoanCtxt<'a>>) { match *fk { - visit::fk_item_fn(*) | visit::fk_method(*) | + visit::fk_item_fn(*) | + visit::fk_method(*) | visit::fk_dtor(*) => { - declared_purity = ty::ty_fn_purity(fty); - src = id; + // Don't process nested items. + return; } - visit::fk_anon(*) | visit::fk_fn_block(*) => { + visit::fk_anon(*) | + visit::fk_fn_block(*) => { + let fty = ty::node_id_to_type(self.tcx(), id); let fty_sigil = ty::ty_closure_sigil(fty); check_moves_from_captured_variables(self, id, fty_sigil); - let pair = ty::determine_inherited_purity( - (self.declared_purity.purity, self.declared_purity.def), - (ty::ty_fn_purity(fty), id), - fty_sigil); - declared_purity = pair.first(); - src = pair.second(); } } - debug!("purity on entry=%?", copy self.declared_purity); - do save_and_restore_managed(self.declared_purity) { - do save_and_restore_managed(self.fn_args) { - self.declared_purity = @mut PurityState::function(declared_purity, src); - - match *fk { - visit::fk_anon(*) | - visit::fk_fn_block(*) if is_stack_closure => { - // inherits the fn_args from enclosing ctxt - } - visit::fk_anon(*) | visit::fk_fn_block(*) | - visit::fk_method(*) | visit::fk_item_fn(*) | - visit::fk_dtor(*) => { - let mut fn_args = ~[]; - for decl.inputs.each |input| { - // For the purposes of purity, only consider function- - // typed bindings in trivial patterns to be function - // arguments. For example, do not allow `f` and `g` in - // (f, g): (&fn(), &fn()) to be called. - match input.pat.node { - ast::pat_ident(_, _, None) => { - fn_args.push(input.pat.id); - } - _ => {} // Ignore this argument. - } - } - *self.fn_args = @fn_args; - } - } - - visit::visit_fn(fk, decl, body, sp, id, self, visitor); - } - } - debug!("purity on exit=%?", copy self.declared_purity); + visit::visit_fn(fk, decl, body, sp, id, self, visitor); fn check_moves_from_captured_variables(self: @mut CheckLoanCtxt, id: ast::node_id, @@ -706,16 +650,16 @@ fn check_loans_in_fn(fk: &visit::fn_kind, fmt!("illegal by-move capture of %s", self.bccx.cmt_to_str(move_cmt))); } - MoveWhileBorrowed(move_cmt, loan_cmt) => { + MoveWhileBorrowed(loan_path, loan_span) => { self.bccx.span_err( cap_var.span, - fmt!("by-move capture of %s prohibited \ - due to outstanding loan", - self.bccx.cmt_to_str(move_cmt))); + fmt!("cannot move `%s` into closure \ + because it is borrowed", + self.bccx.loan_path_to_str(loan_path))); self.bccx.span_note( - loan_cmt.span, - fmt!("loan of %s granted here", - self.bccx.cmt_to_str(loan_cmt))); + loan_span, + fmt!("borrow of `%s` occurs here", + self.bccx.loan_path_to_str(loan_path))); } } } @@ -726,17 +670,19 @@ fn check_loans_in_fn(fk: &visit::fn_kind, } } -fn check_loans_in_local(local: @ast::local, - self: @mut CheckLoanCtxt, - vt: visit::vt<@mut CheckLoanCtxt>) { +fn check_loans_in_local<'a>(local: @ast::local, + self: @mut CheckLoanCtxt<'a>, + vt: visit::vt<@mut CheckLoanCtxt<'a>>) { visit::visit_local(local, self, vt); } -fn check_loans_in_expr(expr: @ast::expr, - self: @mut CheckLoanCtxt, - vt: visit::vt<@mut CheckLoanCtxt>) { - debug!("check_loans_in_expr(expr=%?/%s)", - expr.id, pprust::expr_to_str(expr, self.tcx().sess.intr())); +fn check_loans_in_expr<'a>(expr: @ast::expr, + self: @mut CheckLoanCtxt<'a>, + vt: visit::vt<@mut CheckLoanCtxt<'a>>) { + debug!("check_loans_in_expr(expr=%s)", + expr.repr(self.tcx())); + + visit::visit_expr(expr, self, vt); self.check_for_conflicting_loans(expr.id); @@ -746,12 +692,12 @@ fn check_loans_in_expr(expr: @ast::expr, match expr.node { ast::expr_swap(l, r) => { - self.check_assignment(at_swap, l); - self.check_assignment(at_swap, r); + self.check_assignment(l); + self.check_assignment(r); } ast::expr_assign(dest, _) | ast::expr_assign_op(_, dest, _) => { - self.check_assignment(at_straight_up, dest); + self.check_assignment(dest); } ast::expr_call(f, ref args, _) => { self.check_call(expr, Some(f), f.id, f.span, *args); @@ -776,32 +722,35 @@ fn check_loans_in_expr(expr: @ast::expr, expr.span, ~[]); } - ast::expr_match(*) => { - // Note: moves out of pattern bindings are not checked by - // the borrow checker, at least not directly. What happens - // is that if there are any moved bindings, the discriminant - // will be considered a move, and this will be checked as - // normal. Then, in `middle::check_match`, we will check - // that no move occurs in a binding that is underneath an - // `@` or `&`. Together these give the same guarantees as - // `check_move_out_from_expr()` without requiring us to - // rewalk the patterns and rebuild the pattern - // categorizations. - } _ => { } } - - visit::visit_expr(expr, self, vt); } -fn check_loans_in_block(blk: &ast::blk, - self: @mut CheckLoanCtxt, - vt: visit::vt<@mut CheckLoanCtxt>) { - do save_and_restore_managed(self.declared_purity) { - self.check_for_conflicting_loans(blk.node.id); +fn check_loans_in_pat<'a>(pat: @ast::pat, + self: @mut CheckLoanCtxt<'a>, + vt: visit::vt<@mut CheckLoanCtxt<'a>>) +{ + self.check_for_conflicting_loans(pat.id); + + // Note: moves out of pattern bindings are not checked by + // the borrow checker, at least not directly. What happens + // is that if there are any moved bindings, the discriminant + // will be considered a move, and this will be checked as + // normal. Then, in `middle::check_match`, we will check + // that no move occurs in a binding that is underneath an + // `@` or `&`. Together these give the same guarantees as + // `check_move_out_from_expr()` without requiring us to + // rewalk the patterns and rebuild the pattern + // categorizations. + + visit::visit_pat(pat, self, vt); +} - *self.declared_purity = self.declared_purity.recurse(blk); - visit::visit_block(blk, self, vt); - } +fn check_loans_in_block<'a>(blk: &ast::blk, + self: @mut CheckLoanCtxt<'a>, + vt: visit::vt<@mut CheckLoanCtxt<'a>>) +{ + visit::visit_block(blk, self, vt); + self.check_for_conflicting_loans(blk.node.id); } diff --git a/src/librustc/middle/borrowck/doc.rs b/src/librustc/middle/borrowck/doc.rs new file mode 100644 index 0000000000000..1e09fbe71843c --- /dev/null +++ b/src/librustc/middle/borrowck/doc.rs @@ -0,0 +1,750 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + +# The Borrow Checker + +This pass has the job of enforcing memory safety. This is a subtle +topic. The only way I know how to explain it is terms of a formal +model, so that's what I'll do. + +# Formal model + +Let's consider a simple subset of Rust in which you can only borrow +from lvalues like so: + + LV = x | LV.f | *LV + +Here `x` represents some variable, `LV.f` is a field reference, +and `*LV` is a pointer dereference. There is no auto-deref or other +niceties. This means that if you have a type like: + + struct S { f: uint } + +and a variable `a: ~S`, then the rust expression `a.f` would correspond +to an `LV` of `(*a).f`. + +Here is the formal grammar for the types we'll consider: + + TY = () | S<'LT...> | ~TY | & 'LT MQ TY | @ MQ TY + MQ = mut | imm | const + +Most of these types should be pretty self explanatory. Here `S` is a +struct name and we assume structs are declared like so: + + SD = struct S<'LT...> { (f: TY)... } + +# An intuitive explanation + +## Issuing loans + +Now, imagine we had a program like this: + + struct Foo { f: uint, g: uint } + ... + 'a: { + let mut x: ~Foo = ...; + let y = &mut (*x).f; + x = ...; + } + +This is of course dangerous because mutating `x` will free the old +value and hence invalidate `y`. The borrow checker aims to prevent +this sort of thing. + +### Loans + +The way the borrow checker works is that it analyzes each borrow +expression (in our simple model, that's stuff like `&LV`, though in +real life there are a few other cases to consider). For each borrow +expression, it computes a vector of loans: + + LOAN = (LV, LT, PT, LK) + PT = Partial | Total + LK = MQ | RESERVE + +Each `LOAN` tuple indicates some sort of restriction on what can be +done to the lvalue `LV`; `LV` will always be a path owned by the +current stack frame. These restrictions are called "loans" because +they are always the result of a borrow expression. + +Every loan has a lifetime `LT` during which those restrictions are in +effect. The indicator `PT` distinguishes between *total* loans, in +which the LV itself was borrowed, and *partial* loans, which means +that some content ownwed by LV was borrowed. + +The final element in the loan tuple is the *loan kind* `LK`. There +are four kinds: mutable, immutable, const, and reserve: + +- A "mutable" loan means that LV may be written to through an alias, and + thus LV cannot be written to directly or immutably aliased (remember + that we preserve the invariant that any given value can only be + written to through one path at a time; hence if there is a mutable + alias to LV, then LV cannot be written directly until this alias is + out of scope). + +- An "immutable" loan means that LV must remain immutable. Hence it + cannot be written, but other immutable aliases are permitted. + +- A "const" loan means that an alias to LV exists. LV may still be + written or frozen. + +- A "reserve" loan is the strongest case. It prevents both mutation + and aliasing of any kind, including `&const` loans. Reserve loans + are a side-effect of borrowing an `&mut` loan. + +In addition to affecting mutability, a loan of any kind implies that +LV cannot be moved. + +### Example + +To give you a better feeling for what a loan is, let's look at three +loans that would be issued as a result of the borrow `&(*x).f` in the +example above: + + ((*x).f, Total, mut, 'a) + (*x, Partial, mut, 'a) + (x, Partial, mut, 'a) + +The first loan states that the expression `(*x).f` has been loaned +totally as mutable for the lifetime `'a`. This first loan would +prevent an assignment `(*x).f = ...` from occurring during the +lifetime `'a`. + +Now let's look at the second loan. You may have expected that each +borrow would result in only one loan. But this is not the case. +Instead, there will be loans for every path where mutation might +affect the validity of the borrowed pointer that is created (in some +cases, there can even be multiple loans per path, see the section on +"Borrowing in Calls" below for the gory details). The reason for this +is to prevent actions that would indirectly affect the borrowed path. +In this case, we wish to ensure that `(*x).f` is not mutated except +through the mutable alias `y`. Therefore, we must not only prevent an +assignment to `(*x).f` but also an assignment like `*x = Foo {...}`, +as this would also mutate the field `f`. To do so, we issue a +*partial* mutable loan for `*x` (the loan is partial because `*x` +itself was not borrowed). This partial loan will cause any attempt to +assign to `*x` to be flagged as an error. + +Because both partial and total loans prevent assignments, you may +wonder why we bother to distinguish between them. The reason for this +distinction has to do with preventing double borrows. In particular, +it is legal to borrow both `&mut x.f` and `&mut x.g` simultaneously, +but it is not legal to borrow `&mut x.f` twice. In the borrow checker, +the first case would result in two *partial* mutable loans of `x` +(along with one total mutable loan of `x.f` and one of `x.g) whereas +the second would result in two *total* mutable loans of `x.f` (along +with two partial mutable loans of `x`). Multiple *total mutable* loan +for the same path are not permitted, but multiple *partial* loans (of +any mutability) are permitted. + +Finally, we come to the third loan. This loan is a partial mutable +loan of `x`. This loan prevents us from reassigning `x`, which would +be bad for two reasons. First, it would change the value of `(*x).f` +but, even worse, it would cause the pointer `y` to become a dangling +pointer. Bad all around. + +## Checking for illegal assignments, moves, and reborrows + +Once we have computed the loans introduced by each borrow, the borrow +checker will determine the full set of loans in scope at each +expression and use that to decide whether that expression is legal. +Remember that the scope of loan is defined by its lifetime LT. We +sometimes say that a loan which is in-scope at a particular point is +an "outstanding loan". + +The kinds of expressions which in-scope loans can render illegal are +*assignments*, *moves*, and *borrows*. + +An assignments to an lvalue LV is illegal if there is in-scope mutable +or immutable loan for LV. Assignment with an outstanding mutable loan +is illegal because then the `&mut` pointer is supposed to be the only +way to mutate the value. Assignment with an outstanding immutable +loan is illegal because the value is supposed to be immutable at that +point. + +A move from an lvalue LV is illegal if there is any sort of +outstanding loan. + +A borrow expression may be illegal if any of the loans which it +produces conflict with other outstanding loans. Two loans are +considered compatible if one of the following conditions holds: + +- At least one loan is a const loan. +- Both loans are partial loans. +- Both loans are immutable. + +Any other combination of loans is illegal. + +# The set of loans that results from a borrow expression + +Here we'll define four functions---MUTATE, FREEZE, ALIAS, and +TAKE---which are all used to compute the set of LOANs that result +from a borrow expression. The first three functions each have +a similar type signature: + + MUTATE(LV, LT, PT) -> LOANS + FREEZE(LV, LT, PT) -> LOANS + ALIAS(LV, LT, PT) -> LOANS + +MUTATE, FREEZE, and ALIAS are used when computing the loans result +from mutable, immutable, and const loans respectively. For example, +the loans resulting from an expression like `&mut (*x).f` would be +computed by `MUTATE((*x).f, LT, Total)`, where `LT` is the lifetime of +the resulting pointer. Similarly the loans for `&(*x).f` and `&const +(*x).f` would be computed by `FREEZE((*x).f, LT, Total)` and +`ALIAS((*x).f, LT, Total)` respectively. (Actually this is a slight +simplification; see the section below on Borrows in Calls for the full +gory details) + +The names MUTATE, FREEZE, and ALIAS are intended to suggest the +semantics of `&mut`, `&`, and `&const` borrows respectively. `&mut`, +for example, creates a mutable alias of LV. `&` causes the borrowed +value to be frozen (immutable). `&const` does neither but does +introduce an alias to be the borrowed value. + +Each of these three functions is only defined for some inputs. That +is, it may occur that some particular borrow is not legal. For +example, it is illegal to make an `&mut` loan of immutable data. In +that case, the MUTATE() function is simply not defined (in the code, +it returns a Result<> condition to indicate when a loan would be +illegal). + +The final function, RESERVE, is used as part of borrowing an `&mut` +pointer. Due to the fact that it is used for one very particular +purpose, it has a rather simpler signature than the others: + + RESERVE(LV, LT) -> LOANS + +It is explained when we come to that case. + +## The function MUTATE() + +Here we use [inference rules][ir] to define the MUTATE() function. +We will go case by case for the various kinds of lvalues that +can be borrowed. + +[ir]: http://en.wikipedia.org/wiki/Rule_of_inference + +### Mutating local variables + +The rule for mutating local variables is as follows: + + Mutate-Variable: + LT <= Scope(x) + Mut(x) = Mut + -------------------------------------------------- + MUTATE(x, LT, PT) = (x, LT, PT, mut) + +Here `Scope(x)` is the lifetime of the block in which `x` was declared +and `Mut(x)` indicates the mutability with which `x` was declared. +This rule simply states that you can only create a mutable alias +to a variable if it is mutable, and that alias cannot outlive the +stack frame in which the variable is declared. + +### Mutating fields and owned pointers + +As it turns out, the rules for mutating fields and mutating owned +pointers turn out to be quite similar. The reason is that the +expressions `LV.f` and `*LV` are both owned by their base expression +`LV`. So basically the result of mutating `LV.f` or `*LV` is computed +by adding a loan for `LV.f` or `*LV` and then the loans for a partial +take of `LV`: + + Mutate-Field: + MUTATE(LV, LT, Partial) = LOANS + ------------------------------------------------------------ + MUTATE(LV.f, LT, PT) = LOANS, (LV.F, LT, PT, mut) + + Mutate-Owned-Ptr: + Type(LV) = ~Ty + MUTATE(LV, LT, Partial) = LOANS + ------------------------------------------------------------ + MUTATE(*LV, LT, PT) = LOANS, (*LV, LT, PT, mut) + +Note that while our micro-language only has fields, the slight +variations on the `Mutate-Field` rule are used for any interior content +that appears in the full Rust language, such as the contents of a +tuple, fields in a struct, or elements of a fixed-length vector. + +### Mutating dereferenced borrowed pointers + +The rule for borrowed pointers is by far the most complicated: + + Mutate-Mut-Borrowed-Ptr: + Type(LV) = <_P mut Ty // (1) + LT <= LT_P // (2) + RESERVE(LV, LT) = LOANS // (3) + ------------------------------------------------------------ + MUTATE(*LV, LT, PT) = LOANS, (*LV, LT, PT, Mut) + +Condition (1) states that only a mutable borrowed pointer can be +taken. Condition (2) states that the lifetime of the alias must be +less than the lifetime of the borrowed pointer being taken. + +Conditions (3) and (4) are where things get interesting. The intended +semantics of the borrow is that the new `&mut` pointer is the only one +which has the right to modify the data; the original `&mut` pointer +must not be used for mutation. Because borrowed pointers do not own +their content nor inherit mutability, we must be particularly cautious +of aliases, which could permit the original borrowed pointer to be +reached from another path and thus circumvent our loans. + +Here is one example of what could go wrong if we ignore clause (4): + + let x: &mut T; + ... + let y = &mut *x; // Only *y should be able to mutate... + let z = &const x; + **z = ...; // ...but here **z is still able to mutate! + +Another possible error could occur with moves: + + let x: &mut T; + ... + let y = &mut *x; // Issues loan: (*x, LT, Total, Mut) + let z = x; // moves from x + *z = ...; // Mutates *y indirectly! Bad. + +In both of these cases, the problem is that when creating the alias +`y` we would only issue a loan preventing assignment through `*x`. +But this loan can be easily circumvented by moving from `x` or +aliasing it. Note that, in the first example, the alias of `x` was +created using `&const`, which is a particularly weak form of alias. + +The danger of aliases can also occur when the `&mut` pointer itself +is already located in an alias location, as here: + + let x: @mut &mut T; // or &mut &mut T, &&mut T, + ... // &const &mut T, @&mut T, etc + let y = &mut **x; // Only *y should be able to mutate... + let z = x; + **z = ...; // ...but here **z is still able to mutate! + +When we cover the rules for RESERVE, we will see that it would +disallow this case, because MUTATE can only be applied to canonical +lvalues which are owned by the current stack frame. + +It might be the case that if `&const` and `@const` pointers were +removed, we could do away with RESERVE and simply use MUTATE instead. +But we have to be careful about the final example in particular, since +dynamic freezing would not be sufficient to prevent this example. +Perhaps a combination of MUTATE with a predicate OWNED(LV). + +One final detail: unlike every other case, when we calculate the loans +using RESERVE we do not use the original lifetime `LT` but rather +`GLB(Scope(LV), LT)`. What this says is: + +### Mutating dereferenced managed pointers + +Because the correctness of managed pointer loans is checked dynamically, +the rule is quite simple: + + Mutate-Mut-Managed-Ptr: + Type(LV) = @mut Ty + Add ROOT-FREEZE annotation for *LV with lifetime LT + ------------------------------------------------------------ + MUTATE(*LV, LT, Total) = [] + +No loans are issued. Instead, we add a side annotation that causes +`*LV` to be rooted and frozen on entry to LV. You could rephrase +these rules as having multiple returns values, or rephrase this as a +kind of loan, but whatever. + +One interesting point is that *partial takes* of `@mut` are forbidden. +This is not for any soundness reason but just because it is clearer +for users when `@mut` values are either lent completely or not at all. + +## The function FREEZE + +The rules for FREEZE are pretty similar to MUTATE. The first four +cases I'll just present without discussion, as the reasoning is +quite analogous to the MUTATE case: + + Freeze-Variable: + LT <= Scope(x) + -------------------------------------------------- + FREEZE(x, LT, PT) = (x, LT, PT, imm) + + Freeze-Field: + FREEZE(LV, LT, Partial) = LOANS + ------------------------------------------------------------ + FREEZE(LV.f, LT, PT) = LOANS, (LV.F, LT, PT, imm) + + Freeze-Owned-Ptr: + Type(LV) = ~Ty + FREEZE(LV, LT, Partial) = LOANS + ------------------------------------------------------------ + FREEZE(*LV, LT, PT) = LOANS, (*LV, LT, PT, imm) + + Freeze-Mut-Borrowed-Ptr: + Type(LV) = <_P mut Ty + LT <= LT_P + RESERVE(LV, LT) = LOANS + ------------------------------------------------------------ + FREEZE(*LV, LT, PT) = LOANS, (*LV, LT, PT, Imm) + + Freeze-Mut-Managed-Ptr: + Type(LV) = @mut Ty + Add ROOT-FREEZE annotation for *LV with lifetime LT + ------------------------------------------------------------ + Freeze(*LV, LT, Total) = [] + +The rule to "freeze" an immutable borrowed pointer is quite +simple, since the content is already immutable: + + Freeze-Imm-Borrowed-Ptr: + Type(LV) = <_P Ty // (1) + LT <= LT_P // (2) + ------------------------------------------------------------ + FREEZE(*LV, LT, PT) = LOANS, (*LV, LT, PT, Mut) + +The final two rules pertain to borrows of `@Ty`. There is a bit of +subtlety here. The main problem is that we must guarantee that the +managed box remains live for the entire borrow. We can either do this +dynamically, by rooting it, or (better) statically, and hence there +are two rules: + + Freeze-Imm-Managed-Ptr-1: + Type(LV) = @Ty + Add ROOT annotation for *LV + ------------------------------------------------------------ + FREEZE(*LV, LT, PT) = [] + + Freeze-Imm-Managed-Ptr-2: + Type(LV) = @Ty + LT <= Scope(LV) + Mut(LV) = imm + LV is not moved + ------------------------------------------------------------ + FREEZE(*LV, LT, PT) = [] + +The intention of the second rule is to avoid an extra root if LV +serves as a root. In that case, LV must (1) outlive the borrow; (2) +be immutable; and (3) not be moved. + +## The ALIAS function + +The function ALIAS is used for `&const` loans but also to handle one +corner case concerning function arguments (covered in the section +"Borrows in Calls" below). It computes the loans that result from +observing that there is a pointer to `LV` and thus that pointer must +remain valid. + +The first two rules are simple: + + Alias-Variable: + LT <= Scope(x) + -------------------------------------------------- + ALIAS(x, LT, PT) = (x, LT, PT, Const) + + Alias-Field: + ALIAS(LV, LT, Partial) = LOANS + ------------------------------------------------------------ + ALIAS(LV.f, LT, PT) = LOANS, (LV.F, LT, PT, Const) + +### Aliasing owned pointers + +The rule for owned pointers is somewhat interesting: + + Alias-Owned-Ptr: + Type(LV) = ~Ty + FREEZE(LV, LT, Partial) = LOANS + ------------------------------------------------------------ + ALIAS(*LV, LT, PT) = LOANS, (*LV, LT, PT, Const) + +Here we *freeze* the base `LV`. The reason is that if an owned +pointer is mutated it frees its content, which means that the alias to +`*LV` would become a dangling pointer. + +### Aliasing borrowed pointers + +The rule for borrowed pointers is quite simple, because borrowed +pointers do not own their content and thus do not play a role in +keeping it live: + + Alias-Borrowed-Ptr: + Type(LV) = <_P MQ Ty + LT <= LT_P + ------------------------------------------------------------ + ALIAS(*LV, LT, PT) = [] + +Basically, the existence of a borrowed pointer to some memory with +lifetime LT_P is proof that the memory can safely be aliased for any +lifetime LT <= LT_P. + +### Aliasing managed pointers + +The rules for aliasing managed pointers are similar to those +used with FREEZE, except that they apply to all manager pointers +regardles of mutability: + + Alias-Managed-Ptr-1: + Type(LV) = @MQ Ty + Add ROOT annotation for *LV + ------------------------------------------------------------ + ALIAS(*LV, LT, PT) = [] + + Alias-Managed-Ptr-2: + Type(LV) = @MQ Ty + LT <= Scope(LV) + Mut(LV) = imm + LV is not moved + ------------------------------------------------------------ + ALIAS(*LV, LT, PT) = [] + +## The RESERVE function + +The final function, RESERVE, is used for loans of `&mut` pointers. As +discussed in the section on the function MUTATE, we must be quite +careful when "re-borrowing" an `&mut` pointer to ensure that the original +`&mut` pointer can no longer be used to mutate. + +There are a couple of dangers to be aware of: + +- `&mut` pointers do not inherit mutability. Therefore, if you have + an lvalue LV with type `&mut T` and you freeze `LV`, you do *not* + freeze `*LV`. This is quite different from an `LV` with type `~T`. + +- Also, because they do not inherit mutability, if the `&mut` pointer + lives in an aliased location, then *any alias* can be used to write! + +As a consequence of these two rules, RESERVE can only be successfully +invoked on an lvalue LV that is *owned by the current stack frame*. +This ensures that there are no aliases that are not visible from the +outside. Moreover, Reserve loans are incompatible with all other +loans, even Const loans. This prevents any aliases from being created +within the current function. + +### Reserving local variables + +The rule for reserving a variable is generally straightforward but +with one interesting twist: + + Reserve-Variable: + -------------------------------------------------- + RESERVE(x, LT) = (x, LT, Total, Reserve) + +The twist here is that the incoming lifetime is not required to +be a subset of the incoming variable, unlike every other case. To +see the reason for this, imagine the following function: + + struct Foo { count: uint } + fn count_field(x: &'a mut Foo) -> &'a mut count { + &mut (*x).count + } + +This function consumes one `&mut` pointer and returns another with the +same lifetime pointing at a particular field. The borrow for the +`&mut` expression will result in a call to `RESERVE(x, 'a)`, which is +intended to guarantee that `*x` is not later aliased or used to +mutate. But the lifetime of `x` is limited to the current function, +which is a sublifetime of the parameter `'a`, so the rules used for +MUTATE, FREEZE, and ALIAS (which require that the lifetime of the loan +not exceed the lifetime of the variable) would result in an error. + +Nonetheless this function is perfectly legitimate. After all, the +caller has moved in an `&mut` pointer with lifetime `'a`, and thus has +given up their right to mutate the value for the remainder of `'a`. +So it is fine for us to return a pointer with the same lifetime. + +The reason that RESERVE differs from the other functions is that +RESERVE is not responsible for guaranteeing that the pointed-to data +will outlive the borrowed pointer being created. After all, `&mut` +values do not own the data they point at. + +### Reserving owned content + +The rules for fields and owned pointers are very straightforward: + + Reserve-Field: + RESERVE(LV, LT) = LOANS + ------------------------------------------------------------ + RESERVE(LV.f, LT) = LOANS, (LV.F, LT, Total, Reserve) + + Reserve-Owned-Ptr: + Type(LV) = ~Ty + RESERVE(LV, LT) = LOANS + ------------------------------------------------------------ + RESERVE(*LV, LT) = LOANS, (*LV, LT, Total, Reserve) + +### Reserving `&mut` borrowed pointers + +Unlike other borrowed pointers, `&mut` pointers are unaliasable, +so we can reserve them like everything else: + + Reserve-Mut-Borrowed-Ptr: + Type(LV) = <_P mut Ty + RESERVE(LV, LT) = LOANS + ------------------------------------------------------------ + RESERVE(*LV, LT) = LOANS, (*LV, LT, Total, Reserve) + +## Borrows in calls + +Earlier we said that the MUTATE, FREEZE, and ALIAS functions were used +to compute the loans resulting from a borrow expression. But this is +not strictly correct, there is a slight complication that occurs with +calls by which additional loans may be necessary. We will explain +that here and give the full details. + +Imagine a call expression `'a: E1(E2, E3)`, where `Ei` are some +expressions. If we break this down to something a bit lower-level, it +is kind of short for: + + 'a: { + 'a_arg1: let temp1: ... = E1; + 'a_arg2: let temp2: ... = E2; + 'a_arg3: let temp3: ... = E3; + 'a_call: temp1(temp2, temp3) + } + +Here the lifetime labels indicate the various lifetimes. As you can +see there are in fact four relevant lifetimes (only one of which was +named by the user): `'a` corresponds to the expression `E1(E2, E3)` as +a whole. `'a_arg1`, `'a_arg2`, and `'a_arg3` correspond to the +evaluations of `E1`, `E2`, and `E3` respectively. Finally, `'a_call` +corresponds to the *actual call*, which is the point where the values +of the parameters will be used. + +Now, let's look at a (contrived, but representative) example to see +why all this matters: + + struct Foo { f: uint, g: uint } + ... + fn add(p: &mut uint, v: uint) { + *p += v; + } + ... + fn inc(p: &mut uint) -> uint { + *p += 1; *p + } + fn weird() { + let mut x: ~Foo = ~Foo { ... }; + 'a: add(&mut (*x).f, + 'b: inc(&mut (*x).f)) // (*) + } + +The important part is the line marked `(*)` which contains a call to +`add()`. The first argument is a mutable borrow of the field `f`. +The second argument *always borrows* the field `f`. Now, if these two +borrows overlapped in time, this would be illegal, because there would +be two `&mut` pointers pointing at `f`. And, in a way, they *do* +overlap in time, since the first argument will be evaluated first, +meaning that the pointer will exist when the second argument executes. +But in another important way they do not overlap in time. Let's +expand out that final call to `add()` as we did before: + + 'a: { + 'a_arg1: let a_temp1: ... = add; + 'a_arg2: let a_temp2: &'a_call mut uint = &'a_call mut (*x).f; + 'a_arg3_: let a_temp3: uint = { + let b_temp1: ... = inc; + let b_temp2: &'b_call = &'b_call mut (*x).f; + 'b_call: b_temp1(b_temp2) + }; + 'a_call: a_temp1(a_temp2, a_temp3) + } + +When it's written this way, we can see that although there are two +borrows, the first has lifetime `'a_call` and the second has lifetime +`'b_call` and in fact these lifetimes do not overlap. So everything +is fine. + +But this does not mean that there isn't reason for caution! Imagine a +devious program like *this* one: + + struct Foo { f: uint, g: uint } + ... + fn add(p: &mut uint, v: uint) { + *p += v; + } + ... + fn consume(x: ~Foo) -> uint { + x.f + x.g + } + fn weird() { + let mut x: ~Foo = ~Foo { ... }; + 'a: add(&mut (*x).f, consume(x)) // (*) + } + +In this case, there is only one borrow, but the second argument is +`consume(x)` instead of a second borrow. Because `consume()` is +declared to take a `~Foo`, it will in fact free the pointer `x` when +it has finished executing. If it is not obvious why this is +troublesome, consider this expanded version of that call: + + 'a: { + 'a_arg1: let a_temp1: ... = add; + 'a_arg2: let a_temp2: &'a_call mut uint = &'a_call mut (*x).f; + 'a_arg3_: let a_temp3: uint = { + let b_temp1: ... = consume; + let b_temp2: ~Foo = x; + 'b_call: b_temp1(x) + }; + 'a_call: a_temp1(a_temp2, a_temp3) + } + +In this example, we will have borrowed the first argument before `x` +is freed and then free `x` during evaluation of the second +argument. This causes `a_temp2` to be invalidated. + +Of course the loans computed from the borrow expression are supposed +to prevent this situation. But if we just considered the loans from +`MUTATE((*x).f, 'a_call, Total)`, the resulting loans would be: + + ((*x).f, 'a_call, Total, Mut) + (*x, 'a_call, Partial, Mut) + (x, 'a_call, Partial, Mut) + +Because these loans are only in scope for `'a_call`, they do nothing +to prevent the move that occurs evaluating the second argument. + +The way that we solve this is to say that if you have a borrow +expression `&'LT_P mut LV` which itself occurs in the lifetime +`'LT_B`, then the resulting loans are: + + MUTATE(LV, LT_P, Total) + ALIAS(LV, LUB(LT_P, LT_B), Total) + +The call to MUTATE is what we've seen so far. The second part +expresses the idea that the expression LV will be evaluated starting +at LT_B until the end of LT_P. Now, in the normal case, LT_P >= LT_B, +and so the second set of loans that result from a ALIAS are basically +a no-op. However, in the case of an argument where the evaluation of +the borrow occurs before the interval where the resulting pointer will +be used, this ALIAS is important. + +In the case of our example, it would produce a set of loans like: + + ((*x).f, 'a, Total, Const) + (*x, 'a, Total, Const) + (x, 'a, Total, Imm) + +The scope of these loans is `'a = LUB('a_arg2, 'a_call)`, and so they +encompass all subsequent arguments. The first set of loans are Const +loans, which basically just prevent moves. However, when we cross +over the dereference of the owned pointer `x`, the rule for ALIAS +specifies that `x` must be frozen, and hence the final loan is an Imm +loan. In any case the troublesome second argument would be flagged +as an error. + +# Maps that are created + +Borrowck results in two maps. + +- `root_map`: identifies those expressions or patterns whose result + needs to be rooted. Conceptually the root_map maps from an + expression or pattern node to a `node_id` identifying the scope for + which the expression must be rooted (this `node_id` should identify + a block or call). The actual key to the map is not an expression id, + however, but a `root_map_key`, which combines an expression id with a + deref count and is used to cope with auto-deref. + +*/ diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs deleted file mode 100644 index e40d0e63eb38e..0000000000000 --- a/src/librustc/middle/borrowck/gather_loans.rs +++ /dev/null @@ -1,643 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ---------------------------------------------------------------------- -// Gathering loans -// -// The borrow check proceeds in two phases. In phase one, we gather the full -// set of loans that are required at any point. These are sorted according to -// their associated scopes. In phase two, checking loans, we will then make -// sure that all of these loans are honored. - -use middle::borrowck::preserve::{PreserveCondition, PcOk, PcIfPure}; -use middle::borrowck::{Loan, bckerr, bckres, BorrowckCtxt, err_mutbl}; -use middle::borrowck::{LoanKind, TotalFreeze, PartialFreeze, - TotalTake, PartialTake, Immobile}; -use middle::borrowck::ReqMaps; -use middle::borrowck::loan; -use middle::mem_categorization::{cmt, mem_categorization_ctxt}; -use middle::pat_util; -use middle::ty::{ty_region}; -use middle::ty; -use util::common::indenter; -use util::ppaux::{Repr, region_to_str}; - -use core::hashmap::{HashSet, HashMap}; -use syntax::ast::{m_const, m_imm, m_mutbl}; -use syntax::ast; -use syntax::codemap::span; -use syntax::print::pprust; -use syntax::visit; - -/// Context used while gathering loans: -/// -/// - `bccx`: the the borrow check context -/// - `req_maps`: the maps computed by `gather_loans()`, see def'n of the -/// struct `ReqMaps` for more info -/// - `item_ub`: the id of the block for the enclosing fn/method item -/// - `root_ub`: the id of the outermost block for which we can root -/// an `@T`. This is the id of the innermost enclosing -/// loop or function body. -/// -/// The role of `root_ub` is to prevent us from having to accumulate -/// vectors of rooted items at runtime. Consider this case: -/// -/// fn foo(...) -> int { -/// let mut ptr: ∫ -/// while some_cond { -/// let x: @int = ...; -/// ptr = &*x; -/// } -/// *ptr -/// } -/// -/// If we are not careful here, we would infer the scope of the borrow `&*x` -/// to be the body of the function `foo()` as a whole. We would then -/// have root each `@int` that is produced, which is an unbounded number. -/// No good. Instead what will happen is that `root_ub` will be set to the -/// body of the while loop and we will refuse to root the pointer `&*x` -/// because it would have to be rooted for a region greater than `root_ub`. -struct GatherLoanCtxt { - bccx: @BorrowckCtxt, - req_maps: ReqMaps, - item_ub: ast::node_id, - root_ub: ast::node_id, - ignore_adjustments: HashSet -} - -pub fn gather_loans(bccx: @BorrowckCtxt, crate: @ast::crate) -> ReqMaps { - let glcx = @mut GatherLoanCtxt { - bccx: bccx, - req_maps: ReqMaps { req_loan_map: HashMap::new(), - pure_map: HashMap::new() }, - item_ub: 0, - root_ub: 0, - ignore_adjustments: HashSet::new() - }; - let v = visit::mk_vt(@visit::Visitor {visit_expr: req_loans_in_expr, - visit_fn: req_loans_in_fn, - visit_stmt: add_stmt_to_map, - .. *visit::default_visitor()}); - visit::visit_crate(crate, glcx, v); - let @GatherLoanCtxt{req_maps, _} = glcx; - return req_maps; -} - -fn req_loans_in_fn(fk: &visit::fn_kind, - decl: &ast::fn_decl, - body: &ast::blk, - sp: span, - id: ast::node_id, - self: @mut GatherLoanCtxt, - v: visit::vt<@mut GatherLoanCtxt>) { - // see explanation attached to the `root_ub` field: - let old_item_id = self.item_ub; - let old_root_ub = self.root_ub; - self.root_ub = body.node.id; - - match *fk { - visit::fk_anon(*) | visit::fk_fn_block(*) => {} - visit::fk_item_fn(*) | visit::fk_method(*) | - visit::fk_dtor(*) => { - self.item_ub = body.node.id; - } - } - - visit::visit_fn(fk, decl, body, sp, id, self, v); - self.root_ub = old_root_ub; - self.item_ub = old_item_id; -} - -fn req_loans_in_expr(ex: @ast::expr, - self: @mut GatherLoanCtxt, - vt: visit::vt<@mut GatherLoanCtxt>) { - let bccx = self.bccx; - let tcx = bccx.tcx; - let old_root_ub = self.root_ub; - - debug!("req_loans_in_expr(expr=%?/%s)", - ex.id, pprust::expr_to_str(ex, tcx.sess.intr())); - - // If this expression is borrowed, have to ensure it remains valid: - { - let mut this = &mut *self; - if !this.ignore_adjustments.contains(&ex.id) { - for tcx.adjustments.find(&ex.id).each |&adjustments| { - this.guarantee_adjustments(ex, *adjustments); - } - } - } - - // Special checks for various kinds of expressions: - match ex.node { - ast::expr_addr_of(mutbl, base) => { - let base_cmt = self.bccx.cat_expr(base); - - // make sure that the thing we are pointing out stays valid - // for the lifetime `scope_r` of the resulting ptr: - let scope_r = ty_region(tcx, ex.span, tcx.ty(ex)); - self.guarantee_valid(base_cmt, mutbl, scope_r); - visit::visit_expr(ex, self, vt); - } - - ast::expr_match(ex_v, ref arms) => { - let cmt = self.bccx.cat_expr(ex_v); - for (*arms).each |arm| { - for arm.pats.each |pat| { - self.gather_pat(cmt, *pat, arm.body.node.id, ex.id); - } - } - visit::visit_expr(ex, self, vt); - } - - ast::expr_index(rcvr, _) | - ast::expr_binary(_, rcvr, _) | - ast::expr_unary(_, rcvr) | - ast::expr_assign_op(_, rcvr, _) - if self.bccx.method_map.contains_key(&ex.id) => { - // Receivers in method calls are always passed by ref. - // - // Here, in an overloaded operator, the call is this expression, - // and hence the scope of the borrow is this call. - // - // FIX? / NOT REALLY---technically we should check the other - // argument and consider the argument mode. But how annoying. - // And this problem when goes away when argument modes are - // phased out. So I elect to leave this undone. - let scope_r = ty::re_scope(ex.id); - let rcvr_cmt = self.bccx.cat_expr(rcvr); - self.guarantee_valid(rcvr_cmt, m_imm, scope_r); - - // FIXME (#3387): Total hack: Ignore adjustments for the left-hand - // side. Their regions will be inferred to be too large. - self.ignore_adjustments.insert(rcvr.id); - - visit::visit_expr(ex, self, vt); - } - - // FIXME--#3387 - // ast::expr_binary(_, lhs, rhs) => { - // // Universal comparison operators like ==, >=, etc - // // take their arguments by reference. - // let lhs_ty = ty::expr_ty(self.tcx(), lhs); - // if !ty::type_is_scalar(lhs_ty) { - // let scope_r = ty::re_scope(ex.id); - // let lhs_cmt = self.bccx.cat_expr(lhs); - // self.guarantee_valid(lhs_cmt, m_imm, scope_r); - // let rhs_cmt = self.bccx.cat_expr(rhs); - // self.guarantee_valid(rhs_cmt, m_imm, scope_r); - // } - // visit::visit_expr(ex, self, vt); - // } - - ast::expr_field(rcvr, _, _) - if self.bccx.method_map.contains_key(&ex.id) => { - // Receivers in method calls are always passed by ref. - // - // Here, the field a.b is in fact a closure. Eventually, this - // should be an &fn, but for now it's an @fn. In any case, - // the enclosing scope is either the call where it is a rcvr - // (if used like `a.b(...)`), the call where it's an argument - // (if used like `x(a.b)`), or the block (if used like `let x - // = a.b`). - let scope_r = self.tcx().region_maps.encl_region(ex.id); - let rcvr_cmt = self.bccx.cat_expr(rcvr); - self.guarantee_valid(rcvr_cmt, m_imm, scope_r); - visit::visit_expr(ex, self, vt); - } - - // see explanation attached to the `root_ub` field: - ast::expr_while(cond, ref body) => { - // during the condition, can only root for the condition - self.root_ub = cond.id; - (vt.visit_expr)(cond, self, vt); - - // during body, can only root for the body - self.root_ub = body.node.id; - (vt.visit_block)(body, self, vt); - } - - // see explanation attached to the `root_ub` field: - ast::expr_loop(ref body, _) => { - self.root_ub = body.node.id; - visit::visit_expr(ex, self, vt); - } - - _ => { - visit::visit_expr(ex, self, vt); - } - } - - // Check any contained expressions: - - self.root_ub = old_root_ub; -} - -pub impl GatherLoanCtxt { - fn tcx(&mut self) -> ty::ctxt { self.bccx.tcx } - - fn guarantee_adjustments(&mut self, - expr: @ast::expr, - adjustment: &ty::AutoAdjustment) { - debug!("guarantee_adjustments(expr=%s, adjustment=%?)", - expr.repr(self.tcx()), adjustment); - let _i = indenter(); - - match *adjustment { - ty::AutoAddEnv(*) => { - debug!("autoaddenv -- no autoref"); - return; - } - - ty::AutoDerefRef( - ty::AutoDerefRef { - autoref: None, _ }) => { - debug!("no autoref"); - return; - } - - ty::AutoDerefRef( - ty::AutoDerefRef { - autoref: Some(ref autoref), - autoderefs: autoderefs}) => { - let mcx = &mem_categorization_ctxt { - tcx: self.tcx(), - method_map: self.bccx.method_map}; - let cmt = mcx.cat_expr_autoderefd(expr, autoderefs); - debug!("after autoderef, cmt=%s", self.bccx.cmt_to_repr(cmt)); - - match autoref.kind { - ty::AutoPtr => { - self.guarantee_valid(cmt, - autoref.mutbl, - autoref.region) - } - ty::AutoBorrowVec | ty::AutoBorrowVecRef => { - let cmt_index = mcx.cat_index(expr, cmt); - self.guarantee_valid(cmt_index, - autoref.mutbl, - autoref.region) - } - ty::AutoBorrowFn => { - let cmt_deref = mcx.cat_deref_fn(expr, cmt, 0); - self.guarantee_valid(cmt_deref, - autoref.mutbl, - autoref.region) - } - } - } - } - } - - // guarantees that addr_of(cmt) will be valid for the duration of - // `static_scope_r`, or reports an error. This may entail taking - // out loans, which will be added to the `req_loan_map`. This can - // also entail "rooting" GC'd pointers, which means ensuring - // dynamically that they are not freed. - fn guarantee_valid(&mut self, - cmt: cmt, - req_mutbl: ast::mutability, - scope_r: ty::Region) - { - - let loan_kind = match req_mutbl { - m_mutbl => TotalTake, - m_imm => TotalFreeze, - m_const => Immobile - }; - - self.bccx.stats.guaranteed_paths += 1; - - debug!("guarantee_valid(cmt=%s, req_mutbl=%?, \ - loan_kind=%?, scope_r=%s)", - self.bccx.cmt_to_repr(cmt), - req_mutbl, - loan_kind, - region_to_str(self.tcx(), scope_r)); - let _i = indenter(); - - match cmt.lp { - // If this expression is a loanable path, we MUST take out a - // loan. This is somewhat non-obvious. You might think, - // for example, that if we have an immutable local variable - // `x` whose value is being borrowed, we could rely on `x` - // not to change. This is not so, however, because even - // immutable locals can be moved. So we take out a loan on - // `x`, guaranteeing that it remains immutable for the - // duration of the reference: if there is an attempt to move - // it within that scope, the loan will be detected and an - // error will be reported. - Some(_) => { - match loan::loan(self.bccx, cmt, scope_r, loan_kind) { - Err(ref e) => { self.bccx.report((*e)); } - Ok(loans) => { - self.add_loans(cmt, loan_kind, scope_r, loans); - } - } - } - - // The path is not loanable: in that case, we must try and - // preserve it dynamically (or see that it is preserved by - // virtue of being rooted in some immutable path). We must - // also check that the mutability of the desired pointer - // matches with the actual mutability (but if an immutable - // pointer is desired, that is ok as long as we are pure) - None => { - let result: bckres = { - do self.check_mutbl(loan_kind, cmt).chain |pc1| { - do self.bccx.preserve(cmt, scope_r, - self.item_ub, - self.root_ub).chain |pc2| { - Ok(pc1.combine(pc2)) - } - } - }; - - match result { - Ok(PcOk) => { - debug!("result of preserve: PcOk"); - - // we were able guarantee the validity of the ptr, - // perhaps by rooting or because it is immutably - // rooted. good. - self.bccx.stats.stable_paths += 1; - } - Ok(PcIfPure(ref e)) => { - debug!("result of preserve: %?", PcIfPure((*e))); - - // we are only able to guarantee the validity if - // the scope is pure - match scope_r { - ty::re_scope(pure_id) => { - // if the scope is some block/expr in the - // fn, then just require that this scope - // be pure - self.req_maps.pure_map.insert(pure_id, *e); - self.bccx.stats.req_pure_paths += 1; - - debug!("requiring purity for scope %?", - scope_r); - - if self.tcx().sess.borrowck_note_pure() { - self.bccx.span_note( - cmt.span, - fmt!("purity required")); - } - } - _ => { - // otherwise, we can't enforce purity for - // that scope, so give up and report an - // error - self.bccx.report((*e)); - } - } - } - Err(ref e) => { - // we cannot guarantee the validity of this pointer - debug!("result of preserve: error"); - self.bccx.report((*e)); - } - } - } - } - } - - // Check that the pat `cmt` is compatible with the required - // mutability, presuming that it can be preserved to stay alive - // long enough. - // - // For example, if you have an expression like `&x.f` where `x` - // has type `@mut{f:int}`, this check might fail because `&x.f` - // reqires an immutable pointer, but `f` lives in (aliased) - // mutable memory. - fn check_mutbl(&mut self, - loan_kind: LoanKind, - cmt: cmt) - -> bckres { - debug!("check_mutbl(loan_kind=%?, cmt.mutbl=%?)", - loan_kind, cmt.mutbl); - - match loan_kind { - Immobile => Ok(PcOk), - - TotalTake | PartialTake => { - if cmt.mutbl.is_mutable() { - Ok(PcOk) - } else { - Err(bckerr { cmt: cmt, code: err_mutbl(loan_kind) }) - } - } - - TotalFreeze | PartialFreeze => { - if cmt.mutbl.is_immutable() { - Ok(PcOk) - } else if cmt.cat.is_mutable_box() { - Ok(PcOk) - } else { - // Eventually: - let e = bckerr {cmt: cmt, - code: err_mutbl(loan_kind)}; - Ok(PcIfPure(e)) - } - } - } - } - - fn add_loans(&mut self, - cmt: cmt, - loan_kind: LoanKind, - scope_r: ty::Region, - loans: ~[Loan]) { - if loans.len() == 0 { - return; - } - - // Normally we wouldn't allow `re_free` here. However, in this case - // it should be sound. Below is nmatsakis' reasoning: - // - // Perhaps [this permits] a function kind of like this one here, which - // consumes one mut pointer and returns a narrower one: - // - // struct Foo { f: int } - // fn foo(p: &'v mut Foo) -> &'v mut int { &mut p.f } - // - // I think this should work fine but there is more subtlety to it than - // I at first imagined. Unfortunately it's a very important use case, - // I think, so it really ought to work. The changes you [pcwalton] - // made to permit re_free() do permit this case, I think, but I'm not - // sure what else they permit. I have to think that over a bit. - // - // Ordinarily, a loan with scope re_free wouldn't make sense, because - // you couldn't enforce it. But in this case, your function signature - // informs the caller that you demand exclusive access to p and its - // contents for the lifetime v. Since borrowed pointers are - // non-copyable, they must have (a) made a borrow which will enforce - // those conditions and then (b) given you the resulting pointer. - // Therefore, they should be respecting the loan. So it actually seems - // that it's ok in this case to have a loan with re_free, so long as - // the scope of the loan is no greater than the region pointer on - // which it is based. Neat but not something I had previously - // considered all the way through. (Note that we already rely on - // similar reasoning to permit you to return borrowed pointers into - // immutable structures, this is just the converse I suppose) - - let scope_id = match scope_r { - ty::re_scope(scope_id) | - ty::re_free(ty::FreeRegion {scope_id, _}) => { - scope_id - } - _ => { - self.bccx.tcx.sess.span_bug( - cmt.span, - fmt!("loans required but scope is scope_region is %s \ - (%?)", - region_to_str(self.tcx(), scope_r), - scope_r)); - } - }; - - self.add_loans_to_scope_id(scope_id, loans); - - if loan_kind.is_freeze() && !cmt.mutbl.is_immutable() { - self.bccx.stats.loaned_paths_imm += 1; - - if self.tcx().sess.borrowck_note_loan() { - self.bccx.span_note( - cmt.span, - fmt!("immutable loan required")); - } - } else { - self.bccx.stats.loaned_paths_same += 1; - } - } - - fn add_loans_to_scope_id(&mut self, - scope_id: ast::node_id, - loans: ~[Loan]) { - debug!("adding %u loans to scope_id %?: %s", - loans.len(), scope_id, - str::connect(loans.map(|l| self.bccx.loan_to_repr(l)), ", ")); - match self.req_maps.req_loan_map.find(&scope_id) { - Some(req_loans) => { - req_loans.push_all(loans); - return; - } - None => {} - } - self.req_maps.req_loan_map.insert(scope_id, @mut loans); - } - - fn gather_pat(@mut self, - discr_cmt: cmt, - root_pat: @ast::pat, - arm_id: ast::node_id, - match_id: ast::node_id) { - do self.bccx.cat_pattern(discr_cmt, root_pat) |cmt, pat| { - match pat.node { - ast::pat_ident(bm, _, _) if self.pat_is_binding(pat) => { - match bm { - ast::bind_by_ref(mutbl) => { - // ref x or ref x @ p --- creates a ptr which must - // remain valid for the scope of the match - - // find the region of the resulting pointer (note that - // the type of such a pattern will *always* be a - // region pointer) - let scope_r = ty_region(self.tcx(), pat.span, - self.tcx().ty(pat)); - - // if the scope of the region ptr turns out to be - // specific to this arm, wrap the categorization with - // a cat_discr() node. There is a detailed discussion - // of the function of this node in method preserve(): - let arm_scope = ty::re_scope(arm_id); - if self.bccx.is_subregion_of(scope_r, arm_scope) { - let cmt_discr = self.bccx.cat_discr(cmt, match_id); - self.guarantee_valid(cmt_discr, mutbl, scope_r); - } else { - self.guarantee_valid(cmt, mutbl, scope_r); - } - } - ast::bind_by_copy | ast::bind_infer => { - // Nothing to do here; neither copies nor moves induce - // borrows. - } - } - } - - ast::pat_vec(_, Some(slice_pat), _) => { - // The `slice_pat` here creates a slice into the - // original vector. This is effectively a borrow of - // the elements of the vector being matched. - - let slice_ty = self.tcx().ty(slice_pat); - let (slice_mutbl, slice_r) = - self.vec_slice_info(slice_pat, slice_ty); - let mcx = self.bccx.mc_ctxt(); - let cmt_index = mcx.cat_index(slice_pat, cmt); - self.guarantee_valid(cmt_index, slice_mutbl, slice_r); - } - - _ => {} - } - } - } - - fn vec_slice_info(@mut self, - pat: @ast::pat, - slice_ty: ty::t) -> (ast::mutability, ty::Region) { - /*! - * - * In a pattern like [a, b, ..c], normally `c` has slice type, - * but if you have [a, b, ..ref c], then the type of `ref c` - * will be `&&[]`, so to extract the slice details we have - * to recurse through rptrs. - */ - - match ty::get(slice_ty).sty { - ty::ty_evec(slice_mt, ty::vstore_slice(slice_r)) => { - (slice_mt.mutbl, slice_r) - } - - ty::ty_rptr(_, ref mt) => { - self.vec_slice_info(pat, mt.ty) - } - - _ => { - self.tcx().sess.span_bug( - pat.span, - fmt!("Type of slice pattern is not a slice")); - } - } - } - - fn pat_is_variant_or_struct(@mut self, pat: @ast::pat) -> bool { - pat_util::pat_is_variant_or_struct(self.bccx.tcx.def_map, pat) - } - - fn pat_is_binding(@mut self, pat: @ast::pat) -> bool { - pat_util::pat_is_binding(self.bccx.tcx.def_map, pat) - } -} - -// Setting up info that preserve needs. -// This is just the most convenient place to do it. -fn add_stmt_to_map(stmt: @ast::stmt, - self: @mut GatherLoanCtxt, - vt: visit::vt<@mut GatherLoanCtxt>) { - match stmt.node { - ast::stmt_expr(_, id) | ast::stmt_semi(_, id) => { - self.bccx.stmt_map.insert(id); - } - _ => () - } - visit::visit_stmt(stmt, self, vt); -} - diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs new file mode 100644 index 0000000000000..21d7e7041d959 --- /dev/null +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -0,0 +1,322 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module implements the check that the lifetime of a borrow +//! does not exceed the lifetime of the value being borrowed. + +use core::prelude::*; +use middle::borrowck::*; +use mc = middle::mem_categorization; +use middle::ty; +use syntax::ast::{m_const, m_imm, m_mutbl}; +use syntax::ast; +use syntax::codemap::span; + +pub fn guarantee_lifetime(bccx: @BorrowckCtxt, + item_scope_id: ast::node_id, + root_scope_id: ast::node_id, + span: span, + cmt: mc::cmt, + loan_region: ty::Region, + loan_mutbl: ast::mutability) { + debug!("guarantee_lifetime(cmt=%s, loan_region=%s)", + cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx)); + let ctxt = GuaranteeLifetimeContext {bccx: bccx, + item_scope_id: item_scope_id, + span: span, + loan_region: loan_region, + loan_mutbl: loan_mutbl, + cmt_original: cmt, + root_scope_id: root_scope_id}; + ctxt.check(cmt, None); +} + +/////////////////////////////////////////////////////////////////////////// +// Private + +struct GuaranteeLifetimeContext { + bccx: @BorrowckCtxt, + + // the node id of the function body for the enclosing item + item_scope_id: ast::node_id, + + // the node id of the innermost loop / function body; this is the + // longest scope for which we can root managed boxes + root_scope_id: ast::node_id, + + span: span, + loan_region: ty::Region, + loan_mutbl: ast::mutability, + cmt_original: mc::cmt +} + +impl GuaranteeLifetimeContext { + fn tcx(&self) -> ty::ctxt { + self.bccx.tcx + } + + fn check(&self, cmt: mc::cmt, discr_scope: Option) { + //! Main routine. Walks down `cmt` until we find the "guarantor". + + match cmt.cat { + mc::cat_rvalue | + mc::cat_implicit_self | + mc::cat_copied_upvar(*) | + mc::cat_local(*) | + mc::cat_arg(*) | + mc::cat_self(*) | + mc::cat_deref(_, _, mc::region_ptr(*)) | + mc::cat_deref(_, _, mc::unsafe_ptr) => { + let scope = self.scope(cmt); + self.check_scope(scope) + } + + mc::cat_stack_upvar(cmt) => { + self.check(cmt, discr_scope) + } + + mc::cat_static_item => { + } + + mc::cat_deref(base, derefs, mc::gc_ptr(ptr_mutbl)) => { + let base_scope = self.scope(base); + + // See rule Freeze-Imm-Managed-Ptr-2 in doc.rs + let omit_root = ( + self.bccx.is_subregion_of(self.loan_region, base_scope) && + base.mutbl.is_immutable() && + !self.is_moved(base) + ); + + if !omit_root { + self.check_root(base, derefs, ptr_mutbl, discr_scope); + } else { + debug!("omitting root, base=%s, base_scope=%?", + base.repr(self.tcx()), base_scope); + } + } + + mc::cat_deref(base, _, mc::uniq_ptr(*)) | + mc::cat_interior(base, _) => { + self.check(base, discr_scope) + } + + mc::cat_discr(base, new_discr_scope) => { + // Subtle: in a match, we must ensure that each binding + // variable remains valid for the duration of the arm in + // which it appears, presuming that this arm is taken. + // But it is inconvenient in trans to root something just + // for one arm. Therefore, we insert a cat_discr(), + // basically a special kind of category that says "if this + // value must be dynamically rooted, root it for the scope + // `match_id`. + // + // As an example, consider this scenario: + // + // let mut x = @Some(3); + // match *x { Some(y) {...} None {...} } + // + // Technically, the value `x` need only be rooted + // in the `some` arm. However, we evaluate `x` in trans + // before we know what arm will be taken, so we just + // always root it for the duration of the match. + // + // As a second example, consider *this* scenario: + // + // let x = @mut @Some(3); + // match x { @@Some(y) {...} @@None {...} } + // + // Here again, `x` need only be rooted in the `some` arm. + // In this case, the value which needs to be rooted is + // found only when checking which pattern matches: but + // this check is done before entering the arm. Therefore, + // even in this case we just choose to keep the value + // rooted for the entire match. This means the value will be + // rooted even if the none arm is taken. Oh well. + // + // At first, I tried to optimize the second case to only + // root in one arm, but the result was suboptimal: first, + // it interfered with the construction of phi nodes in the + // arm, as we were adding code to root values before the + // phi nodes were added. This could have been addressed + // with a second basic block. However, the naive approach + // also yielded suboptimal results for patterns like: + // + // let x = @mut @...; + // match x { @@some_variant(y) | @@some_other_variant(y) => + // + // The reason is that we would root the value once for + // each pattern and not once per arm. This is also easily + // fixed, but it's yet more code for what is really quite + // the corner case. + // + // Nonetheless, if you decide to optimize this case in the + // future, you need only adjust where the cat_discr() + // node appears to draw the line between what will be rooted + // in the *arm* vs the *match*. + self.check(base, Some(new_discr_scope)) + } + } + } + + fn check_root(&self, + cmt_base: mc::cmt, + derefs: uint, + ptr_mutbl: ast::mutability, + discr_scope: Option) { + debug!("check_root(cmt_base=%s, derefs=%? ptr_mutbl=%?, \ + discr_scope=%?)", + cmt_base.repr(self.tcx()), + derefs, + ptr_mutbl, + discr_scope); + + // Make sure that the loan does not exceed the maximum time + // that we can root the value, dynamically. + let root_region = ty::re_scope(self.root_scope_id); + if !self.bccx.is_subregion_of(self.loan_region, root_region) { + self.report_error( + err_out_of_root_scope(root_region, self.loan_region)); + return; + } + + // Extract the scope id that indicates how long the rooting is required + let root_scope = match self.loan_region { + ty::re_scope(id) => id, + _ => { + // the check above should fail for anything is not re_scope + self.bccx.tcx.sess.span_bug( + cmt_base.span, + fmt!("Cannot issue root for scope region: %?", + self.loan_region)); + } + }; + + // If inside of a match arm, expand the rooting to the entire + // match. See the detailed discussion in `check()` above. + let mut root_scope = match discr_scope { + None => root_scope, + Some(id) => { + if self.bccx.is_subscope_of(root_scope, id) { + id + } else { + root_scope + } + } + }; + + // FIXME(#3511) grow to the nearest cleanup scope---this can + // cause observable errors if freezing! + if !self.bccx.tcx.region_maps.is_cleanup_scope(root_scope) { + debug!("%? is not a cleanup scope, adjusting", root_scope); + root_scope = self.bccx.tcx.region_maps.cleanup_scope(root_scope); + } + + // If we are borrowing the inside of an `@mut` box, + // we need to dynamically mark it to prevent incompatible + // borrows from happening later. + let opt_dyna = match ptr_mutbl { + m_imm | m_const => None, + m_mutbl => { + match self.loan_mutbl { + m_mutbl => Some(DynaMut), + m_imm | m_const => Some(DynaImm) + } + } + }; + + // Add a record of what is required + let rm_key = root_map_key {id: cmt_base.id, derefs: derefs}; + let root_info = RootInfo {scope: root_scope, freeze: opt_dyna}; + self.bccx.root_map.insert(rm_key, root_info); + + debug!("root_key: %? root_info: %?", rm_key, root_info); + } + + fn check_scope(&self, max_scope: ty::Region) { + //! Reports an error if `loan_region` is larger than `valid_scope` + + if !self.bccx.is_subregion_of(self.loan_region, max_scope) { + self.report_error(err_out_of_scope(max_scope, self.loan_region)); + } + } + + fn is_moved(&self, cmt: mc::cmt) -> bool { + //! True if `cmt` is something that is potentially moved + //! out of the current stack frame. + + match cmt.guarantor().cat { + mc::cat_local(id) | + mc::cat_self(id) | + mc::cat_arg(id, _) => { + self.bccx.moved_variables_set.contains(&id) + } + mc::cat_rvalue | + mc::cat_static_item | + mc::cat_implicit_self | + mc::cat_copied_upvar(*) | + mc::cat_deref(*) => { + false + } + r @ mc::cat_interior(*) | + r @ mc::cat_stack_upvar(*) | + r @ mc::cat_discr(*) => { + self.tcx().sess.span_bug( + cmt.span, + fmt!("illegal guarantor category: %?", r)); + } + } + } + + fn scope(&self, cmt: mc::cmt) -> ty::Region { + //! Returns the maximal region scope for the which the + //! lvalue `cmt` is guaranteed to be valid without any + //! rooting etc, and presuming `cmt` is not mutated. + + match cmt.cat { + mc::cat_rvalue => { + ty::re_scope(self.bccx.tcx.region_maps.cleanup_scope(cmt.id)) + } + mc::cat_implicit_self | + mc::cat_copied_upvar(_) => { + ty::re_scope(self.item_scope_id) + } + mc::cat_static_item => { + ty::re_static + } + mc::cat_local(local_id) | + mc::cat_arg(local_id, _) | + mc::cat_self(local_id) => { + self.bccx.tcx.region_maps.encl_region(local_id) + } + mc::cat_deref(_, _, mc::unsafe_ptr(*)) => { + ty::re_static + } + mc::cat_deref(_, _, mc::region_ptr(_, r)) => { + r + } + mc::cat_deref(cmt, _, mc::uniq_ptr(*)) | + mc::cat_deref(cmt, _, mc::gc_ptr(*)) | + mc::cat_interior(cmt, _) | + mc::cat_stack_upvar(cmt) | + mc::cat_discr(cmt, _) => { + self.scope(cmt) + } + } + } + + fn report_error(&self, code: bckerr_code) { + self.bccx.report(BckError { + cmt: self.cmt_original, + span: self.span, + code: code + }); + } +} diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs new file mode 100644 index 0000000000000..82638ceb4d4f1 --- /dev/null +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -0,0 +1,710 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ---------------------------------------------------------------------- +// Gathering loans +// +// The borrow check proceeds in two phases. In phase one, we gather the full +// set of loans that are required at any point. These are sorted according to +// their associated scopes. In phase two, checking loans, we will then make +// sure that all of these loans are honored. + +use core::prelude::*; + +use middle::borrowck::*; +use mc = middle::mem_categorization; +use middle::pat_util; +use middle::ty::{ty_region}; +use middle::ty; +use util::common::indenter; +use util::ppaux::{Repr}; + +use core::hashmap::HashSet; +use core::vec; +use syntax::ast::{m_const, m_imm, m_mutbl}; +use syntax::ast; +use syntax::ast_util::id_range; +use syntax::codemap::span; +use syntax::print::pprust; +use syntax::visit; + +mod lifetime; +mod restrictions; + +/// Context used while gathering loans: +/// +/// - `bccx`: the the borrow check context +/// - `item_ub`: the id of the block for the enclosing fn/method item +/// - `root_ub`: the id of the outermost block for which we can root +/// an `@T`. This is the id of the innermost enclosing +/// loop or function body. +/// +/// The role of `root_ub` is to prevent us from having to accumulate +/// vectors of rooted items at runtime. Consider this case: +/// +/// fn foo(...) -> int { +/// let mut ptr: ∫ +/// while some_cond { +/// let x: @int = ...; +/// ptr = &*x; +/// } +/// *ptr +/// } +/// +/// If we are not careful here, we would infer the scope of the borrow `&*x` +/// to be the body of the function `foo()` as a whole. We would then +/// have root each `@int` that is produced, which is an unbounded number. +/// No good. Instead what will happen is that `root_ub` will be set to the +/// body of the while loop and we will refuse to root the pointer `&*x` +/// because it would have to be rooted for a region greater than `root_ub`. +struct GatherLoanCtxt { + bccx: @BorrowckCtxt, + id_range: id_range, + all_loans: @mut ~[Loan], + item_ub: ast::node_id, + repeating_ids: ~[ast::node_id], + ignore_adjustments: HashSet +} + +pub fn gather_loans(bccx: @BorrowckCtxt, + body: &ast::blk) -> (id_range, @mut ~[Loan]) { + let glcx = @mut GatherLoanCtxt { + bccx: bccx, + id_range: id_range::max(), + all_loans: @mut ~[], + item_ub: body.node.id, + repeating_ids: ~[body.node.id], + ignore_adjustments: HashSet::new() + }; + let v = visit::mk_vt(@visit::Visitor {visit_expr: gather_loans_in_expr, + visit_block: gather_loans_in_block, + visit_fn: gather_loans_in_fn, + visit_stmt: add_stmt_to_map, + visit_pat: add_pat_to_id_range, + .. *visit::default_visitor()}); + (v.visit_block)(body, glcx, v); + return (glcx.id_range, glcx.all_loans); +} + +fn add_pat_to_id_range(p: @ast::pat, + self: @mut GatherLoanCtxt, + v: visit::vt<@mut GatherLoanCtxt>) { + // NB: This visitor function just adds the pat ids into the id + // range. We gather loans that occur in patterns using the + // `gather_pat()` method below. Eventually these two should be + // brought together. + self.id_range.add(p.id); + visit::visit_pat(p, self, v); +} + +fn gather_loans_in_fn(fk: &visit::fn_kind, + decl: &ast::fn_decl, + body: &ast::blk, + sp: span, + id: ast::node_id, + self: @mut GatherLoanCtxt, + v: visit::vt<@mut GatherLoanCtxt>) { + match fk { + // Do not visit items here, the outer loop in borrowck/mod + // will visit them for us in turn. + &visit::fk_item_fn(*) | &visit::fk_method(*) | + &visit::fk_dtor(*) => { + return; + } + + // Visit closures as part of the containing item. + &visit::fk_anon(*) | &visit::fk_fn_block(*) => { + self.push_repeating_id(body.node.id); + visit::visit_fn(fk, decl, body, sp, id, self, v); + self.pop_repeating_id(body.node.id); + } + } +} + +fn gather_loans_in_block(blk: &ast::blk, + self: @mut GatherLoanCtxt, + vt: visit::vt<@mut GatherLoanCtxt>) { + self.id_range.add(blk.node.id); + visit::visit_block(blk, self, vt); +} + +fn gather_loans_in_expr(ex: @ast::expr, + self: @mut GatherLoanCtxt, + vt: visit::vt<@mut GatherLoanCtxt>) { + let bccx = self.bccx; + let tcx = bccx.tcx; + + debug!("gather_loans_in_expr(expr=%?/%s)", + ex.id, pprust::expr_to_str(ex, tcx.sess.intr())); + + self.id_range.add(ex.id); + self.id_range.add(ex.callee_id); + + // If this expression is borrowed, have to ensure it remains valid: + { + let mut this = &mut *self; // FIXME(#5074) + if !this.ignore_adjustments.contains(&ex.id) { + for tcx.adjustments.find(&ex.id).each |&adjustments| { + this.guarantee_adjustments(ex, *adjustments); + } + } + } + + // Special checks for various kinds of expressions: + match ex.node { + ast::expr_addr_of(mutbl, base) => { + let base_cmt = self.bccx.cat_expr(base); + + // make sure that the thing we are pointing out stays valid + // for the lifetime `scope_r` of the resulting ptr: + let scope_r = ty_region(tcx, ex.span, ty::expr_ty(tcx, ex)); + self.guarantee_valid(ex.id, ex.span, base_cmt, mutbl, scope_r); + visit::visit_expr(ex, self, vt); + } + + ast::expr_call(f, ref args, _) => { + let arg_tys = ty::ty_fn_args(ty::expr_ty(self.tcx(), f)); + self.guarantee_arguments(ex, *args, arg_tys); + visit::visit_expr(ex, self, vt); + } + + ast::expr_method_call(_, _, _, ref args, _) => { + let arg_tys = ty::ty_fn_args(ty::node_id_to_type(self.tcx(), + ex.callee_id)); + self.guarantee_arguments(ex, *args, arg_tys); + + visit::visit_expr(ex, self, vt); + } + + ast::expr_match(ex_v, ref arms) => { + let cmt = self.bccx.cat_expr(ex_v); + for arms.each |arm| { + for arm.pats.each |pat| { + self.gather_pat(cmt, *pat, arm.body.node.id, ex.id); + } + } + visit::visit_expr(ex, self, vt); + } + + ast::expr_index(rcvr, _) | + ast::expr_binary(_, rcvr, _) | + ast::expr_unary(_, rcvr) | + ast::expr_assign_op(_, rcvr, _) + if self.bccx.method_map.contains_key(&ex.id) => { + // Receivers in method calls are always passed by ref. + // + // Here, in an overloaded operator, the call is this expression, + // and hence the scope of the borrow is this call. + // + // FIX? / NOT REALLY---technically we should check the other + // argument and consider the argument mode. But how annoying. + // And this problem when goes away when argument modes are + // phased out. So I elect to leave this undone. + let scope_r = ty::re_scope(ex.id); + let rcvr_cmt = self.bccx.cat_expr(rcvr); + self.guarantee_valid(rcvr.id, rcvr.span, rcvr_cmt, m_imm, scope_r); + + // FIXME (#3387): Total hack: Ignore adjustments for the left-hand + // side. Their regions will be inferred to be too large. + self.ignore_adjustments.insert(rcvr.id); + + visit::visit_expr(ex, self, vt); + } + + // FIXME--#3387 + // ast::expr_binary(_, lhs, rhs) => { + // // Universal comparison operators like ==, >=, etc + // // take their arguments by reference. + // let lhs_ty = ty::expr_ty(self.tcx(), lhs); + // if !ty::type_is_scalar(lhs_ty) { + // let scope_r = ty::re_scope(ex.id); + // let lhs_cmt = self.bccx.cat_expr(lhs); + // self.guarantee_valid(lhs_cmt, m_imm, scope_r); + // let rhs_cmt = self.bccx.cat_expr(rhs); + // self.guarantee_valid(rhs_cmt, m_imm, scope_r); + // } + // visit::visit_expr(ex, self, vt); + // } + + // see explanation attached to the `root_ub` field: + ast::expr_while(cond, ref body) => { + // during the condition, can only root for the condition + self.push_repeating_id(cond.id); + (vt.visit_expr)(cond, self, vt); + self.pop_repeating_id(cond.id); + + // during body, can only root for the body + self.push_repeating_id(body.node.id); + (vt.visit_block)(body, self, vt); + self.pop_repeating_id(body.node.id); + } + + // see explanation attached to the `root_ub` field: + ast::expr_loop(ref body, _) => { + self.push_repeating_id(body.node.id); + visit::visit_expr(ex, self, vt); + self.pop_repeating_id(body.node.id); + } + + _ => { + visit::visit_expr(ex, self, vt); + } + } +} + +pub impl GatherLoanCtxt { + fn tcx(&self) -> ty::ctxt { self.bccx.tcx } + + fn push_repeating_id(&mut self, id: ast::node_id) { + self.repeating_ids.push(id); + } + + fn pop_repeating_id(&mut self, id: ast::node_id) { + let popped = self.repeating_ids.pop(); + assert!(id == popped); + } + + fn guarantee_arguments(&mut self, + call_expr: @ast::expr, + args: &[@ast::expr], + arg_tys: &[ty::arg]) { + for vec::each2(args, arg_tys) |arg, arg_ty| { + match ty::resolved_mode(self.tcx(), arg_ty.mode) { + ast::by_ref => { + self.guarantee_by_ref_argument(call_expr, *arg); + } + ast::by_copy => {} + } + } + } + + fn guarantee_by_ref_argument(&mut self, + call_expr: @ast::expr, + arg_expr: @ast::expr) { + // FIXME(#5074) nested method calls + let scope_r = ty::re_scope(call_expr.id); + let arg_cmt = self.bccx.cat_expr(arg_expr); + self.guarantee_valid(arg_expr.id, arg_expr.span, + arg_cmt, m_imm, scope_r); + } + + fn guarantee_adjustments(&mut self, + expr: @ast::expr, + adjustment: &ty::AutoAdjustment) { + debug!("guarantee_adjustments(expr=%s, adjustment=%?)", + expr.repr(self.tcx()), adjustment); + let _i = indenter(); + + match *adjustment { + ty::AutoAddEnv(*) => { + debug!("autoaddenv -- no autoref"); + return; + } + + ty::AutoDerefRef( + ty::AutoDerefRef { + autoref: None, _ }) => { + debug!("no autoref"); + return; + } + + ty::AutoDerefRef( + ty::AutoDerefRef { + autoref: Some(ref autoref), + autoderefs: autoderefs}) => { + let mcx = &mc::mem_categorization_ctxt { + tcx: self.tcx(), + method_map: self.bccx.method_map}; + let mut cmt = mcx.cat_expr_autoderefd(expr, autoderefs); + debug!("after autoderef, cmt=%s", cmt.repr(self.tcx())); + + match *autoref { + ty::AutoPtr(r, m) => { + self.guarantee_valid(expr.id, + expr.span, + cmt, + m, + r) + } + ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => { + let cmt_index = mcx.cat_index(expr, cmt); + self.guarantee_valid(expr.id, + expr.span, + cmt_index, + m, + r) + } + ty::AutoBorrowFn(r) => { + let cmt_deref = mcx.cat_deref_fn(expr, cmt, 0); + self.guarantee_valid(expr.id, + expr.span, + cmt_deref, + m_imm, + r) + } + ty::AutoUnsafe(_) => {} + } + } + } + } + + // Guarantees that addr_of(cmt) will be valid for the duration of + // `static_scope_r`, or reports an error. This may entail taking + // out loans, which will be added to the `req_loan_map`. This can + // also entail "rooting" GC'd pointers, which means ensuring + // dynamically that they are not freed. + fn guarantee_valid(&mut self, + borrow_id: ast::node_id, + borrow_span: span, + cmt: mc::cmt, + req_mutbl: ast::mutability, + loan_region: ty::Region) + { + debug!("guarantee_valid(borrow_id=%?, cmt=%s, \ + req_mutbl=%?, loan_region=%?)", + borrow_id, + cmt.repr(self.tcx()), + req_mutbl, + loan_region); + + // a loan for the empty region can never be dereferenced, so + // it is always safe + if loan_region == ty::re_empty { + return; + } + + let root_ub = { *self.repeating_ids.last() }; // FIXME(#5074) + + // Check that the lifetime of the borrow does not exceed + // the lifetime of the data being borrowed. + lifetime::guarantee_lifetime(self.bccx, self.item_ub, root_ub, + borrow_span, cmt, loan_region, req_mutbl); + + // Check that we don't allow mutable borrows of non-mutable data. + check_mutability(self.bccx, borrow_span, cmt, req_mutbl); + + // Compute the restrictions that are required to enforce the + // loan is safe. + let restr = restrictions::compute_restrictions( + self.bccx, borrow_span, + cmt, self.restriction_set(req_mutbl)); + + // Create the loan record (if needed). + let loan = match restr { + restrictions::Safe => { + // No restrictions---no loan record necessary + return; + } + + restrictions::SafeIf(loan_path, restrictions) => { + let loan_scope = match loan_region { + ty::re_scope(id) => id, + ty::re_free(ref fr) => fr.scope_id, + + ty::re_static => { + // If we get here, an error must have been + // reported in + // `lifetime::guarantee_lifetime()`, because + // the only legal ways to have a borrow with a + // static lifetime should not require + // restrictions. To avoid reporting derived + // errors, we just return here without adding + // any loans. + return; + } + + ty::re_empty | + ty::re_bound(*) | + ty::re_infer(*) => { + self.tcx().sess.span_bug( + cmt.span, + fmt!("Invalid borrow lifetime: %?", loan_region)); + } + }; + debug!("loan_scope = %?", loan_scope); + + let gen_scope = self.compute_gen_scope(borrow_id, loan_scope); + debug!("gen_scope = %?", gen_scope); + + let kill_scope = self.compute_kill_scope(loan_scope, loan_path); + debug!("kill_scope = %?", kill_scope); + + if req_mutbl == m_mutbl { + self.mark_loan_path_as_mutated(loan_path); + } + + let all_loans = &mut *self.all_loans; // FIXME(#5074) + Loan { + index: all_loans.len(), + loan_path: loan_path, + cmt: cmt, + mutbl: req_mutbl, + gen_scope: gen_scope, + kill_scope: kill_scope, + span: borrow_span, + restrictions: restrictions + } + } + }; + + debug!("guarantee_valid(borrow_id=%?), loan=%s", + borrow_id, loan.repr(self.tcx())); + + // let loan_path = loan.loan_path; + // let loan_gen_scope = loan.gen_scope; + // let loan_kill_scope = loan.kill_scope; + self.all_loans.push(loan); + + // if loan_gen_scope != borrow_id { + // NOTE handle case where gen_scope is not borrow_id + // + // Typically, the scope of the loan includes the point at + // which the loan is originated. This + // This is a subtle case. See the test case + // + // to see what we are guarding against. + + //let restr = restrictions::compute_restrictions( + // self.bccx, borrow_span, cmt, RESTR_EMPTY); + //let loan = { + // let all_loans = &mut *self.all_loans; // FIXME(#5074) + // Loan { + // index: all_loans.len(), + // loan_path: loan_path, + // cmt: cmt, + // mutbl: m_const, + // gen_scope: borrow_id, + // kill_scope: kill_scope, + // span: borrow_span, + // restrictions: restrictions + // } + // } + + fn check_mutability(bccx: @BorrowckCtxt, + borrow_span: span, + cmt: mc::cmt, + req_mutbl: ast::mutability) { + match req_mutbl { + m_const => { + // Data of any mutability can be lent as const. + } + + m_imm => { + match cmt.mutbl { + mc::McImmutable | mc::McDeclared | mc::McInherited => { + // both imm and mut data can be lent as imm; + // for mutable data, this is a freeze + } + mc::McReadOnly => { + bccx.report(BckError {span: borrow_span, + cmt: cmt, + code: err_mutbl(req_mutbl)}); + } + } + } + + m_mutbl => { + // Only mutable data can be lent as mutable. + if !cmt.mutbl.is_mutable() { + bccx.report(BckError {span: borrow_span, + cmt: cmt, + code: err_mutbl(req_mutbl)}); + } + } + } + } + } + + fn restriction_set(&self, req_mutbl: ast::mutability) -> RestrictionSet { + match req_mutbl { + m_const => RESTR_EMPTY, + m_imm => RESTR_EMPTY | RESTR_MUTATE, + m_mutbl => RESTR_EMPTY | RESTR_MUTATE | RESTR_FREEZE + } + } + + fn mark_loan_path_as_mutated(&self, loan_path: @LoanPath) { + //! For mutable loans of content whose mutability derives + //! from a local variable, mark the mutability decl as necessary. + + match *loan_path { + LpVar(local_id) => { + self.tcx().used_mut_nodes.insert(local_id); + } + LpExtend(base, mc::McInherited, _) => { + self.mark_loan_path_as_mutated(base); + } + LpExtend(_, mc::McDeclared, _) | + LpExtend(_, mc::McImmutable, _) | + LpExtend(_, mc::McReadOnly, _) => { + } + } + } + + fn compute_gen_scope(&self, + borrow_id: ast::node_id, + loan_scope: ast::node_id) -> ast::node_id { + //! Determine when to introduce the loan. Typically the loan + //! is introduced at the point of the borrow, but in some cases, + //! notably method arguments, the loan may be introduced only + //! later, once it comes into scope. + + let rm = self.bccx.tcx.region_maps; + if rm.is_subscope_of(borrow_id, loan_scope) { + borrow_id + } else { + loan_scope + } + } + + fn compute_kill_scope(&self, + loan_scope: ast::node_id, + lp: @LoanPath) -> ast::node_id { + //! Determine when the loan restrictions go out of scope. + //! This is either when the lifetime expires or when the + //! local variable which roots the loan-path goes out of scope, + //! whichever happens faster. + //! + //! It may seem surprising that we might have a loan region + //! larger than the variable which roots the loan-path; this can + //! come about when variables of `&mut` type are re-borrowed, + //! as in this example: + //! + //! fn counter<'a>(v: &'a mut Foo) -> &'a mut uint { + //! &mut v.counter + //! } + //! + //! In this case, the borrowed pointer (`'a`) outlives the + //! variable `v` that hosts it. Note that this doesn't come up + //! with immutable `&` pointers, because borrows of such pointers + //! do not require restrictions and hence do not cause a loan. + + let rm = self.bccx.tcx.region_maps; + let lexical_scope = rm.encl_scope(lp.node_id()); + if rm.is_subscope_of(lexical_scope, loan_scope) { + lexical_scope + } else { + assert!(rm.is_subscope_of(loan_scope, lexical_scope)); + loan_scope + } + } + + fn gather_pat(&mut self, + discr_cmt: mc::cmt, + root_pat: @ast::pat, + arm_body_id: ast::node_id, + match_id: ast::node_id) { + do self.bccx.cat_pattern(discr_cmt, root_pat) |cmt, pat| { + match pat.node { + ast::pat_ident(bm, _, _) if self.pat_is_binding(pat) => { + match bm { + ast::bind_by_ref(mutbl) => { + // ref x or ref x @ p --- creates a ptr which must + // remain valid for the scope of the match + + // find the region of the resulting pointer (note that + // the type of such a pattern will *always* be a + // region pointer) + let scope_r = + ty_region(self.tcx(), pat.span, + ty::node_id_to_type(self.tcx(), pat.id)); + + // if the scope of the region ptr turns out to be + // specific to this arm, wrap the categorization + // with a cat_discr() node. There is a detailed + // discussion of the function of this node in + // `lifetime.rs`: + let arm_scope = ty::re_scope(arm_body_id); + if self.bccx.is_subregion_of(scope_r, arm_scope) { + let cmt_discr = self.bccx.cat_discr(cmt, match_id); + self.guarantee_valid(pat.id, pat.span, + cmt_discr, mutbl, scope_r); + } else { + self.guarantee_valid(pat.id, pat.span, + cmt, mutbl, scope_r); + } + } + ast::bind_by_copy | ast::bind_infer => { + // Nothing to do here; neither copies nor moves induce + // borrows. + } + } + } + + ast::pat_vec(_, Some(slice_pat), _) => { + // The `slice_pat` here creates a slice into the + // original vector. This is effectively a borrow of + // the elements of the vector being matched. + + let slice_ty = ty::node_id_to_type(self.tcx(), + slice_pat.id); + let (slice_mutbl, slice_r) = + self.vec_slice_info(slice_pat, slice_ty); + let mcx = self.bccx.mc_ctxt(); + let cmt_index = mcx.cat_index(slice_pat, cmt); + self.guarantee_valid(pat.id, pat.span, + cmt_index, slice_mutbl, slice_r); + } + + _ => {} + } + } + } + + fn vec_slice_info(&self, + pat: @ast::pat, + slice_ty: ty::t) -> (ast::mutability, ty::Region) { + /*! + * + * In a pattern like [a, b, ..c], normally `c` has slice type, + * but if you have [a, b, ..ref c], then the type of `ref c` + * will be `&&[]`, so to extract the slice details we have + * to recurse through rptrs. + */ + + match ty::get(slice_ty).sty { + ty::ty_evec(slice_mt, ty::vstore_slice(slice_r)) => { + (slice_mt.mutbl, slice_r) + } + + ty::ty_rptr(_, ref mt) => { + self.vec_slice_info(pat, mt.ty) + } + + _ => { + self.tcx().sess.span_bug( + pat.span, + fmt!("Type of slice pattern is not a slice")); + } + } + } + + fn pat_is_variant_or_struct(&self, pat: @ast::pat) -> bool { + pat_util::pat_is_variant_or_struct(self.bccx.tcx.def_map, pat) + } + + fn pat_is_binding(&self, pat: @ast::pat) -> bool { + pat_util::pat_is_binding(self.bccx.tcx.def_map, pat) + } +} + +// Setting up info that preserve needs. +// This is just the most convenient place to do it. +fn add_stmt_to_map(stmt: @ast::stmt, + self: @mut GatherLoanCtxt, + vt: visit::vt<@mut GatherLoanCtxt>) { + match stmt.node { + ast::stmt_expr(_, id) | ast::stmt_semi(_, id) => { + self.bccx.stmt_map.insert(id); + } + _ => () + } + visit::visit_stmt(stmt, self, vt); +} diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs new file mode 100644 index 0000000000000..950dbc58ec364 --- /dev/null +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -0,0 +1,251 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Computes the restrictions that result from a borrow. + +use core::prelude::*; +use middle::borrowck::*; +use mc = middle::mem_categorization; +use middle::ty; +use syntax::ast::{m_const, m_imm, m_mutbl}; +use syntax::ast; +use syntax::codemap::span; + +pub enum RestrictionResult { + Safe, + SafeIf(@LoanPath, ~[Restriction]) +} + +pub fn compute_restrictions(bccx: @BorrowckCtxt, + span: span, + cmt: mc::cmt, + restr: RestrictionSet) -> RestrictionResult { + let ctxt = RestrictionsContext { + bccx: bccx, + span: span, + cmt_original: cmt + }; + + ctxt.compute(cmt, restr) +} + +/////////////////////////////////////////////////////////////////////////// +// Private + +struct RestrictionsContext { + bccx: @BorrowckCtxt, + span: span, + cmt_original: mc::cmt +} + +impl RestrictionsContext { + fn tcx(&self) -> ty::ctxt { + self.bccx.tcx + } + + fn compute(&self, + cmt: mc::cmt, + restrictions: RestrictionSet) -> RestrictionResult { + + // Check for those cases where we cannot control the aliasing + // and make sure that we are not being asked to. + match cmt.freely_aliasable() { + None => {} + Some(cause) => { + self.check_aliasing_permitted(cause, restrictions); + } + } + + match cmt.cat { + mc::cat_rvalue => { + // Effectively, rvalues are stored into a + // non-aliasable temporary on the stack. Since they + // are inherently non-aliasable, they can only be + // accessed later through the borrow itself and hence + // must inherently comply with its terms. + Safe + } + + mc::cat_local(local_id) | + mc::cat_arg(local_id, ast::by_copy) | + mc::cat_self(local_id) => { + let lp = @LpVar(local_id); + SafeIf(lp, ~[Restriction {loan_path: lp, + set: restrictions}]) + } + + mc::cat_interior(cmt_base, i @ mc::interior_variant(_)) => { + // When we borrow the interior of an enum, we have to + // ensure the enum itself is not mutated, because that + // could cause the type of the memory to change. + let result = self.compute(cmt_base, restrictions | RESTR_MUTATE); + self.extend(result, cmt.mutbl, LpInterior(i), restrictions) + } + + mc::cat_interior(cmt_base, i @ mc::interior_tuple) | + mc::cat_interior(cmt_base, i @ mc::interior_anon_field) | + mc::cat_interior(cmt_base, i @ mc::interior_field(*)) | + mc::cat_interior(cmt_base, i @ mc::interior_index(*)) => { + // For all of these cases, overwriting the base would + // not change the type of the memory, so no additional + // restrictions are needed. + // + // FIXME(#5397) --- Mut fields are not treated soundly + // (hopefully they will just get phased out) + let result = self.compute(cmt_base, restrictions); + self.extend(result, cmt.mutbl, LpInterior(i), restrictions) + } + + mc::cat_deref(cmt_base, _, mc::uniq_ptr(*)) => { + // When we borrow the interior of an owned pointer, we + // cannot permit the base to be mutated, because that + // would cause the unique pointer to be freed. + let result = self.compute(cmt_base, restrictions | RESTR_MUTATE); + self.extend(result, cmt.mutbl, LpDeref, restrictions) + } + + mc::cat_copied_upvar(*) | // FIXME(#2152) allow mutation of upvars + mc::cat_static_item(*) | + mc::cat_implicit_self(*) | + mc::cat_arg(_, ast::by_ref) | + mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) | + mc::cat_deref(_, _, mc::gc_ptr(m_imm)) => { + Safe + } + + mc::cat_deref(_, _, mc::region_ptr(m_const, _)) | + mc::cat_deref(_, _, mc::gc_ptr(m_const)) => { + self.check_no_mutability_control(cmt, restrictions); + Safe + } + + mc::cat_deref(cmt_base, _, mc::gc_ptr(m_mutbl)) => { + // Technically, no restrictions are *necessary* here. + // The validity of the borrow is guaranteed + // dynamically. However, nonetheless we add a + // restriction to make a "best effort" to report + // static errors. For example, if there is code like + // + // let v = @mut ~[1, 2, 3]; + // for v.each |e| { + // v.push(e + 1); + // } + // + // Then the code below would add restrictions on `*v`, + // which means that an error would be reported + // here. This of course is not perfect. For example, + // a function like the following would not report an error + // at compile-time but would fail dynamically: + // + // let v = @mut ~[1, 2, 3]; + // let w = v; + // for v.each |e| { + // w.push(e + 1); + // } + // + // In addition, we only add a restriction for those cases + // where we can construct a sensible loan path, so an + // example like the following will fail dynamically: + // + // impl V { + // fn get_list(&self) -> @mut ~[int]; + // } + // ... + // let v: &V = ...; + // for v.get_list().each |e| { + // v.get_list().push(e + 1); + // } + match opt_loan_path(cmt_base) { + None => Safe, + Some(lp_base) => { + let lp = @LpExtend(lp_base, cmt.mutbl, LpDeref); + SafeIf(lp, ~[Restriction {loan_path: lp, + set: restrictions}]) + } + } + } + + mc::cat_deref(cmt_base, _, mc::region_ptr(m_mutbl, _)) => { + // Because an `&mut` pointer does not inherit its + // mutability, we can only prevent mutation or prevent + // freezing if it is not aliased. Therefore, in such + // cases we restrict aliasing on `cmt_base`. + if restrictions.intersects(RESTR_MUTATE | RESTR_FREEZE) { + let result = self.compute(cmt_base, restrictions | RESTR_ALIAS); + self.extend(result, cmt.mutbl, LpDeref, restrictions) + } else { + let result = self.compute(cmt_base, restrictions); + self.extend(result, cmt.mutbl, LpDeref, restrictions) + } + } + + mc::cat_deref(_, _, mc::unsafe_ptr) => { + // We are very trusting when working with unsafe pointers. + Safe + } + + mc::cat_stack_upvar(cmt_base) | + mc::cat_discr(cmt_base, _) => { + self.compute(cmt_base, restrictions) + } + } + } + + fn extend(&self, + result: RestrictionResult, + mc: mc::MutabilityCategory, + elem: LoanPathElem, + restrictions: RestrictionSet) -> RestrictionResult { + match result { + Safe => Safe, + SafeIf(base_lp, base_vec) => { + let lp = @LpExtend(base_lp, mc, elem); + SafeIf(lp, vec::append_one(base_vec, + Restriction {loan_path: lp, + set: restrictions})) + } + } + } + + fn check_aliasing_permitted(&self, + cause: mc::AliasableReason, + restrictions: RestrictionSet) { + //! This method is invoked when the current `cmt` is something + //! where aliasing cannot be controlled. It reports an error if + //! the restrictions required that it not be aliased; currently + //! this only occurs when re-borrowing an `&mut` pointer. + //! + //! NB: To be 100% consistent, we should report an error if + //! RESTR_FREEZE is found, because we cannot prevent freezing, + //! nor would we want to. However, we do not report such an + //! error, because this restriction only occurs when the user + //! is creating an `&mut` pointer to immutable or read-only + //! data, and there is already another piece of code that + //! checks for this condition. + + if restrictions.intersects(RESTR_ALIAS) { + self.bccx.report_aliasability_violation( + self.span, + BorrowViolation, + cause); + } + } + + fn check_no_mutability_control(&self, + cmt: mc::cmt, + restrictions: RestrictionSet) { + if restrictions.intersects(RESTR_MUTATE | RESTR_FREEZE) { + self.bccx.report(BckError {span: self.span, + cmt: cmt, + code: err_freeze_aliasable_const}); + } + } +} + diff --git a/src/librustc/middle/borrowck/loan.rs b/src/librustc/middle/borrowck/loan.rs deleted file mode 100644 index 21de29b8f60ad..0000000000000 --- a/src/librustc/middle/borrowck/loan.rs +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -The `Loan` module deals with borrows of *uniquely mutable* data. We -say that data is uniquely mutable if the current activation (stack -frame) controls the only mutable reference to the data. The most -common way that this can occur is if the current activation owns the -data being borrowed, but it can also occur with `&mut` pointers. The -primary characteristic of uniquely mutable data is that, at any given -time, there is at most one path that can be used to mutate it, and -that path is only accessible from the top stack frame. - -Given that some data found at a path P is being borrowed to a borrowed -pointer with mutability M and lifetime L, the job of the code in this -module is to compute the set of *loans* that are necessary to ensure -that (1) the data found at P outlives L and that (2) if M is mutable -then the path P will not be modified directly or indirectly except -through that pointer. A *loan* is the combination of a path P_L, a -mutability M_L, and a lifetime L_L where: - -- The path P_L indicates what data has been lent. -- The mutability M_L indicates the access rights on the data: - - const: the data cannot be moved - - immutable/mutable: the data cannot be moved or mutated -- The lifetime L_L indicates the *scope* of the loan. - -FIXME #4730 --- much more needed, don't have time to write this all up now - -*/ - -// ---------------------------------------------------------------------- -// Loan(Ex, M, S) = Ls holds if ToAddr(Ex) will remain valid for the entirety -// of the scope S, presuming that the returned set of loans `Ls` are honored. - -use middle::borrowck::{Loan, bckerr, bckres, BorrowckCtxt, err_mutbl}; -use middle::borrowck::{LoanKind, TotalFreeze, PartialFreeze, - TotalTake, PartialTake, Immobile}; -use middle::borrowck::{err_out_of_scope}; -use middle::mem_categorization::{cat_arg, cat_binding, cat_discr, cat_comp}; -use middle::mem_categorization::{cat_deref, cat_discr, cat_local, cat_self}; -use middle::mem_categorization::{cat_special, cat_stack_upvar, cmt}; -use middle::mem_categorization::{comp_field, comp_index, comp_variant}; -use middle::mem_categorization::{gc_ptr, region_ptr}; -use middle::ty; -use util::common::indenter; - -use syntax::ast::m_imm; -use syntax::ast; - -pub fn loan(bccx: @BorrowckCtxt, - cmt: cmt, - scope_region: ty::Region, - loan_kind: LoanKind) -> bckres<~[Loan]> -{ - let mut lc = LoanContext { - bccx: bccx, - scope_region: scope_region, - loans: ~[] - }; - match lc.loan(cmt, loan_kind, true) { - Err(ref e) => return Err((*e)), - Ok(()) => {} - } - // FIXME #4945: Workaround for borrow check bug. - Ok(copy lc.loans) -} - -struct LoanContext { - bccx: @BorrowckCtxt, - - // the region scope for which we must preserve the memory - scope_region: ty::Region, - - // accumulated list of loans that will be required - loans: ~[Loan] -} - -pub impl LoanContext { - fn tcx(&self) -> ty::ctxt { self.bccx.tcx } - - fn loan(&mut self, - cmt: cmt, - loan_kind: LoanKind, - owns_lent_data: bool) -> bckres<()> - { - /*! - * - * The main routine. - * - * # Parameters - * - * - `cmt`: the categorization of the data being borrowed - * - `req_mutbl`: the mutability of the borrowed pointer - * that was created - * - `owns_lent_data`: indicates whether `cmt` owns the - * data that is being lent. See - * discussion in `issue_loan()`. - */ - - debug!("loan(%s, %?)", - self.bccx.cmt_to_repr(cmt), - loan_kind); - let _i = indenter(); - - // see stable() above; should only be called when `cmt` is lendable - if cmt.lp.is_none() { - self.bccx.tcx.sess.span_bug( - cmt.span, - ~"loan() called with non-lendable value"); - } - - match cmt.cat { - cat_binding(_) | cat_rvalue | cat_special(_) => { - // should never be loanable - self.bccx.tcx.sess.span_bug( - cmt.span, - ~"rvalue with a non-none lp"); - } - cat_local(local_id) | cat_arg(local_id) | cat_self(local_id) => { - // FIXME(#4903) - let local_region = self.bccx.tcx.region_maps.encl_region(local_id); - self.issue_loan(cmt, local_region, loan_kind, - owns_lent_data) - } - cat_stack_upvar(cmt) => { - self.loan(cmt, loan_kind, owns_lent_data) - } - cat_discr(base, _) => { - self.loan(base, loan_kind, owns_lent_data) - } - cat_comp(cmt_base, comp_field(_, m)) | - cat_comp(cmt_base, comp_index(_, m)) => { - // For most components, the type of the embedded data is - // stable. Therefore, the base structure need only be - // const---unless the component must be immutable. In - // that case, it must also be embedded in an immutable - // location, or else the whole structure could be - // overwritten and the component along with it. - self.loan_stable_comp(cmt, cmt_base, loan_kind, m, - owns_lent_data) - } - cat_comp(cmt_base, comp_tuple) | - cat_comp(cmt_base, comp_anon_field) => { - // As above. - self.loan_stable_comp(cmt, cmt_base, loan_kind, m_imm, - owns_lent_data) - } - cat_comp(cmt_base, comp_variant(enum_did)) => { - // For enums, the memory is unstable if there are multiple - // variants, because if the enum value is overwritten then - // the memory changes type. - if ty::enum_is_univariant(self.bccx.tcx, enum_did) { - self.loan_stable_comp(cmt, cmt_base, loan_kind, m_imm, - owns_lent_data) - } else { - self.loan_unstable_deref(cmt, cmt_base, loan_kind, - owns_lent_data) - } - } - cat_deref(cmt_base, _, uniq_ptr) => { - // For unique pointers, the memory being pointed out is - // unstable because if the unique pointer is overwritten - // then the memory is freed. - self.loan_unstable_deref(cmt, cmt_base, loan_kind, - owns_lent_data) - } - cat_deref(cmt_base, _, region_ptr(ast::m_mutbl, region)) => { - // Mutable data can be loaned out as immutable or const. We must - // loan out the base as well as the main memory. For example, - // if someone borrows `*b`, we want to borrow `b` as immutable - // as well. - do self.loan(cmt_base, TotalFreeze, false).chain |_| { - self.issue_loan(cmt, region, loan_kind, owns_lent_data) - } - } - cat_deref(_, _, unsafe_ptr) | - cat_deref(_, _, gc_ptr(_)) | - cat_deref(_, _, region_ptr(_, _)) => { - // Aliased data is simply not lendable. - self.bccx.tcx.sess.span_bug( - cmt.span, - ~"aliased ptr with a non-none lp"); - } - } - } - - // A "stable component" is one where assigning the base of the - // component cannot cause the component itself to change types. - // Example: record fields. - fn loan_stable_comp(&mut self, - cmt: cmt, - cmt_base: cmt, - loan_kind: LoanKind, - comp_mutbl: ast::mutability, - owns_lent_data: bool) -> bckres<()> - { - let base_kind = match (comp_mutbl, loan_kind) { - // Declared as "immutable" means: inherited mutability and - // hence mutable iff parent is mutable. So propagate - // mutability on up. - (m_imm, TotalFreeze) | (m_imm, PartialFreeze) => PartialFreeze, - (m_imm, TotalTake) | (m_imm, PartialTake) => PartialTake, - - // Declared as "mutable" means: always mutable no matter - // what the mutability of the base is. So that means we - // can weaken the condition on the base to PartialFreeze. - // This implies that the user could freeze the base, but - // that is ok since the even with an &T base, the mut - // field will still be considered mutable. - (_, TotalTake) | (_, PartialTake) | - (_, TotalFreeze) | (_, PartialFreeze) => { - PartialFreeze - } - - // If we just need to guarantee the value won't be moved, - // it doesn't matter what mutability the component was - // declared with. - (_, Immobile) => Immobile, - }; - - do self.loan(cmt_base, base_kind, owns_lent_data).chain |_ok| { - // can use static for the scope because the base - // determines the lifetime, ultimately - self.issue_loan(cmt, ty::re_static, loan_kind, - owns_lent_data) - } - } - - // An "unstable deref" means a deref of a ptr/comp where, if the - // base of the deref is assigned to, pointers into the result of the - // deref would be invalidated. Examples: interior of variants, uniques. - fn loan_unstable_deref(&mut self, - cmt: cmt, - cmt_base: cmt, - loan_kind: LoanKind, - owns_lent_data: bool) -> bckres<()> { - // Variant components: the base must be immutable, because - // if it is overwritten, the types of the embedded data - // could change. - do self.loan(cmt_base, PartialFreeze, owns_lent_data).chain |_| { - // can use static, as in loan_stable_comp() - self.issue_loan(cmt, ty::re_static, loan_kind, - owns_lent_data) - } - } - - fn issue_loan(&mut self, - cmt: cmt, - scope_ub: ty::Region, - loan_kind: LoanKind, - owns_lent_data: bool) -> bckres<()> { - // Subtle: the `scope_ub` is the maximal lifetime of `cmt`. - // Therefore, if `cmt` owns the data being lent, then the - // scope of the loan must be less than `scope_ub`, or else the - // data would be freed while the loan is active. - // - // However, if `cmt` does *not* own the data being lent, then - // it is ok if `cmt` goes out of scope during the loan. This - // can occur when you have an `&mut` parameter that is being - // reborrowed. - - if !owns_lent_data || - self.bccx.is_subregion_of(self.scope_region, scope_ub) - { - if cmt.mutbl.is_mutable() { - // If this loan is a mutable loan, then mark the loan path (if - // it exists) as being used. This is similar to the check - // performed in check_loans.rs in check_assignment(), but this - // is for a different purpose of having the 'mut' qualifier. - for cmt.lp.each |lp| { - for lp.node_id().each |&id| { - self.tcx().used_mut_nodes.insert(id); - } - } - } else if loan_kind.is_take() { - // We do not allow non-mutable data to be "taken" - // under any circumstances. - return Err(bckerr { - cmt:cmt, - code:err_mutbl(loan_kind) - }); - } - - self.loans.push(Loan { - // Note: cmt.lp must be Some(_) because otherwise this - // loan process does not apply at all. - lp: cmt.lp.get(), - cmt: cmt, - kind: loan_kind - }); - - return Ok(()); - } else { - // The loan being requested lives longer than the data - // being loaned out! - return Err(bckerr { - cmt:cmt, - code:err_out_of_scope(scope_ub, self.scope_region) - }); - } - } -} - diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 3746f9c6e60b1..c108b020378eb 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -8,254 +8,64 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! -# Borrow check - -This pass is in job of enforcing *memory safety* and *purity*. As -memory safety is by far the more complex topic, I'll focus on that in -this description, but purity will be covered later on. In the context -of Rust, memory safety means three basic things: - -- no writes to immutable memory; -- all pointers point to non-freed memory; -- all pointers point to memory of the same type as the pointer. - -The last point might seem confusing: after all, for the most part, -this condition is guaranteed by the type check. However, there are -two cases where the type check effectively delegates to borrow check. - -The first case has to do with enums. If there is a pointer to the -interior of an enum, and the enum is in a mutable location (such as a -local variable or field declared to be mutable), it is possible that -the user will overwrite the enum with a new value of a different -variant, and thus effectively change the type of the memory that the -pointer is pointing at. +/*! See doc.rs for a thorough explanation of the borrow checker */ -The second case has to do with mutability. Basically, the type -checker has only a limited understanding of mutability. It will allow -(for example) the user to get an immutable pointer with the address of -a mutable local variable. It will also allow a `@mut T` or `~mut T` -pointer to be borrowed as a `&r.T` pointer. These seeming oversights -are in fact intentional; they allow the user to temporarily treat a -mutable value as immutable. It is up to the borrow check to guarantee -that the value in question is not in fact mutated during the lifetime -`r` of the reference. +use core; +use core::prelude::*; -# Definition of unstable memory - -The primary danger to safety arises due to *unstable memory*. -Unstable memory is memory whose validity or type may change as a -result of an assignment, move, or a variable going out of scope. -There are two cases in Rust where memory is unstable: the contents of -unique boxes and enums. - -Unique boxes are unstable because when the variable containing the -unique box is re-assigned, moves, or goes out of scope, the unique box -is freed or---in the case of a move---potentially given to another -task. In either case, if there is an extant and usable pointer into -the box, then safety guarantees would be compromised. - -Enum values are unstable because they are reassigned the types of -their contents may change if they are assigned with a different -variant than they had previously. - -# Safety criteria that must be enforced - -Whenever a piece of memory is borrowed for lifetime L, there are two -things which the borrow checker must guarantee. First, it must -guarantee that the memory address will remain allocated (and owned by -the current task) for the entirety of the lifetime L. Second, it must -guarantee that the type of the data will not change for the entirety -of the lifetime L. In exchange, the region-based type system will -guarantee that the pointer is not used outside the lifetime L. These -guarantees are to some extent independent but are also inter-related. - -In some cases, the type of a pointer cannot be invalidated but the -lifetime can. For example, imagine a pointer to the interior of -a shared box like: - - let mut x = @mut {f: 5, g: 6}; - let y = &mut x.f; - -Here, a pointer was created to the interior of a shared box which -contains a record. Even if `*x` were to be mutated like so: - - *x = {f: 6, g: 7}; - -This would cause `*y` to change from 5 to 6, but the pointer pointer -`y` remains valid. It still points at an integer even if that integer -has been overwritten. - -However, if we were to reassign `x` itself, like so: - - x = @{f: 6, g: 7}; - -This could potentially invalidate `y`, because if `x` were the final -reference to the shared box, then that memory would be released and -now `y` points at freed memory. (We will see that to prevent this -scenario we will *root* shared boxes that reside in mutable memory -whose contents are borrowed; rooting means that we create a temporary -to ensure that the box is not collected). - -In other cases, like an enum on the stack, the memory cannot be freed -but its type can change: - - let mut x = Some(5); - match x { - Some(ref y) => { ... } - None => { ... } - } - -Here as before, the pointer `y` would be invalidated if we were to -reassign `x` to `none`. (We will see that this case is prevented -because borrowck tracks data which resides on the stack and prevents -variables from reassigned if there may be pointers to their interior) - -Finally, in some cases, both dangers can arise. For example, something -like the following: - - let mut x = ~Some(5); - match x { - ~Some(ref y) => { ... } - ~None => { ... } - } - -In this case, if `x` to be reassigned or `*x` were to be mutated, then -the pointer `y` would be invalided. (This case is also prevented by -borrowck tracking data which is owned by the current stack frame) - -# Summary of the safety check - -In order to enforce mutability, the borrow check has a few tricks up -its sleeve: - -- When data is owned by the current stack frame, we can identify every - possible assignment to a local variable and simply prevent - potentially dangerous assignments directly. - -- If data is owned by a shared box, we can root the box to increase - its lifetime. - -- If data is found within a borrowed pointer, we can assume that the - data will remain live for the entirety of the borrowed pointer. - -- We can rely on the fact that pure actions (such as calling pure - functions) do not mutate data which is not owned by the current - stack frame. - -# Possible future directions - -There are numerous ways that the `borrowck` could be strengthened, but -these are the two most likely: - -- flow-sensitivity: we do not currently consider flow at all but only - block-scoping. This means that innocent code like the following is - rejected: - - let mut x: int; - ... - x = 5; - let y: &int = &x; // immutable ptr created - ... - - The reason is that the scope of the pointer `y` is the entire - enclosing block, and the assignment `x = 5` occurs within that - block. The analysis is not smart enough to see that `x = 5` always - happens before the immutable pointer is created. This is relatively - easy to fix and will surely be fixed at some point. - -- finer-grained purity checks: currently, our fallback for - guaranteeing random references into mutable, aliasable memory is to - require *total purity*. This is rather strong. We could use local - type-based alias analysis to distinguish writes that could not - possibly invalid the references which must be guaranteed. This - would only work within the function boundaries; function calls would - still require total purity. This seems less likely to be - implemented in the short term as it would make the code - significantly more complex; there is currently no code to analyze - the types and determine the possible impacts of a write. - -# How the code works - -The borrow check code is divided into several major modules, each of -which is documented in its own file. - -The `gather_loans` and `check_loans` are the two major passes of the -analysis. The `gather_loans` pass runs over the IR once to determine -what memory must remain valid and for how long. Its name is a bit of -a misnomer; it does in fact gather up the set of loans which are -granted, but it also determines when @T pointers must be rooted and -for which scopes purity must be required. - -The `check_loans` pass walks the IR and examines the loans and purity -requirements computed in `gather_loans`. It checks to ensure that (a) -the conditions of all loans are honored; (b) no contradictory loans -were granted (for example, loaning out the same memory as mutable and -immutable simultaneously); and (c) any purity requirements are -honored. - -The remaining modules are helper modules used by `gather_loans` and -`check_loans`: - -- `categorization` has the job of analyzing an expression to determine - what kind of memory is used in evaluating it (for example, where - dereferences occur and what kind of pointer is dereferenced; whether - the memory is mutable; etc) -- `loan` determines when data uniquely tied to the stack frame can be - loaned out. -- `preserve` determines what actions (if any) must be taken to preserve - aliasable data. This is the code which decides when to root - an @T pointer or to require purity. - -# Maps that are created - -Borrowck results in two maps. - -- `root_map`: identifies those expressions or patterns whose result - needs to be rooted. Conceptually the root_map maps from an - expression or pattern node to a `node_id` identifying the scope for - which the expression must be rooted (this `node_id` should identify - a block or call). The actual key to the map is not an expression id, - however, but a `root_map_key`, which combines an expression id with a - deref count and is used to cope with auto-deref. - -- `mutbl_map`: identifies those local variables which are modified or - moved. This is used by trans to guarantee that such variables are - given a memory location and not used as immediates. - */ - -use middle::mem_categorization::*; +use mc = middle::mem_categorization; use middle::ty; use middle::typeck; use middle::moves; +use middle::dataflow::DataFlowContext; +use middle::dataflow::DataFlowOperator; use util::common::stmt_set; -use util::ppaux::note_and_explain_region; +use util::ppaux::{note_and_explain_region, Repr}; use core::hashmap::{HashSet, HashMap}; -use core::to_bytes; -use syntax::ast::{mutability, m_imm}; +use core::io; +use core::result::{Result}; +use core::ops::{BitOr, BitAnd}; use syntax::ast; +use syntax::ast_map; +use syntax::visit; use syntax::codemap::span; +macro_rules! if_ok( + ($inp: expr) => ( + match $inp { + Ok(v) => { v } + Err(e) => { return Err(e); } + } + ) +) + +pub mod doc; + pub mod check_loans; + +#[path="gather_loans/mod.rs"] pub mod gather_loans; -pub mod loan; -pub mod preserve; + +pub struct LoanDataFlowOperator; +pub type LoanDataFlow = DataFlowContext; pub fn check_crate( tcx: ty::ctxt, method_map: typeck::method_map, moves_map: moves::MovesMap, + moved_variables_set: moves::MovedVariablesSet, capture_map: moves::CaptureMap, - crate: @ast::crate) -> (root_map, mutbl_map, write_guard_map) + crate: @ast::crate) -> (root_map, write_guard_map) { let bccx = @BorrowckCtxt { tcx: tcx, method_map: method_map, moves_map: moves_map, + moved_variables_set: moved_variables_set, capture_map: capture_map, root_map: root_map(), - mutbl_map: @mut HashSet::new(), + loan_map: @mut HashMap::new(), write_guard_map: @mut HashSet::new(), stmt_map: @mut HashSet::new(), stats: @mut BorrowStats { @@ -267,8 +77,9 @@ pub fn check_crate( } }; - let req_maps = gather_loans::gather_loans(bccx, crate); - check_loans::check_loans(bccx, req_maps, crate); + let v = visit::mk_vt(@visit::Visitor {visit_fn: borrowck_fn, + ..*visit::default_visitor()}); + visit::visit_crate(crate, bccx, v); if tcx.sess.borrowck_stats() { io::println(~"--- borrowck stats ---"); @@ -284,7 +95,7 @@ pub fn check_crate( make_stat(bccx, bccx.stats.req_pure_paths))); } - return (bccx.root_map, bccx.mutbl_map, bccx.write_guard_map); + return (bccx.root_map, bccx.write_guard_map); fn make_stat(bccx: &BorrowckCtxt, stat: uint) -> ~str { let stat_f = stat as float; @@ -293,6 +104,46 @@ pub fn check_crate( } } +fn borrowck_fn(fk: &visit::fn_kind, + decl: &ast::fn_decl, + body: &ast::blk, + sp: span, + id: ast::node_id, + self: @BorrowckCtxt, + v: visit::vt<@BorrowckCtxt>) { + match fk { + &visit::fk_anon(*) | + &visit::fk_fn_block(*) => { + // Closures are checked as part of their containing fn item. + } + + &visit::fk_item_fn(*) | + &visit::fk_method(*) | + &visit::fk_dtor(*) => { + debug!("borrowck_fn(id=%?)", id); + + // Check the body of fn items. + let (id_range, all_loans) = + gather_loans::gather_loans(self, body); + let all_loans: &~[Loan] = &*all_loans; // FIXME(#5074) + let mut dfcx = + DataFlowContext::new(self.tcx, + self.method_map, + LoanDataFlowOperator, + id_range, + all_loans.len()); + for all_loans.eachi |loan_idx, loan| { + dfcx.add_gen(loan.gen_scope, loan_idx); + dfcx.add_kill(loan.kill_scope, loan_idx); + } + dfcx.propagate(body); + check_loans::check_loans(self, &dfcx, *all_loans, body); + } + } + + visit::visit_fn(fk, decl, body, sp, id, self, v); +} + // ---------------------------------------------------------------------- // Type definitions @@ -300,9 +151,10 @@ pub struct BorrowckCtxt { tcx: ty::ctxt, method_map: typeck::method_map, moves_map: moves::MovesMap, + moved_variables_set: moves::MovedVariablesSet, capture_map: moves::CaptureMap, root_map: root_map, - mutbl_map: mutbl_map, + loan_map: LoanMap, write_guard_map: write_guard_map, stmt_map: stmt_set, @@ -318,137 +170,228 @@ pub struct BorrowStats { guaranteed_paths: uint } -pub struct RootInfo { - scope: ast::node_id, - // This will be true if we need to freeze this box at runtime. This will - // result in a call to `borrow_as_imm()` and `return_to_mut()`. - freezes: bool // True if we need to freeze this box at runtime. -} - -// a map mapping id's of expressions of gc'd type (@T, @[], etc) where -// the box needs to be kept live to the id of the scope for which they -// must stay live. -pub type root_map = @mut HashMap; +pub type LoanMap = @mut HashMap; // the keys to the root map combine the `id` of the expression with -// the number of types that it is autodereferenced. So, for example, +// the number of types that it is autodereferenced. So, for example, // if you have an expression `x.f` and x has type ~@T, we could add an // entry {id:x, derefs:0} to refer to `x` itself, `{id:x, derefs:1}` // to refer to the deref of the unique pointer, and so on. -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] pub struct root_map_key { id: ast::node_id, derefs: uint } -// set of ids of local vars / formal arguments that are modified / moved. -// this is used in trans for optimization purposes. -pub type mutbl_map = @mut HashSet; - // A set containing IDs of expressions of gc'd type that need to have a write // guard. pub type write_guard_map = @mut HashSet; -// Errors that can occur -#[deriving(Eq)] -pub enum bckerr_code { - err_mut_uniq, - err_mut_variant, - err_root_not_permitted, - err_mutbl(LoanKind), - err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope - err_out_of_scope(ty::Region, ty::Region) // superscope, subscope -} +pub type BckResult = Result; -// Combination of an error code and the categorization of the expression -// that caused it #[deriving(Eq)] -pub struct bckerr { - cmt: cmt, - code: bckerr_code +pub enum PartialTotal { + Partial, // Loan affects some portion + Total // Loan affects entire path } -pub enum MoveError { - MoveOk, - MoveFromIllegalCmt(cmt), - MoveWhileBorrowed(/*move*/ cmt, /*loan*/ cmt) +/////////////////////////////////////////////////////////////////////////// +// Loans and loan paths + +/// Record of a loan that was issued. +pub struct Loan { + index: uint, + loan_path: @LoanPath, + cmt: mc::cmt, + mutbl: ast::mutability, + restrictions: ~[Restriction], + gen_scope: ast::node_id, + kill_scope: ast::node_id, + span: span, } -// shorthand for something that fails with `bckerr` or succeeds with `T` -pub type bckres = Result; +#[deriving(Eq)] +pub enum LoanPath { + LpVar(ast::node_id), // `x` in doc.rs + LpExtend(@LoanPath, mc::MutabilityCategory, LoanPathElem) +} #[deriving(Eq)] -pub enum LoanKind { - TotalFreeze, // Entire path is frozen (borrowed as &T) - PartialFreeze, // Some subpath is frozen (borrowed as &T) - TotalTake, // Entire path is "taken" (borrowed as &mut T) - PartialTake, // Some subpath is "taken" (borrowed as &mut T) - Immobile // Path cannot be moved (borrowed as &const T) +pub enum LoanPathElem { + LpDeref, // `*LV` in doc.rs + LpInterior(mc::interior_kind) // `LV.f` in doc.rs } -/// a complete record of a loan that was granted -pub struct Loan { - lp: @loan_path, - cmt: cmt, - kind: LoanKind +pub impl LoanPath { + fn node_id(&self) -> ast::node_id { + match *self { + LpVar(local_id) => local_id, + LpExtend(base, _, _) => base.node_id() + } + } } -/// maps computed by `gather_loans` that are then used by `check_loans` -/// -/// - `req_loan_map`: map from each block/expr to the required loans needed -/// for the duration of that block/expr -/// - `pure_map`: map from block/expr that must be pure to the error message -/// that should be reported if they are not pure -pub struct ReqMaps { - req_loan_map: HashMap, - pure_map: HashMap +pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> { + //! Computes the `LoanPath` (if any) for a `cmt`. + //! Note that this logic is somewhat duplicated in + //! the method `compute()` found in `gather_loans::restrictions`, + //! which allows it to share common loan path pieces as it + //! traverses the CMT. + + match cmt.cat { + mc::cat_rvalue | + mc::cat_static_item | + mc::cat_copied_upvar(_) | + mc::cat_implicit_self | + mc::cat_arg(_, ast::by_ref) => { + None + } + + mc::cat_local(id) | + mc::cat_arg(id, ast::by_copy) | + mc::cat_self(id) => { + Some(@LpVar(id)) + } + + mc::cat_deref(cmt_base, _, _) => { + opt_loan_path(cmt_base).map( + |&lp| @LpExtend(lp, cmt.mutbl, LpDeref)) + } + + mc::cat_interior(cmt_base, ik) => { + opt_loan_path(cmt_base).map( + |&lp| @LpExtend(lp, cmt.mutbl, LpInterior(ik))) + } + + mc::cat_stack_upvar(cmt_base) | + mc::cat_discr(cmt_base, _) => { + opt_loan_path(cmt_base) + } + } } -pub fn save_and_restore(save_and_restore_t: &mut T, - f: &fn() -> U) -> U { - let old_save_and_restore_t = *save_and_restore_t; - let u = f(); - *save_and_restore_t = old_save_and_restore_t; - u +/////////////////////////////////////////////////////////////////////////// +// Restrictions +// +// Borrowing an lvalue often results in *restrictions* that limit what +// can be done with this lvalue during the scope of the loan: +// +// - `RESTR_MUTATE`: The lvalue may not be modified and mutable pointers to +// the value cannot be created. +// - `RESTR_FREEZE`: Immutable pointers to the value cannot be created. +// - `RESTR_ALIAS`: The lvalue may not be aliased in any way. +// +// In addition, no value which is restricted may be moved. Therefore, +// restrictions are meaningful even if the RestrictionSet is empty, +// because the restriction against moves is implied. + +pub struct Restriction { + loan_path: @LoanPath, + set: RestrictionSet } -pub fn save_and_restore_managed(save_and_restore_t: @mut T, - f: &fn() -> U) -> U { - let old_save_and_restore_t = *save_and_restore_t; - let u = f(); - *save_and_restore_t = old_save_and_restore_t; - u +pub struct RestrictionSet { + bits: u32 } -pub impl LoanKind { - fn is_freeze(&self) -> bool { - match *self { - TotalFreeze | PartialFreeze => true, - _ => false - } +pub static RESTR_EMPTY: RestrictionSet = RestrictionSet {bits: 0b000}; +pub static RESTR_MUTATE: RestrictionSet = RestrictionSet {bits: 0b001}; +pub static RESTR_FREEZE: RestrictionSet = RestrictionSet {bits: 0b010}; +pub static RESTR_ALIAS: RestrictionSet = RestrictionSet {bits: 0b100}; + +pub impl RestrictionSet { + fn intersects(&self, restr: RestrictionSet) -> bool { + (self.bits & restr.bits) != 0 } - fn is_take(&self) -> bool { - match *self { - TotalTake | PartialTake => true, - _ => false - } + fn contains_all(&self, restr: RestrictionSet) -> bool { + (self.bits & restr.bits) == restr.bits } } -/// Creates and returns a new root_map +impl BitOr for RestrictionSet { + fn bitor(&self, rhs: &RestrictionSet) -> RestrictionSet { + RestrictionSet {bits: self.bits | rhs.bits} + } +} -impl to_bytes::IterBytes for root_map_key { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { - to_bytes::iter_bytes_2(&self.id, &self.derefs, lsb0, f); +impl BitAnd for RestrictionSet { + fn bitand(&self, rhs: &RestrictionSet) -> RestrictionSet { + RestrictionSet {bits: self.bits & rhs.bits} } } +/////////////////////////////////////////////////////////////////////////// +// Rooting of managed boxes +// +// When we borrow the interior of a managed box, it is sometimes +// necessary to *root* the box, meaning to stash a copy of the box +// somewhere that the garbage collector will find it. This ensures +// that the box is not collected for the lifetime of the borrow. +// +// As part of this rooting, we sometimes also freeze the box at +// runtime, meaning that we dynamically detect when the box is +// borrowed in incompatible ways. +// +// Both of these actions are driven through the `root_map`, which maps +// from a node to the dynamic rooting action that should be taken when +// that node executes. The node is identified through a +// `root_map_key`, which pairs a node-id and a deref count---the +// problem is that sometimes the box that needs to be rooted is only +// uncovered after a certain number of auto-derefs. + +pub struct RootInfo { + scope: ast::node_id, + freeze: Option // Some() if we should freeze box at runtime +} + +pub type root_map = @mut HashMap; + pub fn root_map() -> root_map { return @mut HashMap::new(); } -// ___________________________________________________________________________ +pub enum DynaFreezeKind { + DynaImm, + DynaMut +} + +impl ToStr for DynaFreezeKind { + fn to_str(&self) -> ~str { + match *self { + DynaMut => ~"mutable", + DynaImm => ~"immutable" + } + } +} + +/////////////////////////////////////////////////////////////////////////// +// Errors + +// Errors that can occur +#[deriving(Eq)] +pub enum bckerr_code { + err_mutbl(ast::mutability), + err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope + err_out_of_scope(ty::Region, ty::Region), // superscope, subscope + err_freeze_aliasable_const +} + +// Combination of an error code and the categorization of the expression +// that caused it +#[deriving(Eq)] +pub struct BckError { + span: span, + cmt: mc::cmt, + code: bckerr_code +} + +pub enum AliasableViolationKind { + MutabilityViolation, + BorrowViolation +} + +/////////////////////////////////////////////////////////////////////////// // Misc pub impl BorrowckCtxt { @@ -456,27 +399,31 @@ pub impl BorrowckCtxt { self.tcx.region_maps.is_subregion_of(r_sub, r_sup) } - fn cat_expr(&self, expr: @ast::expr) -> cmt { - cat_expr(self.tcx, self.method_map, expr) + fn is_subscope_of(&self, r_sub: ast::node_id, r_sup: ast::node_id) -> bool { + self.tcx.region_maps.is_subscope_of(r_sub, r_sup) + } + + fn cat_expr(&self, expr: @ast::expr) -> mc::cmt { + mc::cat_expr(self.tcx, self.method_map, expr) } - fn cat_expr_unadjusted(&self, expr: @ast::expr) -> cmt { - cat_expr_unadjusted(self.tcx, self.method_map, expr) + fn cat_expr_unadjusted(&self, expr: @ast::expr) -> mc::cmt { + mc::cat_expr_unadjusted(self.tcx, self.method_map, expr) } fn cat_expr_autoderefd(&self, expr: @ast::expr, - adj: @ty::AutoAdjustment) -> cmt { + adj: @ty::AutoAdjustment) -> mc::cmt { match *adj { ty::AutoAddEnv(*) => { // no autoderefs - cat_expr_unadjusted(self.tcx, self.method_map, expr) + mc::cat_expr_unadjusted(self.tcx, self.method_map, expr) } ty::AutoDerefRef( ty::AutoDerefRef { autoderefs: autoderefs, _}) => { - cat_expr_autoderefd(self.tcx, self.method_map, expr, - autoderefs) + mc::cat_expr_autoderefd(self.tcx, self.method_map, expr, + autoderefs) } } } @@ -485,43 +432,33 @@ pub impl BorrowckCtxt { id: ast::node_id, span: span, ty: ty::t, - def: ast::def) -> cmt { - cat_def(self.tcx, self.method_map, id, span, ty, def) - } - - fn cat_variant(&self, - arg: N, - enum_did: ast::def_id, - cmt: cmt) -> cmt { - cat_variant(self.tcx, self.method_map, arg, enum_did, cmt) + def: ast::def) -> mc::cmt { + mc::cat_def(self.tcx, self.method_map, id, span, ty, def) } - fn cat_discr(&self, cmt: cmt, match_id: ast::node_id) -> cmt { - return @cmt_ {cat:cat_discr(cmt, match_id),.. *cmt}; + fn cat_discr(&self, cmt: mc::cmt, match_id: ast::node_id) -> mc::cmt { + @mc::cmt_ {cat:mc::cat_discr(cmt, match_id), + mutbl:cmt.mutbl.inherit(), + ..*cmt} } - fn mc_ctxt(&self) -> mem_categorization_ctxt { - mem_categorization_ctxt {tcx: self.tcx, + fn mc_ctxt(&self) -> mc::mem_categorization_ctxt { + mc::mem_categorization_ctxt {tcx: self.tcx, method_map: self.method_map} } - fn cat_pattern(&self, cmt: cmt, pat: @ast::pat, op: &fn(cmt, @ast::pat)) { + fn cat_pattern(&self, + cmt: mc::cmt, + pat: @ast::pat, + op: &fn(mc::cmt, @ast::pat)) { let mc = self.mc_ctxt(); mc.cat_pattern(cmt, pat, op); } - fn report_if_err(&self, bres: bckres<()>) { - match bres { - Ok(()) => (), - Err(ref e) => self.report((*e)) - } - } - - fn report(&self, err: bckerr) { + fn report(&self, err: BckError) { self.span_err( - err.cmt.span, - fmt!("illegal borrow: %s", - self.bckerr_to_str(err))); + err.span, + self.bckerr_to_str(err)); self.note_and_explain_bckerr(err); } @@ -533,51 +470,75 @@ pub impl BorrowckCtxt { self.tcx.sess.span_note(s, m); } - fn add_to_mutbl_map(&self, cmt: cmt) { - match cmt.cat { - cat_local(id) | cat_arg(id) => { - self.mutbl_map.insert(id); - } - cat_stack_upvar(cmt) => { - self.add_to_mutbl_map(cmt); - } - _ => () - } - } - - fn bckerr_to_str(&self, err: bckerr) -> ~str { + fn bckerr_to_str(&self, err: BckError) -> ~str { match err.code { err_mutbl(lk) => { - fmt!("creating %s alias to %s", - self.loan_kind_to_str(lk), - self.cmt_to_str(err.cmt)) + fmt!("cannot borrow %s %s as %s", + err.cmt.mutbl.to_user_str(), + self.cmt_to_str(err.cmt), + self.mut_to_str(lk)) } - err_mut_uniq => { - ~"unique value in aliasable, mutable location" + err_out_of_root_scope(*) => { + fmt!("cannot root managed value long enough") } - err_mut_variant => { - ~"enum variant in aliasable, mutable location" + err_out_of_scope(*) => { + fmt!("borrowed value does not live long enough") } - err_root_not_permitted => { - // note: I don't expect users to ever see this error - // message, reasons are discussed in attempt_root() in - // preserve.rs. - ~"rooting is not permitted" + err_freeze_aliasable_const => { + // Means that the user borrowed a ~T or enum value + // residing in &const or @const pointer. Terrible + // error message, but then &const and @const are + // supposed to be going away. + fmt!("unsafe borrow of aliasable, const value") } - err_out_of_root_scope(*) => { - ~"cannot root managed value long enough" + } + } + + fn report_aliasability_violation(&self, + span: span, + kind: AliasableViolationKind, + cause: mc::AliasableReason) { + let prefix = match kind { + MutabilityViolation => "cannot assign to an `&mut`", + BorrowViolation => "cannot borrow an `&mut`" + }; + + match cause { + mc::AliasableOther => { + self.tcx.sess.span_err( + span, + fmt!("%s in an aliasable location", prefix)); } - err_out_of_scope(*) => { - ~"borrowed value does not live long enough" + mc::AliasableManaged(ast::m_mutbl) => { + // FIXME(#5074) we should prob do this borrow + self.tcx.sess.span_err( + span, + fmt!("%s in a `@mut` pointer; \ + try borrowing as `&mut` first", prefix)); + } + mc::AliasableManaged(m) => { + self.tcx.sess.span_err( + span, + fmt!("%s in a `@%s` pointer; \ + try an `@mut` instead", + prefix, + self.mut_to_keyword(m))); + } + mc::AliasableBorrowed(m) => { + self.tcx.sess.span_err( + span, + fmt!("%s in a `&%s` pointer; \ + try an `&mut` instead", + prefix, + self.mut_to_keyword(m))); } } } - fn note_and_explain_bckerr(&self, err: bckerr) { + fn note_and_explain_bckerr(&self, err: BckError) { let code = err.code; match code { - err_mutbl(*) | err_mut_uniq | err_mut_variant | - err_root_not_permitted => {} + err_mutbl(*) | err_freeze_aliasable_const(*) => {} err_out_of_root_scope(super_scope, sub_scope) => { note_and_explain_region( @@ -607,46 +568,140 @@ pub impl BorrowckCtxt { } } + fn append_loan_path_to_str_from_interior(&self, + loan_path: &LoanPath, + out: &mut ~str) { + match *loan_path { + LpExtend(_, _, LpDeref) => { + str::push_char(out, '('); + self.append_loan_path_to_str(loan_path, out); + str::push_char(out, ')'); + } + LpExtend(_, _, LpInterior(_)) | + LpVar(_) => { + self.append_loan_path_to_str(loan_path, out); + } + } + } + + fn append_loan_path_to_str(&self, loan_path: &LoanPath, out: &mut ~str) { + match *loan_path { + LpVar(id) => { + match self.tcx.items.find(&id) { + Some(&ast_map::node_local(ident)) => { + str::push_str(out, *self.tcx.sess.intr().get(ident)); + } + r => { + self.tcx.sess.bug( + fmt!("Loan path LpVar(%?) maps to %?, not local", + id, r)); + } + } + } - fn cmt_to_str(&self, cmt: cmt) -> ~str { - let mc = &mem_categorization_ctxt {tcx: self.tcx, - method_map: self.method_map}; - mc.cmt_to_str(cmt) + LpExtend(lp_base, _, LpInterior(mc::interior_field(fld, _))) => { + self.append_loan_path_to_str_from_interior(lp_base, out); + str::push_char(out, '.'); + str::push_str(out, *self.tcx.sess.intr().get(fld)); + } + + LpExtend(lp_base, _, LpInterior(mc::interior_index(*))) => { + self.append_loan_path_to_str_from_interior(lp_base, out); + str::push_str(out, "[]"); + } + + LpExtend(lp_base, _, LpInterior(mc::interior_tuple)) | + LpExtend(lp_base, _, LpInterior(mc::interior_anon_field)) | + LpExtend(lp_base, _, LpInterior(mc::interior_variant(_))) => { + self.append_loan_path_to_str_from_interior(lp_base, out); + str::push_str(out, ".(tuple)"); + } + + LpExtend(lp_base, _, LpDeref) => { + str::push_char(out, '*'); + self.append_loan_path_to_str(lp_base, out); + } + } + } + + fn loan_path_to_str(&self, loan_path: &LoanPath) -> ~str { + let mut result = ~""; + self.append_loan_path_to_str(loan_path, &mut result); + result } - fn cmt_to_repr(&self, cmt: cmt) -> ~str { - let mc = &mem_categorization_ctxt {tcx: self.tcx, - method_map: self.method_map}; - mc.cmt_to_repr(cmt) + fn cmt_to_str(&self, cmt: mc::cmt) -> ~str { + let mc = &mc::mem_categorization_ctxt {tcx: self.tcx, + method_map: self.method_map}; + mc.cmt_to_str(cmt) } fn mut_to_str(&self, mutbl: ast::mutability) -> ~str { - let mc = &mem_categorization_ctxt {tcx: self.tcx, - method_map: self.method_map}; + let mc = &mc::mem_categorization_ctxt {tcx: self.tcx, + method_map: self.method_map}; mc.mut_to_str(mutbl) } - fn loan_kind_to_str(&self, lk: LoanKind) -> ~str { - match lk { - TotalFreeze | PartialFreeze => ~"immutable", - TotalTake | PartialTake => ~"mutable", - Immobile => ~"read-only" + fn mut_to_keyword(&self, mutbl: ast::mutability) -> &'static str { + match mutbl { + ast::m_imm => "", + ast::m_const => "const", + ast::m_mutbl => "mut" } } +} + +impl DataFlowOperator for LoanDataFlowOperator { + #[inline(always)] + fn initial_value(&self) -> bool { + false // no loans in scope by default + } + + #[inline(always)] + fn join(&self, succ: uint, pred: uint) -> uint { + succ | pred // loans from both preds are in scope + } + + #[inline(always)] + fn walk_closures(&self) -> bool { + true + } +} - fn loan_to_repr(&self, loan: &Loan) -> ~str { - fmt!("Loan(lp=%?, cmt=%s, kind=%?)", - loan.lp, self.cmt_to_repr(loan.cmt), loan.kind) +impl Repr for Loan { + fn repr(&self, tcx: ty::ctxt) -> ~str { + fmt!("Loan_%?(%s, %?, %?-%?, %s)", + self.index, + self.loan_path.repr(tcx), + self.mutbl, + self.gen_scope, + self.kill_scope, + self.restrictions.repr(tcx)) } } -// The inherent mutability of a component is its default mutability -// assuming it is embedded in an immutable context. In general, the -// mutability can be "overridden" if the component is embedded in a -// mutable structure. -pub fn inherent_mutability(ck: comp_kind) -> mutability { - match ck { - comp_tuple | comp_anon_field | comp_variant(_) => m_imm, - comp_field(_, m) | comp_index(_, m) => m +impl Repr for Restriction { + fn repr(&self, tcx: ty::ctxt) -> ~str { + fmt!("Restriction(%s, %x)", + self.loan_path.repr(tcx), + self.set.bits as uint) + } +} + +impl Repr for LoanPath { + fn repr(&self, tcx: ty::ctxt) -> ~str { + match self { + &LpVar(id) => { + fmt!("$(%?)", id) + } + + &LpExtend(lp, _, LpDeref) => { + fmt!("%s.*", lp.repr(tcx)) + } + + &LpExtend(lp, _, LpInterior(ref interior)) => { + fmt!("%s.%s", lp.repr(tcx), interior.repr(tcx)) + } + } } } diff --git a/src/librustc/middle/borrowck/preserve.rs b/src/librustc/middle/borrowck/preserve.rs deleted file mode 100644 index c44920fffa568..0000000000000 --- a/src/librustc/middle/borrowck/preserve.rs +++ /dev/null @@ -1,409 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// ---------------------------------------------------------------------- -// Preserve(Ex, S) holds if ToAddr(Ex) will remain valid for the entirety of -// the scope S. -// - -use middle::borrowck::{RootInfo, bckerr, bckerr_code, bckres, BorrowckCtxt}; -use middle::borrowck::{err_mut_uniq, err_mut_variant}; -use middle::borrowck::{err_out_of_root_scope, err_out_of_scope}; -use middle::borrowck::{err_root_not_permitted, root_map_key}; -use middle::mem_categorization::{cat_arg, cat_binding, cat_comp, cat_deref}; -use middle::mem_categorization::{cat_discr, cat_local, cat_self, cat_special}; -use middle::mem_categorization::{cat_stack_upvar, cmt, comp_field}; -use middle::mem_categorization::{comp_index, comp_variant, gc_ptr}; -use middle::mem_categorization::{region_ptr}; -use middle::ty; -use util::common::indenter; - -use syntax::ast; - -pub enum PreserveCondition { - PcOk, - PcIfPure(bckerr) -} - -pub impl PreserveCondition { - // combines two preservation conditions such that if either of - // them requires purity, the result requires purity - fn combine(&self, pc: PreserveCondition) -> PreserveCondition { - match *self { - PcOk => {pc} - PcIfPure(_) => {*self} - } - } -} - -pub impl BorrowckCtxt { - fn preserve(&self, - cmt: cmt, - scope_region: ty::Region, - item_ub: ast::node_id, - root_ub: ast::node_id) -> bckres - { - let ctxt = PreserveCtxt { - bccx: self, - scope_region: scope_region, - item_ub: item_ub, - root_ub: root_ub, - root_managed_data: true - }; - ctxt.preserve(cmt) - } -} - -struct PreserveCtxt<'self> { - bccx: &'self BorrowckCtxt, - - // the region scope for which we must preserve the memory - scope_region: ty::Region, - - // the scope for the body of the enclosing fn/method item - item_ub: ast::node_id, - - // the upper bound on how long we can root an @T pointer - root_ub: ast::node_id, - - // if false, do not attempt to root managed data - root_managed_data: bool -} - -pub impl<'self> PreserveCtxt<'self> { - fn tcx(&self) -> ty::ctxt { self.bccx.tcx } - - fn preserve(&self, cmt: cmt) -> bckres { - debug!("preserve(cmt=%s, root_ub=%?, root_managed_data=%b)", - self.bccx.cmt_to_repr(cmt), self.root_ub, - self.root_managed_data); - let _i = indenter(); - - match cmt.cat { - cat_special(sk_implicit_self) | - cat_special(sk_heap_upvar) => { - self.compare_scope(cmt, ty::re_scope(self.item_ub)) - } - cat_special(sk_static_item) | cat_special(sk_method) => { - Ok(PcOk) - } - cat_rvalue => { - // when we borrow an rvalue, we can keep it rooted but only - // up to the root_ub point - - // When we're in a 'const &x = ...' context, self.root_ub is - // zero and the rvalue is static, not bound to a scope. - let scope_region = if self.root_ub == 0 { - ty::re_static - } else { - // Maybe if we pass in the parent instead here, - // we can prevent the "scope not found" error - debug!("scope_region thing: %? ", cmt.id); - self.tcx().region_maps.encl_region(cmt.id) - }; - - self.compare_scope(cmt, scope_region) - } - cat_stack_upvar(cmt) => { - self.preserve(cmt) - } - cat_local(local_id) => { - // Normally, local variables are lendable, and so this - // case should never trigger. However, if we are - // preserving an expression like a.b where the field `b` - // has @ type, then it will recurse to ensure that the `a` - // is stable to try and avoid rooting the value `a.b`. In - // this case, root_managed_data will be false. - if self.root_managed_data { - self.tcx().sess.span_bug( - cmt.span, - ~"preserve() called with local and !root_managed_data"); - } - let local_region = self.tcx().region_maps.encl_region(local_id); - self.compare_scope(cmt, local_region) - } - cat_binding(local_id) => { - // Bindings are these kind of weird implicit pointers (cc - // #2329). We require (in gather_loans) that they be - // rooted in an immutable location. - let local_region = self.tcx().region_maps.encl_region(local_id); - self.compare_scope(cmt, local_region) - } - cat_arg(local_id) => { - // This can happen as not all args are lendable (e.g., && - // modes). In that case, the caller guarantees stability - // for at least the scope of the fn. This is basically a - // deref of a region ptr. - let local_region = self.tcx().region_maps.encl_region(local_id); - self.compare_scope(cmt, local_region) - } - cat_self(local_id) => { - let local_region = self.tcx().region_maps.encl_region(local_id); - self.compare_scope(cmt, local_region) - } - cat_comp(cmt_base, comp_field(*)) | - cat_comp(cmt_base, comp_index(*)) | - cat_comp(cmt_base, comp_tuple) | - cat_comp(cmt_base, comp_anon_field) => { - // Most embedded components: if the base is stable, the - // type never changes. - self.preserve(cmt_base) - } - cat_comp(cmt_base, comp_variant(enum_did)) => { - if ty::enum_is_univariant(self.tcx(), enum_did) { - self.preserve(cmt_base) - } else { - // If there are multiple variants: overwriting the - // base could cause the type of this memory to change, - // so require imm. - self.require_imm(cmt, cmt_base, err_mut_variant) - } - } - cat_deref(cmt_base, _, uniq_ptr) => { - // Overwriting the base could cause this memory to be - // freed, so require imm. - self.require_imm(cmt, cmt_base, err_mut_uniq) - } - cat_deref(_, _, region_ptr(_, region)) => { - // References are always "stable" for lifetime `region` by - // induction (when the reference of type &MT was created, - // the memory must have been stable). - self.compare_scope(cmt, region) - } - cat_deref(_, _, unsafe_ptr) => { - // Unsafe pointers are the user's problem - Ok(PcOk) - } - cat_deref(base, derefs, gc_ptr(*)) => { - // GC'd pointers of type @MT: if this pointer lives in - // immutable, stable memory, then everything is fine. But - // otherwise we have no guarantee the pointer will stay - // live, so we must root the pointer (i.e., inc the ref - // count) for the duration of the loan. - debug!("base.mutbl = %?", base.mutbl); - if cmt.cat.derefs_through_mutable_box() { - self.attempt_root(cmt, base, derefs) - } else if base.mutbl.is_immutable() { - let non_rooting_ctxt = PreserveCtxt { - root_managed_data: false, - ..*self - }; - match non_rooting_ctxt.preserve(base) { - Ok(PcOk) => { - Ok(PcOk) - } - Ok(PcIfPure(_)) => { - debug!("must root @T, otherwise purity req'd"); - self.attempt_root(cmt, base, derefs) - } - Err(ref e) => { - debug!("must root @T, err: %s", - self.bccx.bckerr_to_str((*e))); - self.attempt_root(cmt, base, derefs) - } - } - } else { - self.attempt_root(cmt, base, derefs) - } - } - cat_discr(base, match_id) => { - // Subtle: in a match, we must ensure that each binding - // variable remains valid for the duration of the arm in - // which it appears, presuming that this arm is taken. - // But it is inconvenient in trans to root something just - // for one arm. Therefore, we insert a cat_discr(), - // basically a special kind of category that says "if this - // value must be dynamically rooted, root it for the scope - // `match_id`. - // - // As an example, consider this scenario: - // - // let mut x = @Some(3); - // match *x { Some(y) {...} None {...} } - // - // Technically, the value `x` need only be rooted - // in the `some` arm. However, we evaluate `x` in trans - // before we know what arm will be taken, so we just - // always root it for the duration of the match. - // - // As a second example, consider *this* scenario: - // - // let x = @mut @Some(3); - // match x { @@Some(y) {...} @@None {...} } - // - // Here again, `x` need only be rooted in the `some` arm. - // In this case, the value which needs to be rooted is - // found only when checking which pattern matches: but - // this check is done before entering the arm. Therefore, - // even in this case we just choose to keep the value - // rooted for the entire match. This means the value will be - // rooted even if the none arm is taken. Oh well. - // - // At first, I tried to optimize the second case to only - // root in one arm, but the result was suboptimal: first, - // it interfered with the construction of phi nodes in the - // arm, as we were adding code to root values before the - // phi nodes were added. This could have been addressed - // with a second basic block. However, the naive approach - // also yielded suboptimal results for patterns like: - // - // let x = @mut @...; - // match x { @@some_variant(y) | @@some_other_variant(y) => - // - // The reason is that we would root the value once for - // each pattern and not once per arm. This is also easily - // fixed, but it's yet more code for what is really quite - // the corner case. - // - // Nonetheless, if you decide to optimize this case in the - // future, you need only adjust where the cat_discr() - // node appears to draw the line between what will be rooted - // in the *arm* vs the *match*. - - let match_rooting_ctxt = PreserveCtxt { - scope_region: ty::re_scope(match_id), - ..*self - }; - match_rooting_ctxt.preserve(base) - } - } - } - - /// Reqiures that `cmt` (which is a deref or subcomponent of - /// `base`) be found in an immutable location (that is, `base` - /// must be immutable). Also requires that `base` itself is - /// preserved. - fn require_imm(&self, - cmt: cmt, - cmt_base: cmt, - code: bckerr_code) -> bckres { - // Variant contents and unique pointers: must be immutably - // rooted to a preserved address. - match self.preserve(cmt_base) { - // the base is preserved, but if we are not mutable then - // purity is required - Ok(PcOk) => { - if !cmt_base.mutbl.is_immutable() { - Ok(PcIfPure(bckerr {cmt:cmt, code:code})) - } else { - Ok(PcOk) - } - } - - // the base requires purity too, that's fine - Ok(PcIfPure(ref e)) => { - Ok(PcIfPure((*e))) - } - - // base is not stable, doesn't matter - Err(ref e) => { - Err((*e)) - } - } - } - - /// Checks that the scope for which the value must be preserved - /// is a subscope of `scope_ub`; if so, success. - fn compare_scope(&self, - cmt: cmt, - scope_ub: ty::Region) -> bckres { - if self.bccx.is_subregion_of(self.scope_region, scope_ub) { - Ok(PcOk) - } else { - Err(bckerr { - cmt:cmt, - code:err_out_of_scope(scope_ub, self.scope_region) - }) - } - } - - /// Here, `cmt=*base` is always a deref of managed data (if - /// `derefs` != 0, then an auto-deref). This routine determines - /// whether it is safe to MAKE cmt stable by rooting the pointer - /// `base`. We can only do the dynamic root if the desired - /// lifetime `self.scope_region` is a subset of `self.root_ub` - /// scope; otherwise, it would either require that we hold the - /// value live for longer than the current fn or else potentially - /// require that an statically unbounded number of values be - /// rooted (if a loop exists). - fn attempt_root(&self, cmt: cmt, base: cmt, - derefs: uint) -> bckres { - if !self.root_managed_data { - // normally, there is a root_ub; the only time that this - // is none is when a boxed value is stored in an immutable - // location. In that case, we will test to see if that - // immutable location itself can be preserved long enough - // in which case no rooting is necessary. But there it - // would be sort of pointless to avoid rooting the inner - // box by rooting an outer box, as it would just keep more - // memory live than necessary, so we set root_ub to none. - return Err(bckerr { cmt: cmt, code: err_root_not_permitted }); - } - - let root_region = ty::re_scope(self.root_ub); - match self.scope_region { - // we can only root values if the desired region is some concrete - // scope within the fn body - ty::re_scope(scope_id) => { - debug!("Considering root map entry for %s: \ - node %d:%u -> scope_id %?, root_ub %?", - self.bccx.cmt_to_repr(cmt), base.id, - derefs, scope_id, self.root_ub); - if self.bccx.is_subregion_of(self.scope_region, root_region) { - debug!("Elected to root"); - let rk = root_map_key { id: base.id, derefs: derefs }; - // This code could potentially lead cause boxes to be frozen - // for longer than necessarily at runtime. It prevents an - // ICE in trans; the fundamental problem is that it's hard - // to make sure trans and borrowck have the same notion of - // scope. The real fix is to clean up how trans handles - // cleanups, but that's hard. If this becomes an issue, it's - // an option to just change this to `let scope_to_use = - // scope_id;`. Though that would potentially re-introduce - // the ICE. See #3511 for more details. - let scope_to_use = if - self.bccx.stmt_map.contains(&scope_id) { - // Root it in its parent scope, b/c - // trans won't introduce a new scope for the - // stmt - self.root_ub - } - else { - // Use the more precise scope - scope_id - }; - // We freeze if and only if this is a *mutable* @ box that - // we're borrowing into a pointer. - self.bccx.root_map.insert(rk, RootInfo { - scope: scope_to_use, - freezes: cmt.cat.derefs_through_mutable_box() - }); - return Ok(PcOk); - } else { - debug!("Unable to root"); - return Err(bckerr { - cmt: cmt, - code: err_out_of_root_scope(root_region, - self.scope_region) - }); - } - } - - // we won't be able to root long enough - _ => { - return Err(bckerr { - cmt:cmt, - code:err_out_of_root_scope(root_region, self.scope_region) - }); - } - - } - } -} diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index bba4d35b56046..dea08eedb61cf 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -185,9 +185,7 @@ pub fn lookup_const_by_id(tcx: ty::ctxt, } } else { let maps = astencode::Maps { - mutbl_map: @mut HashSet::new(), root_map: @mut HashMap::new(), - last_use_map: @mut HashMap::new(), method_map: @mut HashMap::new(), vtable_map: @mut HashMap::new(), write_guard_map: @mut HashSet::new(), diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs new file mode 100644 index 0000000000000..cfdd7f95030aa --- /dev/null +++ b/src/librustc/middle/dataflow.rs @@ -0,0 +1,1009 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +/*! + * A module for propagating forward dataflow information. The analysis + * assumes that the items to be propagated can be represented as bits + * and thus uses bitvectors. Your job is simply to specify the so-called + * GEN and KILL bits for each expression. + */ + +use core::prelude::*; +use core::cast; +use core::uint; +use syntax::ast; +use syntax::ast_util; +use syntax::ast_util::id_range; +use syntax::print::{pp, pprust}; +use middle::ty; +use middle::typeck; +use util::ppaux::Repr; + +pub struct DataFlowContext { + priv tcx: ty::ctxt, + priv method_map: typeck::method_map, + + /// the data flow operator + priv oper: O, + + /// range of ids that appear within the item in question + priv id_range: id_range, + + /// number of bits to propagate per id + priv bits_per_id: uint, + + /// number of words we will use to store bits_per_id. + /// equal to bits_per_id/uint::bits rounded up. + priv words_per_id: uint, + + // Bit sets per id. The following three fields (`gens`, `kills`, + // and `on_entry`) all have the same structure. For each id in + // `id_range`, there is a range of words equal to `words_per_id`. + // So, to access the bits for any given id, you take a slice of + // the full vector (see the method `compute_id_range()`). + + /// bits generated as we exit the scope `id`. Updated by `add_gen()`. + priv gens: ~[uint], + + /// bits killed as we exit the scope `id`. Updated by `add_kill()`. + priv kills: ~[uint], + + /// bits that are valid on entry to the scope `id`. Updated by + /// `propagate()`. + priv on_entry: ~[uint] +} + +/// Parameterization for the precise form of data flow that is used. +pub trait DataFlowOperator { + /// Specifies the initial value for each bit in the `on_entry` set + fn initial_value(&self) -> bool; + + /// Joins two predecessor bits together, typically either `|` or `&` + fn join(&self, succ: uint, pred: uint) -> uint; + + /// True if we should propagate through closures + fn walk_closures(&self) -> bool; +} + +struct PropagationContext<'self, O> { + dfcx: &'self mut DataFlowContext, + changed: bool +} + +#[deriving(Eq)] +enum LoopKind { + /// A `while` or `loop` loop + TrueLoop, + + /// A `for` "loop" (i.e., really a func call where `break`, `return`, + /// and `loop` all essentially perform an early return from the closure) + ForLoop +} + +struct LoopScope<'self> { + loop_id: ast::node_id, + loop_kind: LoopKind, + break_bits: ~[uint] +} + +impl DataFlowContext { + pub fn new(tcx: ty::ctxt, + method_map: typeck::method_map, + oper: O, + id_range: id_range, + bits_per_id: uint) -> DataFlowContext { + let words_per_id = (bits_per_id + uint::bits - 1) / uint::bits; + + debug!("DataFlowContext::new(id_range=%?, bits_per_id=%?, words_per_id=%?)", + id_range, bits_per_id, words_per_id); + + let len = (id_range.max - id_range.min) as uint * words_per_id; + let gens = vec::from_elem(len, 0); + let kills = vec::from_elem(len, 0); + let elem = if oper.initial_value() {uint::max_value} else {0}; + let on_entry = vec::from_elem(len, elem); + + DataFlowContext { + tcx: tcx, + method_map: method_map, + words_per_id: words_per_id, + bits_per_id: bits_per_id, + oper: oper, + id_range: id_range, + gens: gens, + kills: kills, + on_entry: on_entry + } + } + + pub fn add_gen(&mut self, id: ast::node_id, bit: uint) { + //! Indicates that `id` generates `bit` + + debug!("add_gen(id=%?, bit=%?)", id, bit); + let (start, end) = self.compute_id_range(id); + { + let gens = vec::mut_slice(self.gens, start, end); + set_bit(gens, bit); + } + } + + pub fn add_kill(&mut self, id: ast::node_id, bit: uint) { + //! Indicates that `id` kills `bit` + + debug!("add_kill(id=%?, bit=%?)", id, bit); + let (start, end) = self.compute_id_range(id); + { + let kills = vec::mut_slice(self.kills, start, end); + set_bit(kills, bit); + } + } + + fn apply_gen_kill(&self, id: ast::node_id, bits: &mut [uint]) { + //! Applies the gen and kill sets for `id` to `bits` + + debug!("apply_gen_kill(id=%?, bits=%s) [before]", + id, mut_bits_to_str(bits)); + let (start, end) = self.compute_id_range(id); + let gens = self.gens.slice(start, end); + bitwise(bits, gens, |a, b| a | b); + let kills = self.kills.slice(start, end); + bitwise(bits, kills, |a, b| a & !b); + + debug!("apply_gen_kill(id=%?, bits=%s) [after]", + id, mut_bits_to_str(bits)); + } + + fn apply_kill(&self, id: ast::node_id, bits: &mut [uint]) { + debug!("apply_kill(id=%?, bits=%s) [before]", + id, mut_bits_to_str(bits)); + let (start, end) = self.compute_id_range(id); + let kills = self.kills.slice(start, end); + bitwise(bits, kills, |a, b| a & !b); + debug!("apply_kill(id=%?, bits=%s) [after]", + id, mut_bits_to_str(bits)); + } + + fn compute_id_range(&self, absolute_id: ast::node_id) -> (uint, uint) { + assert!(absolute_id >= self.id_range.min); + assert!(absolute_id < self.id_range.max); + + let relative_id = absolute_id - self.id_range.min; + let start = (relative_id as uint) * self.words_per_id; + let end = start + self.words_per_id; + (start, end) + } + + + pub fn each_bit_on_entry(&self, + id: ast::node_id, + f: &fn(uint) -> bool) { + //! Iterates through each bit that is set on entry to `id`. + //! Only useful after `propagate()` has been called. + + let (start, end) = self.compute_id_range(id); + let on_entry = vec::slice(self.on_entry, start, end); + debug!("each_bit_on_entry(id=%?, on_entry=%s)", + id, bits_to_str(on_entry)); + self.each_bit(on_entry, f); + } + + pub fn each_gen_bit(&self, + id: ast::node_id, + f: &fn(uint) -> bool) { + //! Iterates through each bit in the gen set for `id`. + + let (start, end) = self.compute_id_range(id); + let gens = vec::slice(self.gens, start, end); + debug!("each_gen_bit(id=%?, gens=%s)", + id, bits_to_str(gens)); + self.each_bit(gens, f) + } + + fn each_bit(&self, + words: &[uint], + f: &fn(uint) -> bool) { + //! Helper for iterating over the bits in a bit set. + + for words.eachi |word_index, &word| { + if word != 0 { + let base_index = word_index * uint::bits; + for uint::range(0, uint::bits) |offset| { + let bit = 1 << offset; + if (word & bit) != 0 { + // NB: we round up the total number of bits + // that we store in any given bit set so that + // it is an even multiple of uint::bits. This + // means that there may be some stray bits at + // the end that do not correspond to any + // actual value. So before we callback, check + // whether the bit_index is greater than the + // actual value the user specified and stop + // iterating if so. + let bit_index = base_index + offset; + if bit_index >= self.bits_per_id || !f(bit_index) { + return; + } + } + } + } + } + } +} + +impl DataFlowContext { +// ^^^^^^^^^^^^ only needed for pretty printing + pub fn propagate(&mut self, blk: &ast::blk) { + //! Performs the data flow analysis. + + if self.bits_per_id == 0 { + // Optimize the surprisingly common degenerate case. + return; + } + + let mut propcx = PropagationContext { + dfcx: self, + changed: true + }; + + let mut temp = vec::from_elem(self.words_per_id, 0); + let mut loop_scopes = ~[]; + + while propcx.changed { + propcx.changed = false; + propcx.reset(temp); + propcx.walk_block(blk, temp, &mut loop_scopes); + } + + debug!("Dataflow result:"); + debug!("%s", { + let this = @copy *self; + this.pretty_print_to(io::stderr(), blk); + "" + }); + } + + fn pretty_print_to(@self, wr: @io::Writer, blk: &ast::blk) { + let pre: @fn(pprust::ann_node) = |node| { + let (ps, id) = match node { + pprust::node_expr(ps, expr) => (ps, expr.id), + pprust::node_block(ps, blk) => (ps, blk.node.id), + pprust::node_item(ps, _) => (ps, 0), + pprust::node_pat(ps, pat) => (ps, pat.id) + }; + + if id >= self.id_range.min || id < self.id_range.max { + let (start, end) = self.compute_id_range(id); + let on_entry = vec::slice(self.on_entry, start, end); + let entry_str = bits_to_str(on_entry); + + let gens = vec::slice(self.gens, start, end); + let gens_str = if gens.any(|&u| u != 0) { + fmt!(" gen: %s", bits_to_str(gens)) + } else { + ~"" + }; + + let kills = vec::slice(self.kills, start, end); + let kills_str = if kills.any(|&u| u != 0) { + fmt!(" kill: %s", bits_to_str(kills)) + } else { + ~"" + }; + + let comment_str = fmt!("id %d: %s%s%s", + id, entry_str, gens_str, kills_str); + pprust::synth_comment(ps, comment_str); + pp::space(ps.s); + } + }; + + let post: @fn(pprust::ann_node) = |_| { + }; + + let ps = pprust::rust_printer_annotated( + wr, self.tcx.sess.intr(), + pprust::pp_ann {pre:pre, post:post}); + pprust::cbox(ps, pprust::indent_unit); + pprust::ibox(ps, 0u); + pprust::print_block(ps, blk); + pp::eof(ps.s); + } +} + +impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { + fn tcx(&self) -> ty::ctxt { + self.dfcx.tcx + } + + fn walk_block(&mut self, + blk: &ast::blk, + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + debug!("DataFlowContext::walk_block(blk.node.id=%?, in_out=%s)", + blk.node.id, bits_to_str(reslice(in_out))); + + self.merge_with_entry_set(blk.node.id, in_out); + + for blk.node.stmts.each |&stmt| { + self.walk_stmt(stmt, in_out, loop_scopes); + } + + self.walk_opt_expr(blk.node.expr, in_out, loop_scopes); + + self.dfcx.apply_gen_kill(blk.node.id, in_out); + } + + fn walk_stmt(&mut self, + stmt: @ast::stmt, + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + match stmt.node { + ast::stmt_decl(decl, _) => { + self.walk_decl(decl, in_out, loop_scopes); + } + + ast::stmt_expr(expr, _) | ast::stmt_semi(expr, _) => { + self.walk_expr(expr, in_out, loop_scopes); + } + + ast::stmt_mac(*) => { + self.tcx().sess.span_bug(stmt.span, ~"unexpanded macro"); + } + } + } + + fn walk_decl(&mut self, + decl: @ast::decl, + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + match decl.node { + ast::decl_local(ref locals) => { + for locals.each |local| { + self.walk_pat(local.node.pat, in_out, loop_scopes); + self.walk_opt_expr(local.node.init, in_out, loop_scopes); + } + } + + ast::decl_item(_) => {} + } + } + + fn walk_expr(&mut self, + expr: @ast::expr, + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + debug!("DataFlowContext::walk_expr(expr=%s, in_out=%s)", + expr.repr(self.dfcx.tcx), bits_to_str(reslice(in_out))); + + self.merge_with_entry_set(expr.id, in_out); + + match expr.node { + ast::expr_fn_block(ref decl, ref body) => { + if self.dfcx.oper.walk_closures() { + // In the absence of once fns, we must assume that + // every function body will execute more than + // once. Thus we treat every function body like a + // loop. + // + // What is subtle and a bit tricky, also, is how + // to deal with the "output" bits---that is, what + // do we consider to be the successor of a + // function body, given that it could be called + // from any point within its lifetime? What we do + // is to add their effects immediately as of the + // point of creation. Of course we have to ensure + // that this is sound for the analyses which make + // use of dataflow. + // + // In the case of the initedness checker (which + // does not currently use dataflow, but I hope to + // convert at some point), we will simply not walk + // closures at all, so it's a moot point. + // + // In the case of the borrow checker, this means + // the loans which would be created by calling a + // function come into effect immediately when the + // function is created. This is guaranteed to be + // earlier than the point at which the loan + // actually comes into scope (which is the point + // at which the closure is *called*). Because + // loans persist until the scope of the loans is + // exited, it is always a safe approximation to + // have a loan begin earlier than it actually will + // at runtime, so this should be sound. + // + // We stil have to be careful in the region + // checker and borrow checker to treat function + // bodies like loops, which implies some + // limitations. For example, a closure cannot root + // a managed box for longer than its body. + // + // General control flow looks like this: + // + // +- (expr) <----------+ + // | | | + // | v | + // | (body) -----------+--> (exit) + // | | | + // | + (break/loop) -+ + // | | + // +--------------------+ + // + // This is a bit more conservative than a loop. + // Note that we must assume that even after a + // `break` occurs (e.g., in a `for` loop) that the + // closure may be reinvoked. + // + // One difference from other loops is that `loop` + // and `break` statements which target a closure + // both simply add to the `break_bits`. + + // func_bits represents the state when the function + // returns + let mut func_bits = reslice(in_out).to_vec(); + + loop_scopes.push(LoopScope { + loop_id: expr.id, + loop_kind: ForLoop, + break_bits: reslice(in_out).to_vec() + }); + for decl.inputs.each |input| { + self.walk_pat(input.pat, func_bits, loop_scopes); + } + self.walk_block(body, func_bits, loop_scopes); + + // add the bits from any early return via `break`, + // `continue`, or `return` into `func_bits` + let loop_scope = loop_scopes.pop(); + join_bits(&self.dfcx.oper, loop_scope.break_bits, func_bits); + + // add `func_bits` to the entry bits for `expr`, + // since we must assume the function may be called + // more than once + self.add_to_entry_set(expr.id, reslice(func_bits)); + + // the final exit bits include whatever was present + // in the original, joined with the bits from the function + join_bits(&self.dfcx.oper, func_bits, in_out); + } + } + + ast::expr_if(cond, ref then, els) => { + // + // (cond) + // | + // v + // ( ) + // / \ + // | | + // v v + // (then)(els) + // | | + // v v + // ( succ ) + // + self.walk_expr(cond, in_out, loop_scopes); + + let mut then_bits = reslice(in_out).to_vec(); + self.walk_block(then, then_bits, loop_scopes); + + self.walk_opt_expr(els, in_out, loop_scopes); + join_bits(&self.dfcx.oper, then_bits, in_out); + } + + ast::expr_while(cond, ref blk) => { + // + // (expr) <--+ + // | | + // v | + // +--(cond) | + // | | | + // | v | + // v (blk) ----+ + // | + // <--+ (break) + // + + self.walk_expr(cond, in_out, loop_scopes); + + let mut body_bits = reslice(in_out).to_vec(); + loop_scopes.push(LoopScope { + loop_id: expr.id, + loop_kind: TrueLoop, + break_bits: reslice(in_out).to_vec() + }); + self.walk_block(blk, body_bits, loop_scopes); + self.add_to_entry_set(expr.id, body_bits); + let new_loop_scope = loop_scopes.pop(); + copy_bits(new_loop_scope.break_bits, in_out); + } + + ast::expr_loop(ref blk, _) => { + // + // (expr) <--+ + // | | + // v | + // (blk) ----+ + // | + // <--+ (break) + // + + let mut body_bits = reslice(in_out).to_vec(); + self.reset(in_out); + loop_scopes.push(LoopScope { + loop_id: expr.id, + loop_kind: TrueLoop, + break_bits: reslice(in_out).to_vec() + }); + self.walk_block(blk, body_bits, loop_scopes); + self.add_to_entry_set(expr.id, body_bits); + + let new_loop_scope = loop_scopes.pop(); + assert_eq!(new_loop_scope.loop_id, expr.id); + copy_bits(new_loop_scope.break_bits, in_out); + } + + ast::expr_match(discr, ref arms) => { + // + // (discr) + // / | \ + // | | | + // v v v + // (..arms..) + // | | | + // v v v + // ( succ ) + // + // + self.walk_expr(discr, in_out, loop_scopes); + + let mut guards = reslice(in_out).to_vec(); + + // We know that exactly one arm will be taken, so we + // can start out with a blank slate and just union + // together the bits from each arm: + self.reset(in_out); + + for arms.each |arm| { + // in_out reflects the discr and all guards to date + self.walk_opt_expr(arm.guard, guards, loop_scopes); + + // determine the bits for the body and then union + // them into `in_out`, which reflects all bodies to date + let mut body = reslice(guards).to_vec(); + self.walk_pat_alternatives(arm.pats, body, loop_scopes); + self.walk_block(&arm.body, body, loop_scopes); + join_bits(&self.dfcx.oper, body, in_out); + } + } + + ast::expr_ret(o_e) => { + self.walk_opt_expr(o_e, in_out, loop_scopes); + + // is this a return from a `for`-loop closure? + match loop_scopes.position(|s| s.loop_kind == ForLoop) { + Some(i) => { + // if so, add the in_out bits to the state + // upon exit. Remember that we cannot count + // upon the `for` loop function not to invoke + // the closure again etc. + self.break_from_to(expr, &mut loop_scopes[i], in_out); + } + + None => {} + } + + self.reset(in_out); + } + + ast::expr_break(label) => { + let scope = self.find_scope(expr, label, loop_scopes); + self.break_from_to(expr, scope, in_out); + self.reset(in_out); + } + + ast::expr_again(label) => { + let scope = self.find_scope(expr, label, loop_scopes); + + match scope.loop_kind { + TrueLoop => { + self.pop_scopes(expr, scope, in_out); + self.add_to_entry_set(scope.loop_id, reslice(in_out)); + } + + ForLoop => { + // If this `loop` construct is looping back to a `for` + // loop, then `loop` is really just a return from the + // closure. Therefore, we treat it the same as `break`. + // See case for `expr_fn_block` for more details. + self.break_from_to(expr, scope, in_out); + } + } + + self.reset(in_out); + } + + ast::expr_assign(l, r) | + ast::expr_assign_op(_, l, r) => { + self.walk_expr(r, in_out, loop_scopes); + self.walk_expr(l, in_out, loop_scopes); + } + + ast::expr_swap(l, r) => { + self.walk_expr(l, in_out, loop_scopes); + self.walk_expr(r, in_out, loop_scopes); + } + + ast::expr_vec(ref exprs, _) => { + self.walk_exprs(*exprs, in_out, loop_scopes) + } + + ast::expr_repeat(l, r, _) => { + self.walk_expr(l, in_out, loop_scopes); + self.walk_expr(r, in_out, loop_scopes); + } + + ast::expr_struct(_, ref fields, with_expr) => { + self.walk_opt_expr(with_expr, in_out, loop_scopes); + for fields.each |field| { + self.walk_expr(field.node.expr, in_out, loop_scopes); + } + } + + ast::expr_call(f, ref args, _) => { + self.walk_call(expr.callee_id, expr.id, + f, *args, in_out, loop_scopes); + } + + ast::expr_method_call(rcvr, _, _, ref args, _) => { + self.walk_call(expr.callee_id, expr.id, + rcvr, *args, in_out, loop_scopes); + } + + ast::expr_index(l, r) | + ast::expr_binary(_, l, r) if self.is_method_call(expr) => { + self.walk_call(expr.callee_id, expr.id, + l, [r], in_out, loop_scopes); + } + + ast::expr_unary(_, e) if self.is_method_call(expr) => { + self.walk_call(expr.callee_id, expr.id, + e, [], in_out, loop_scopes); + } + + ast::expr_tup(ref exprs) => { + self.walk_exprs(*exprs, in_out, loop_scopes); + } + + ast::expr_binary(op, l, r) if ast_util::lazy_binop(op) => { + self.walk_expr(l, in_out, loop_scopes); + let temp = reslice(in_out).to_vec(); + self.walk_expr(r, in_out, loop_scopes); + join_bits(&self.dfcx.oper, temp, in_out); + } + + ast::expr_log(l, r) | + ast::expr_index(l, r) | + ast::expr_binary(_, l, r) => { + self.walk_exprs([l, r], in_out, loop_scopes); + } + + ast::expr_lit(*) | + ast::expr_path(*) => { + } + + ast::expr_addr_of(_, e) | + ast::expr_copy(e) | + ast::expr_loop_body(e) | + ast::expr_do_body(e) | + ast::expr_cast(e, _) | + ast::expr_unary(_, e) | + ast::expr_paren(e) | + ast::expr_vstore(e, _) | + ast::expr_field(e, _, _) => { + self.walk_expr(e, in_out, loop_scopes); + } + + ast::expr_inline_asm(ref inline_asm) => { + for inline_asm.inputs.each |&(_, expr)| { + self.walk_expr(expr, in_out, loop_scopes); + } + for inline_asm.outputs.each |&(_, expr)| { + self.walk_expr(expr, in_out, loop_scopes); + } + } + + ast::expr_block(ref blk) => { + self.walk_block(blk, in_out, loop_scopes); + } + + ast::expr_mac(*) => { + self.tcx().sess.span_bug(expr.span, ~"unexpanded macro"); + } + } + + self.dfcx.apply_gen_kill(expr.id, in_out); + } + + fn pop_scopes(&mut self, + from_expr: @ast::expr, + to_scope: &mut LoopScope, + in_out: &mut [uint]) { + //! Whenever you have a `break` or a `loop` statement, flow + //! exits through any number of enclosing scopes on its + //! way to the new destination. This function applies the kill + //! sets of those enclosing scopes to `in_out` (those kill sets + //! concern items that are going out of scope). + + let tcx = self.tcx(); + let region_maps = tcx.region_maps; + + debug!("pop_scopes(from_expr=%s, to_scope=%?, in_out=%s)", + from_expr.repr(tcx), to_scope.loop_id, + bits_to_str(reslice(in_out))); + + let mut id = from_expr.id; + while id != to_scope.loop_id { + self.dfcx.apply_kill(id, in_out); + + match region_maps.opt_encl_scope(id) { + Some(i) => { id = i; } + None => { + tcx.sess.span_bug( + from_expr.span, + fmt!("pop_scopes(from_expr=%s, to_scope=%?) \ + to_scope does not enclose from_expr", + from_expr.repr(tcx), to_scope.loop_id)); + } + } + } + } + + fn break_from_to(&mut self, + from_expr: @ast::expr, + to_scope: &mut LoopScope, + in_out: &mut [uint]) { + self.pop_scopes(from_expr, to_scope, in_out); + self.dfcx.apply_kill(from_expr.id, in_out); + join_bits(&self.dfcx.oper, reslice(in_out), to_scope.break_bits); + debug!("break_from_to(from_expr=%s, to_scope=%?) final break_bits=%s", + from_expr.repr(self.tcx()), + to_scope.loop_id, + bits_to_str(reslice(in_out))); + } + + fn walk_exprs(&mut self, + exprs: &[@ast::expr], + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + for exprs.each |&expr| { + self.walk_expr(expr, in_out, loop_scopes); + } + } + + fn walk_opt_expr(&mut self, + opt_expr: Option<@ast::expr>, + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + for opt_expr.each |&expr| { + self.walk_expr(expr, in_out, loop_scopes); + } + } + + fn walk_call(&mut self, + _callee_id: ast::node_id, + call_id: ast::node_id, + arg0: @ast::expr, + args: &[@ast::expr], + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + self.walk_expr(arg0, in_out, loop_scopes); + self.walk_exprs(args, in_out, loop_scopes); + + // FIXME(#5074) nested method calls + // self.merge_with_entry_set(callee_id, in_out); + // self.dfcx.apply_gen_kill(callee_id, in_out); + + let return_ty = ty::node_id_to_type(self.tcx(), call_id); + let fails = ty::type_is_bot(return_ty); + if fails { + self.reset(in_out); + } + } + + fn walk_pat(&mut self, + pat: @ast::pat, + in_out: &mut [uint], + _loop_scopes: &mut ~[LoopScope]) { + debug!("DataFlowContext::walk_pat(pat=%s, in_out=%s)", + pat.repr(self.dfcx.tcx), bits_to_str(reslice(in_out))); + + do ast_util::walk_pat(pat) |p| { + debug!(" p.id=%? in_out=%s", p.id, bits_to_str(reslice(in_out))); + self.merge_with_entry_set(p.id, in_out); + self.dfcx.apply_gen_kill(p.id, in_out); + } + } + + fn walk_pat_alternatives(&mut self, + pats: &[@ast::pat], + in_out: &mut [uint], + loop_scopes: &mut ~[LoopScope]) { + if pats.len() == 1 { + // Common special case: + return self.walk_pat(pats[0], in_out, loop_scopes); + } + + // In the general case, the patterns in `pats` are + // alternatives, so we must treat this like an N-way select + // statement. + let initial_state = reslice(in_out).to_vec(); + self.reset(in_out); + for pats.each |&pat| { + let mut temp = copy initial_state; + self.walk_pat(pat, in_out, loop_scopes); + join_bits(&self.dfcx.oper, temp, in_out); + } + } + + fn find_scope<'a>(&self, + expr: @ast::expr, + label: Option, + loop_scopes: &'a mut ~[LoopScope]) -> &'a mut LoopScope { + let index = match label { + None => { + let len = loop_scopes.len(); + len - 1 + } + + Some(_) => { + match self.tcx().def_map.find(&expr.id) { + Some(&ast::def_label(loop_id)) => { + match loop_scopes.position(|l| l.loop_id == loop_id) { + Some(i) => i, + None => { + self.tcx().sess.span_bug( + expr.span, + fmt!("No loop scope for id %?", loop_id)); + } + } + } + + r => { + self.tcx().sess.span_bug( + expr.span, + fmt!("Bad entry `%?` in def_map for label", r)); + } + } + } + }; + + &mut loop_scopes[index] + } + + fn is_method_call(&self, expr: @ast::expr) -> bool { + self.dfcx.method_map.contains_key(&expr.id) + } + + fn reset(&mut self, bits: &mut [uint]) { + let e = if self.dfcx.oper.initial_value() {uint::max_value} else {0}; + for vec::each_mut(bits) |b| { *b = e; } + } + + fn add_to_entry_set(&mut self, id: ast::node_id, pred_bits: &[uint]) { + debug!("add_to_entry_set(id=%?, pred_bits=%s)", + id, bits_to_str(pred_bits)); + let (start, end) = self.dfcx.compute_id_range(id); + let changed = { // FIXME(#5074) awkward construction + let on_entry = vec::mut_slice(self.dfcx.on_entry, start, end); + join_bits(&self.dfcx.oper, pred_bits, on_entry) + }; + if changed { + debug!("changed entry set for %? to %s", + id, bits_to_str(self.dfcx.on_entry.slice(start, end))); + self.changed = true; + } + } + + fn merge_with_entry_set(&mut self, + id: ast::node_id, + pred_bits: &mut [uint]) { + debug!("merge_with_entry_set(id=%?, pred_bits=%s)", + id, mut_bits_to_str(pred_bits)); + let (start, end) = self.dfcx.compute_id_range(id); + let changed = { // FIXME(#5074) awkward construction + let on_entry = vec::mut_slice(self.dfcx.on_entry, start, end); + let changed = join_bits(&self.dfcx.oper, reslice(pred_bits), on_entry); + copy_bits(reslice(on_entry), pred_bits); + changed + }; + if changed { + debug!("changed entry set for %? to %s", + id, bits_to_str(self.dfcx.on_entry.slice(start, end))); + self.changed = true; + } + } +} + +fn mut_bits_to_str(words: &mut [uint]) -> ~str { + bits_to_str(reslice(words)) +} + +fn bits_to_str(words: &[uint]) -> ~str { + let mut result = ~""; + let mut sep = '['; + + // Note: this is a little endian printout of bytes. + + for words.each |&word| { + let mut v = word; + for uint::range(0, uint::bytes) |_| { + str::push_char(&mut result, sep); + str::push_str(&mut result, fmt!("%02x", v & 0xFF)); + v >>= 8; + sep = '-'; + } + } + str::push_char(&mut result, ']'); + return result; +} + +fn copy_bits(in_vec: &[uint], out_vec: &mut [uint]) -> bool { + bitwise(out_vec, in_vec, |_, b| b) +} + +fn join_bits(oper: &O, + in_vec: &[uint], + out_vec: &mut [uint]) -> bool { + bitwise(out_vec, in_vec, |a, b| oper.join(a, b)) +} + +#[inline(always)] +fn bitwise(out_vec: &mut [uint], + in_vec: &[uint], + op: &fn(uint, uint) -> uint) -> bool { + assert_eq!(out_vec.len(), in_vec.len()); + let mut changed = false; + for uint::range(0, out_vec.len()) |i| { + let old_val = out_vec[i]; + let new_val = op(old_val, in_vec[i]); + out_vec[i] = new_val; + changed |= (old_val != new_val); + } + return changed; +} + +fn set_bit(words: &mut [uint], bit: uint) -> bool { + debug!("set_bit: words=%s bit=%s", + mut_bits_to_str(words), bit_str(bit)); + let word = bit / uint::bits; + let bit_in_word = bit % uint::bits; + let bit_mask = 1 << bit_in_word; + debug!("word=%u bit_in_word=%u bit_mask=%u", word, bit_in_word, word); + let oldv = words[word]; + let newv = oldv | bit_mask; + words[word] = newv; + oldv != newv +} + +fn bit_str(bit: uint) -> ~str { + let byte = bit >> 8; + let lobits = 1 << (bit & 0xFF); + fmt!("[%u:%u-%02x]", bit, byte, lobits) +} + +fn reslice<'a>(v: &'a mut [uint]) -> &'a [uint] { + // bFIXME(#5074) this function should not be necessary at all + unsafe { + cast::transmute(v) + } +} + diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index cf488b0ac8939..199eb274ab9e1 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -10,7 +10,6 @@ use middle::freevars::freevar_entry; use middle::freevars; -use middle::liveness; use middle::pat_util; use middle::ty; use middle::typeck; @@ -56,19 +55,16 @@ pub static try_adding: &'static str = "Try adding a move"; pub struct Context { tcx: ty::ctxt, method_map: typeck::method_map, - last_use_map: liveness::last_use_map, - current_item: node_id, + current_item: node_id } pub fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, - last_use_map: liveness::last_use_map, crate: @crate) { let ctx = Context { tcx: tcx, method_map: method_map, - last_use_map: last_use_map, - current_item: -1, + current_item: -1 }; let visit = visit::mk_vt(@visit::Visitor { visit_arm: check_arm, diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 2de12b9eb9746..784db49a0fd62 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -252,10 +252,9 @@ pub impl LanguageItems { } } -fn LanguageItemCollector<'r>(crate: @crate, - session: Session, - items: &'r mut LanguageItems) - -> LanguageItemCollector<'r> { +fn LanguageItemCollector(crate: @crate, + session: Session) + -> LanguageItemCollector { let mut item_refs = HashMap::new(); item_refs.insert(@~"const", ConstTraitLangItem as uint); @@ -303,13 +302,13 @@ fn LanguageItemCollector<'r>(crate: @crate, LanguageItemCollector { crate: crate, session: session, - items: items, + items: LanguageItems::new(), item_refs: item_refs } } -struct LanguageItemCollector<'self> { - items: &'self mut LanguageItems, +struct LanguageItemCollector { + items: LanguageItems, crate: @crate, session: Session, @@ -317,8 +316,8 @@ struct LanguageItemCollector<'self> { item_refs: HashMap<@~str, uint>, } -pub impl<'self> LanguageItemCollector<'self> { - fn match_and_collect_meta_item(&self, item_def_id: def_id, +pub impl LanguageItemCollector { + fn match_and_collect_meta_item(&mut self, item_def_id: def_id, meta_item: @meta_item) { match meta_item.node { meta_name_value(key, literal) => { @@ -333,7 +332,7 @@ pub impl<'self> LanguageItemCollector<'self> { } } - fn collect_item(&self, item_index: uint, item_def_id: def_id) { + fn collect_item(&mut self, item_index: uint, item_def_id: def_id) { // Check for duplicates. match self.items.items[item_index] { Some(original_def_id) if original_def_id != item_def_id => { @@ -349,34 +348,37 @@ pub impl<'self> LanguageItemCollector<'self> { self.items.items[item_index] = Some(item_def_id); } - fn match_and_collect_item(&self, + fn match_and_collect_item(&mut self, item_def_id: def_id, key: @~str, value: @~str) { if *key != ~"lang" { return; // Didn't match. } - match self.item_refs.find(&value) { + let item_index = self.item_refs.find(&value).map(|x| **x); + // prevent borrow checker from considering ^~~~~~~~~~~ + // self to be borrowed (annoying) + + match item_index { + Some(item_index) => { + self.collect_item(item_index, item_def_id); + } None => { // Didn't match. - } - Some(&item_index) => { - self.collect_item(item_index, item_def_id) + return; } } } - fn collect_local_language_items(&self) { - unsafe { - let this: *LanguageItemCollector<'self> = transmute(self); - visit_crate(self.crate, (), mk_simple_visitor(@SimpleVisitor { - visit_item: |item| { - for item.attrs.each |attribute| { - unsafe { - (*this).match_and_collect_meta_item( - local_def(item.id), - attribute.node.value - ); - } + fn collect_local_language_items(&mut self) { + let this = ptr::addr_of(&self); + visit_crate(self.crate, (), mk_simple_visitor(@SimpleVisitor { + visit_item: |item| { + for item.attrs.each |attribute| { + unsafe { + (*this).match_and_collect_meta_item( + local_def(item.id), + attribute.node.value + ); } }, .. *default_simple_visitor() @@ -384,7 +386,7 @@ pub impl<'self> LanguageItemCollector<'self> { } } - fn collect_external_language_items(&self) { + fn collect_external_language_items(&mut self) { let crate_store = self.session.cstore; do iter_crate_data(crate_store) |crate_number, _crate_metadata| { for each_lang_item(crate_store, crate_number) @@ -408,7 +410,7 @@ pub impl<'self> LanguageItemCollector<'self> { } } - fn collect(&self) { + fn collect(&mut self) { self.collect_local_language_items(); self.collect_external_language_items(); self.check_completeness(); @@ -418,9 +420,9 @@ pub impl<'self> LanguageItemCollector<'self> { pub fn collect_language_items(crate: @crate, session: Session) -> LanguageItems { - let mut items = LanguageItems::new(); - let collector = LanguageItemCollector(crate, session, &mut items); + let mut collector = LanguageItemCollector(crate, session); collector.collect(); - copy items + let LanguageItemCollector { items, _ } = collector; + items } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 94d82d0acb8e4..2e2c92abcdc78 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -121,16 +121,6 @@ use syntax::visit::{fk_anon, fk_dtor, fk_fn_block, fk_item_fn, fk_method}; use syntax::visit::{vt}; use syntax::{visit, ast_util}; -// Maps from an expr id to a list of variable ids for which this expr -// is the last use. Typically, the expr is a path and the node id is -// the local/argument/etc that the path refers to. However, it also -// possible for the expr to be a closure, in which case the list is a -// list of closed over variables that can be moved into the closure. -// -// Very subtle (#2633): borrowck will remove entries from this table -// if it detects an outstanding loan (that is, the addr is taken). -pub type last_use_map = @mut HashMap; - #[deriving(Eq)] struct Variable(uint); #[deriving(Eq)] @@ -158,7 +148,7 @@ pub fn check_crate(tcx: ty::ctxt, method_map: typeck::method_map, variable_moves_map: moves::VariableMovesMap, capture_map: moves::CaptureMap, - crate: @crate) -> last_use_map { + crate: @crate) { let visitor = visit::mk_vt(@visit::Visitor { visit_fn: visit_fn, visit_local: visit_local, @@ -168,16 +158,13 @@ pub fn check_crate(tcx: ty::ctxt, .. *visit::default_visitor() }); - let last_use_map = @mut HashMap::new(); let initial_maps = @mut IrMaps(tcx, method_map, variable_moves_map, capture_map, - last_use_map, 0); visit::visit_crate(crate, initial_maps, visitor); tcx.sess.abort_if_errors(); - return last_use_map; } impl to_str::ToStr for LiveNode { @@ -241,23 +228,11 @@ enum VarKind { ImplicitRet } -fn relevant_def(def: def) -> Option { - match def { - def_binding(nid, _) | - def_arg(nid, _) | - def_local(nid, _) | - def_self(nid, _) => Some(nid), - - _ => None - } -} - struct IrMaps { tcx: ty::ctxt, method_map: typeck::method_map, variable_moves_map: moves::VariableMovesMap, capture_map: moves::CaptureMap, - last_use_map: last_use_map, num_live_nodes: uint, num_vars: uint, @@ -274,7 +249,6 @@ fn IrMaps(tcx: ty::ctxt, method_map: typeck::method_map, variable_moves_map: moves::VariableMovesMap, capture_map: moves::CaptureMap, - last_use_map: last_use_map, cur_item: node_id) -> IrMaps { IrMaps { @@ -282,7 +256,6 @@ fn IrMaps(tcx: ty::ctxt, method_map: method_map, variable_moves_map: variable_moves_map, capture_map: capture_map, - last_use_map: last_use_map, num_live_nodes: 0, num_vars: 0, live_node_map: HashMap::new(), @@ -367,29 +340,6 @@ pub impl IrMaps { fn lnk(&mut self, ln: LiveNode) -> LiveNodeKind { self.lnks[*ln] } - - fn add_last_use(&mut self, expr_id: node_id, var: Variable) { - let vk = self.var_kinds[*var]; - debug!("Node %d is a last use of variable %?", expr_id, vk); - match vk { - Arg(id, _) | - Local(LocalInfo { id: id, kind: FromLetNoInitializer, _ }) | - Local(LocalInfo { id: id, kind: FromLetWithInitializer, _ }) | - Local(LocalInfo { id: id, kind: FromMatch(_), _ }) => { - let v = match self.last_use_map.find(&expr_id) { - Some(&v) => v, - None => { - let v = @mut ~[]; - self.last_use_map.insert(expr_id, v); - v - } - }; - - v.push(id); - } - ImplicitRet => debug!("--but it is not owned"), - } - } } fn visit_item(item: @item, self: @mut IrMaps, v: vt<@mut IrMaps>) { @@ -413,7 +363,6 @@ fn visit_fn(fk: &visit::fn_kind, self.method_map, self.variable_moves_map, self.capture_map, - self.last_use_map, self.cur_item); unsafe { @@ -522,7 +471,7 @@ fn visit_expr(expr: @expr, self: @mut IrMaps, vt: vt<@mut IrMaps>) { expr_path(_) => { let def = *self.tcx.def_map.get(&expr.id); debug!("expr %d: path that leads to %?", expr.id, def); - if relevant_def(def).is_some() { + if moves::moved_variable_node_id_from_def(def).is_some() { self.add_live_node_for_node(expr.id, ExprNode(expr.span)); } visit::visit_expr(expr, self, vt); @@ -539,7 +488,7 @@ fn visit_expr(expr: @expr, self: @mut IrMaps, vt: vt<@mut IrMaps>) { let cvs = self.capture_map.get(&expr.id); let mut call_caps = ~[]; for cvs.each |cv| { - match relevant_def(cv.def) { + match moves::moved_variable_node_id_from_def(cv.def) { Some(rv) => { let cv_ln = self.add_live_node(FreeVarNode(cv.span)); let is_move = match cv.mode { @@ -668,7 +617,7 @@ pub impl Liveness { match expr.node { expr_path(_) => { let def = *self.tcx.def_map.get(&expr.id); - relevant_def(def).map( + moves::moved_variable_node_id_from_def(def).map( |rdef| self.variable(*rdef, expr.span) ) } @@ -684,7 +633,7 @@ pub impl Liveness { span: span) -> Option { match self.tcx.def_map.find(&node_id) { Some(&def) => { - relevant_def(def).map( + moves::moved_variable_node_id_from_def(def).map( |rdef| self.variable(*rdef, span) ) } @@ -1388,7 +1337,7 @@ pub impl Liveness { fn access_path(&self, expr: @expr, succ: LiveNode, acc: uint) -> LiveNode { let def = *self.tcx.def_map.get(&expr.id); - match relevant_def(def) { + match moves::moved_variable_node_id_from_def(def) { Some(nid) => { let ln = self.live_node(expr.id, expr.span); if acc != 0u { @@ -1521,7 +1470,6 @@ fn check_expr(expr: @expr, self: @Liveness, vt: vt<@Liveness>) { expr_path(_) => { for self.variable_from_def_map(expr.id, expr.span).each |var| { let ln = self.live_node(expr.id, expr.span); - self.consider_last_use(expr, ln, *var); match self.ir.variable_moves_map.find(&expr.id) { None => {} @@ -1540,7 +1488,6 @@ fn check_expr(expr: @expr, self: @Liveness, vt: vt<@Liveness>) { let caps = self.ir.captures(expr); for caps.each |cap| { let var = self.variable(cap.var_nid, expr.span); - self.consider_last_use(expr, cap.ln, var); if cap.is_move { self.check_move_from_var(cap.ln, var, expr); } @@ -1609,7 +1556,7 @@ enum ReadKind { } pub impl Liveness { - fn check_ret(@self, id: node_id, sp: span, _fk: &visit::fn_kind, + fn check_ret(&self, id: node_id, sp: span, _fk: &visit::fn_kind, entry_ln: LiveNode) { if self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() { // if no_ret_var is live, then we fall off the end of the @@ -1629,11 +1576,11 @@ pub impl Liveness { } } - fn check_move_from_var(@self, ln: LiveNode, + fn check_move_from_var(&self, + ln: LiveNode, var: Variable, move_expr: @expr) { /*! - * * Checks whether `var` is live on entry to any of the * successors of `ln`. If it is, report an error. * `move_expr` is the expression which caused the variable @@ -1653,16 +1600,6 @@ pub impl Liveness { } } - fn consider_last_use(@self, expr: @expr, ln: LiveNode, var: Variable) { - debug!("consider_last_use(expr.id=%?, ln=%s, var=%s)", - expr.id, ln.to_str(), var.to_str()); - - match self.live_on_exit(ln, var) { - Some(_) => {} - None => self.ir.add_last_use(expr.id, var) - } - } - fn check_lvalue(@self, expr: @expr, vt: vt<@Liveness>) { match expr.node { expr_path(_) => { @@ -1679,7 +1616,7 @@ pub impl Liveness { self.warn_about_dead_assign(expr.span, expr.id, ln, var); } def => { - match relevant_def(def) { + match moves::moved_variable_node_id_from_def(def) { Some(nid) => { let ln = self.live_node(expr.id, expr.span); let var = self.variable(nid, expr.span); @@ -1699,14 +1636,14 @@ pub impl Liveness { } } - fn check_for_reassignments_in_pat(@self, pat: @pat, mutbl: bool) { + fn check_for_reassignments_in_pat(&self, pat: @pat, mutbl: bool) { do self.pat_bindings(pat) |ln, var, sp, id| { self.check_for_reassignment(ln, var, sp, if mutbl {Some(id)} else {None}); } } - fn check_for_reassignment(@self, ln: LiveNode, var: Variable, + fn check_for_reassignment(&self, ln: LiveNode, var: Variable, orig_span: span, mutbl: Option) { match self.assigned_on_exit(ln, var) { Some(ExprNode(span)) => { @@ -1731,7 +1668,7 @@ pub impl Liveness { } } - fn report_illegal_move(@self, lnk: LiveNodeKind, + fn report_illegal_move(&self, lnk: LiveNodeKind, var: Variable, move_expr: @expr) { // the only time that it is possible to have a moved variable @@ -1796,7 +1733,8 @@ pub impl Liveness { }; } - fn report_move_location(@self, move_expr: @expr, + fn report_move_location(&self, + move_expr: @expr, var: Variable, expr_descr: &str, pronoun: &str) { @@ -1810,7 +1748,8 @@ pub impl Liveness { ty_to_str(self.tcx, move_expr_ty))); } - fn report_illegal_read(@self, chk_span: span, + fn report_illegal_read(&self, + chk_span: span, lnk: LiveNodeKind, var: Variable, rk: ReadKind) { @@ -1841,12 +1780,12 @@ pub impl Liveness { } } - fn should_warn(@self, var: Variable) -> Option<@~str> { + fn should_warn(&self, var: Variable) -> Option<@~str> { let name = self.ir.variable_name(var); if name[0] == ('_' as u8) { None } else { Some(name) } } - fn warn_about_unused_args(@self, decl: &fn_decl, entry_ln: LiveNode) { + fn warn_about_unused_args(&self, decl: &fn_decl, entry_ln: LiveNode) { for decl.inputs.each |arg| { do pat_util::pat_bindings(self.tcx.def_map, arg.pat) |_bm, p_id, sp, _n| { @@ -1856,7 +1795,7 @@ pub impl Liveness { } } - fn warn_about_unused_or_dead_vars_in_pat(@self, pat: @pat) { + fn warn_about_unused_or_dead_vars_in_pat(&self, pat: @pat) { do self.pat_bindings(pat) |ln, var, sp, id| { if !self.warn_about_unused(sp, id, ln, var) { self.warn_about_dead_assign(sp, id, ln, var); @@ -1864,7 +1803,7 @@ pub impl Liveness { } } - fn warn_about_unused(@self, sp: span, id: node_id, + fn warn_about_unused(&self, sp: span, id: node_id, ln: LiveNode, var: Variable) -> bool { if !self.used_on_entry(ln, var) { for self.should_warn(var).each |name| { @@ -1894,7 +1833,7 @@ pub impl Liveness { return false; } - fn warn_about_dead_assign(@self, sp: span, id: node_id, + fn warn_about_dead_assign(&self, sp: span, id: node_id, ln: LiveNode, var: Variable) { if self.live_on_exit(ln, var).is_none() { for self.should_warn(var).each |name| { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 7fa198be1d47f..f525230664a21 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -48,7 +48,7 @@ use middle::ty; use middle::typeck; -use util::ppaux::{ty_to_str, region_to_str}; +use util::ppaux::{ty_to_str, region_to_str, Repr}; use util::common::indenter; use syntax::ast::{m_imm, m_const, m_mutbl}; @@ -58,50 +58,48 @@ use syntax::print::pprust; #[deriving(Eq)] pub enum categorization { - cat_rvalue, // result of eval'ing some misc expr - cat_special(special_kind), // - cat_local(ast::node_id), // local variable - cat_binding(ast::node_id), // pattern binding - cat_arg(ast::node_id), // formal argument - cat_stack_upvar(cmt), // upvar in stack closure - cat_deref(cmt, uint, ptr_kind), // deref of a ptr - cat_comp(cmt, comp_kind), // adjust to locate an internal component - cat_discr(cmt, ast::node_id), // match discriminant (see preserve()) - cat_self(ast::node_id), // explicit `self` + cat_rvalue, // result of eval'ing some misc expr + cat_static_item, + cat_implicit_self, + cat_copied_upvar(CopiedUpvar), // upvar copied into @fn or ~fn env + cat_stack_upvar(cmt), // by ref upvar from &fn + cat_local(ast::node_id), // local variable + cat_arg(ast::node_id, ast::rmode), // formal argument + cat_deref(cmt, uint, ptr_kind), // deref of a ptr + cat_interior(cmt, interior_kind), // something interior + cat_discr(cmt, ast::node_id), // match discriminant (see preserve()) + cat_self(ast::node_id), // explicit `self` +} + +#[deriving(Eq)] +struct CopiedUpvar { + upvar_id: ast::node_id, + onceness: ast::Onceness, } // different kinds of pointers: #[deriving(Eq)] pub enum ptr_kind { - uniq_ptr, + uniq_ptr(ast::mutability), gc_ptr(ast::mutability), region_ptr(ast::mutability, ty::Region), unsafe_ptr } -// I am coining the term "components" to mean "pieces of a data -// structure accessible without a dereference": +// We use the term "interior" to mean "something reachable from the +// base without a pointer dereference", e.g. a field #[deriving(Eq)] -pub enum comp_kind { - comp_tuple, // elt in a tuple - comp_anon_field, // anonymous field (in e.g. +pub enum interior_kind { + interior_tuple, // elt in a tuple + interior_anon_field, // anonymous field (in e.g. // struct Foo(int, int); - comp_variant(ast::def_id), // internals to a variant of given enum - comp_field(ast::ident, // name of field + interior_variant(ast::def_id), // internals to a variant of given enum + interior_field(ast::ident, // name of field ast::mutability), // declared mutability of field - comp_index(ty::t, // type of vec/str/etc being deref'd + interior_index(ty::t, // type of vec/str/etc being deref'd ast::mutability) // mutability of vec content } -// different kinds of expressions we might evaluate -#[deriving(Eq)] -pub enum special_kind { - sk_method, - sk_static_item, - sk_implicit_self, // old by-reference `self` - sk_heap_upvar -} - #[deriving(Eq)] pub enum MutabilityCategory { McImmutable, // Immutable. @@ -120,39 +118,29 @@ pub struct cmt_ { id: ast::node_id, // id of expr/pat producing this value span: span, // span of same expr/pat cat: categorization, // categorization of expr - lp: Option<@loan_path>, // loan path for expr, if any mutbl: MutabilityCategory, // mutability of expr as lvalue ty: ty::t // type of the expr } pub type cmt = @cmt_; -// a loan path is like a category, but it exists only when the data is -// interior to the stack frame. loan paths are used as the key to a -// map indicating what is borrowed at any point in time. -#[deriving(Eq)] -pub enum loan_path { - lp_local(ast::node_id), - lp_arg(ast::node_id), - lp_self, - lp_deref(@loan_path, ptr_kind), - lp_comp(@loan_path, comp_kind) -} - // We pun on *T to mean both actual deref of a ptr as well // as accessing of components: -pub enum deref_kind {deref_ptr(ptr_kind), deref_comp(comp_kind)} +pub enum deref_kind {deref_ptr(ptr_kind), deref_interior(interior_kind)} // Categorizes a derefable type. Note that we include vectors and strings as // derefable (we model an index as the combination of a deref and then a // pointer adjustment). pub fn opt_deref_kind(t: ty::t) -> Option { match ty::get(t).sty { - ty::ty_uniq(*) | + ty::ty_uniq(mt) => { + Some(deref_ptr(uniq_ptr(mt.mutbl))) + } + ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) | ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => { - Some(deref_ptr(uniq_ptr)) + Some(deref_ptr(uniq_ptr(m_imm))) } ty::ty_rptr(r, mt) | @@ -181,19 +169,19 @@ pub fn opt_deref_kind(t: ty::t) -> Option { } ty::ty_enum(did, _) => { - Some(deref_comp(comp_variant(did))) + Some(deref_interior(interior_variant(did))) } ty::ty_struct(_, _) => { - Some(deref_comp(comp_anon_field)) + Some(deref_interior(interior_anon_field)) } ty::ty_evec(mt, ty::vstore_fixed(_)) => { - Some(deref_comp(comp_index(t, mt.mutbl))) + Some(deref_interior(interior_index(t, mt.mutbl))) } ty::ty_estr(ty::vstore_fixed(_)) => { - Some(deref_comp(comp_index(t, m_imm))) + Some(deref_interior(interior_index(t, m_imm))) } _ => None @@ -338,21 +326,11 @@ pub impl MutabilityCategory { } } - fn to_user_str(&self) -> ~str { + fn to_user_str(&self) -> &'static str { match *self { - McDeclared | McInherited => ~"mutable", - McImmutable => ~"immutable", - McReadOnly => ~"const" - } - } -} - -pub impl loan_path { - fn node_id(&self) -> Option { - match *self { - lp_local(id) | lp_arg(id) => Some(id), - lp_deref(lp, _) | lp_comp(lp, _) => lp.node_id(), - lp_self => None + McDeclared | McInherited => "mutable", + McImmutable => "immutable", + McReadOnly => "const" } } } @@ -419,9 +397,9 @@ pub impl mem_categorization_ctxt { } ast::expr_field(base, f_name, _) => { - if self.method_map.contains_key(&expr.id) { - return self.cat_method_ref(expr, expr_ty); - } + // Method calls are now a special syntactic form, + // so `a.b` should always be a field. + assert!(!self.method_map.contains_key(&expr.id)); let base_cmt = self.cat_expr(base); self.cat_field(expr, base_cmt, f_name, expr.id) @@ -475,8 +453,7 @@ pub impl mem_categorization_ctxt { @cmt_ { id:id, span:span, - cat:cat_special(sk_static_item), - lp:None, + cat:cat_static_item, mutbl: McImmutable, ty:expr_ty } @@ -487,66 +464,71 @@ pub impl mem_categorization_ctxt { // stuff as `&const` and `&mut`? // m: mutability of the argument - // lp: loan path, must be none for aliasable things let m = if mutbl {McDeclared} else {McImmutable}; - let lp = Some(@lp_arg(vid)); + let mode = ty::resolved_mode(self.tcx, mode); @cmt_ { - id:id, - span:span, - cat:cat_arg(vid), - lp:lp, + id: id, + span: span, + cat: cat_arg(vid, mode), mutbl: m, ty:expr_ty } } ast::def_self(self_id, is_implicit) => { - let cat, loan_path; - if is_implicit { - cat = cat_special(sk_implicit_self); - loan_path = None; + let cat = if is_implicit { + cat_implicit_self } else { - cat = cat_self(self_id); - loan_path = Some(@lp_self); + cat_self(self_id) }; @cmt_ { id:id, span:span, cat:cat, - lp:loan_path, mutbl: McImmutable, ty:expr_ty } } - ast::def_upvar(_, inner, fn_node_id, _) => { - let ty = ty::node_id_to_type(self.tcx, fn_node_id); - let sigil = ty::ty_closure_sigil(ty); - match sigil { - ast::BorrowedSigil => { - let upcmt = self.cat_def(id, span, expr_ty, *inner); - @cmt_ { - id:id, - span:span, - cat:cat_stack_upvar(upcmt), - lp:upcmt.lp, - mutbl:upcmt.mutbl, - ty:upcmt.ty - } - } - ast::OwnedSigil | ast::ManagedSigil => { - // FIXME #2152 allow mutation of moved upvars - @cmt_ { - id:id, - span:span, - cat:cat_special(sk_heap_upvar), - lp:None, - mutbl:McImmutable, - ty:expr_ty - } - } - } + ast::def_upvar(upvar_id, inner, fn_node_id, _) => { + let ty = ty::node_id_to_type(self.tcx, fn_node_id); + match ty::get(ty).sty { + ty::ty_closure(ref closure_ty) => { + let sigil = closure_ty.sigil; + match sigil { + ast::BorrowedSigil => { + let upvar_cmt = + self.cat_def(id, span, expr_ty, *inner); + @cmt_ { + id:id, + span:span, + cat:cat_stack_upvar(upvar_cmt), + mutbl:upvar_cmt.mutbl.inherit(), + ty:upvar_cmt.ty + } + } + ast::OwnedSigil | ast::ManagedSigil => { + // FIXME #2152 allow mutation of moved upvars + @cmt_ { + id:id, + span:span, + cat:cat_copied_upvar(CopiedUpvar { + upvar_id: upvar_id, + onceness: closure_ty.onceness}), + mutbl:McImmutable, + ty:expr_ty + } + } + } + } + _ => { + self.tcx.sess.span_bug( + span, + fmt!("Upvar of non-closure %? - %s", + fn_node_id, ty.repr(self.tcx))); + } + } } ast::def_local(vid, mutbl) => { @@ -555,7 +537,6 @@ pub impl mem_categorization_ctxt { id:id, span:span, cat:cat_local(vid), - lp:Some(@lp_local(vid)), mutbl:m, ty:expr_ty } @@ -567,7 +548,6 @@ pub impl mem_categorization_ctxt { id:id, span:span, cat:cat_local(vid), - lp:Some(@lp_local(vid)), mutbl:McImmutable, ty:expr_ty } @@ -582,8 +562,7 @@ pub impl mem_categorization_ctxt { @cmt_ { id: arg.id(), span: arg.span(), - cat: cat_comp(cmt, comp_variant(enum_did)), - lp: cmt.lp.map(|l| @lp_comp(*l, comp_variant(enum_did)) ), + cat: cat_interior(cmt, interior_variant(enum_did)), mutbl: cmt.mutbl.inherit(), ty: self.tcx.ty(arg) } @@ -594,7 +573,6 @@ pub impl mem_categorization_ctxt { id:elt.id(), span:elt.span(), cat:cat_rvalue, - lp:None, mutbl:McImmutable, ty:expr_ty } @@ -606,9 +584,9 @@ pub impl mem_categorization_ctxt { /// or if the container is mutable. fn inherited_mutability(&self, base_m: MutabilityCategory, - comp_m: ast::mutability) -> MutabilityCategory + interior_m: ast::mutability) -> MutabilityCategory { - match comp_m { + match interior_m { m_imm => base_m.inherit(), m_const => McReadOnly, m_mutbl => McDeclared @@ -634,13 +612,11 @@ pub impl mem_categorization_ctxt { } }; let m = self.inherited_mutability(base_cmt.mutbl, f_mutbl); - let f_comp = comp_field(f_name, f_mutbl); - let lp = base_cmt.lp.map(|lp| @lp_comp(*lp, f_comp) ); + let f_interior = interior_field(f_name, f_mutbl); @cmt_ { id: node.id(), span: node.span(), - cat: cat_comp(base_cmt, f_comp), - lp:lp, + cat: cat_interior(base_cmt, f_interior), mutbl: m, ty: self.tcx.ty(node) } @@ -688,25 +664,10 @@ pub impl mem_categorization_ctxt { { match deref_kind(self.tcx, base_cmt.ty) { deref_ptr(ptr) => { - let lp = do base_cmt.lp.chain_ref |l| { - // Given that the ptr itself is loanable, we can - // loan out deref'd uniq ptrs or mut ptrs as the data - // they are the only way to mutably reach the data they - // point at. Other ptr types admit mutable aliases and - // are therefore not loanable. - match ptr { - uniq_ptr => Some(@lp_deref(*l, ptr)), - region_ptr(ast::m_mutbl, _) => { - Some(@lp_deref(*l, ptr)) - } - gc_ptr(*) | region_ptr(_, _) | unsafe_ptr => None - } - }; - // for unique ptrs, we inherit mutability from the // owning reference. let m = match ptr { - uniq_ptr => { + uniq_ptr(*) => { self.inherited_mutability(base_cmt.mutbl, mt.mutbl) } gc_ptr(*) | region_ptr(_, _) | unsafe_ptr => { @@ -718,20 +679,17 @@ pub impl mem_categorization_ctxt { id:node.id(), span:node.span(), cat:cat_deref(base_cmt, deref_cnt, ptr), - lp:lp, mutbl:m, ty:mt.ty } } - deref_comp(comp) => { - let lp = base_cmt.lp.map(|l| @lp_comp(*l, comp) ); + deref_interior(interior) => { let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl); @cmt_ { id:node.id(), span:node.span(), - cat:cat_comp(base_cmt, comp), - lp:lp, + cat:cat_interior(base_cmt, interior), mutbl:m, ty:mt.ty } @@ -754,17 +712,10 @@ pub impl mem_categorization_ctxt { return match deref_kind(self.tcx, base_cmt.ty) { deref_ptr(ptr) => { - // (a) the contents are loanable if the base is loanable - // and this is a *unique* vector - let deref_lp = match ptr { - uniq_ptr => {base_cmt.lp.map(|lp| @lp_deref(*lp, uniq_ptr))} - _ => {None} - }; - - // (b) for unique ptrs, we inherit mutability from the + // for unique ptrs, we inherit mutability from the // owning reference. let m = match ptr { - uniq_ptr => { + uniq_ptr(*) => { self.inherited_mutability(base_cmt.mutbl, mt.mutbl) } gc_ptr(_) | region_ptr(_, _) | unsafe_ptr => { @@ -772,37 +723,34 @@ pub impl mem_categorization_ctxt { } }; - // (c) the deref is explicit in the resulting cmt + // the deref is explicit in the resulting cmt let deref_cmt = @cmt_ { id:elt.id(), span:elt.span(), cat:cat_deref(base_cmt, 0u, ptr), - lp:deref_lp, mutbl:m, ty:mt.ty }; - comp(elt, deref_cmt, base_cmt.ty, m, mt) + interior(elt, deref_cmt, base_cmt.ty, m, mt) } - deref_comp(_) => { + deref_interior(_) => { // fixed-length vectors have no deref let m = self.inherited_mutability(base_cmt.mutbl, mt.mutbl); - comp(elt, base_cmt, base_cmt.ty, m, mt) + interior(elt, base_cmt, base_cmt.ty, m, mt) } }; - fn comp(elt: N, of_cmt: cmt, - vect: ty::t, mutbl: MutabilityCategory, - mt: ty::mt) -> cmt + fn interior(elt: N, of_cmt: cmt, + vect: ty::t, mutbl: MutabilityCategory, + mt: ty::mt) -> cmt { - let comp = comp_index(vect, mt.mutbl); - let index_lp = of_cmt.lp.map(|lp| @lp_comp(*lp, comp) ); + let interior = interior_index(vect, mt.mutbl); @cmt_ { id:elt.id(), span:elt.span(), - cat:cat_comp(of_cmt, comp), - lp:index_lp, + cat:cat_interior(of_cmt, interior), mutbl:mutbl, ty:mt.ty } @@ -815,8 +763,7 @@ pub impl mem_categorization_ctxt { @cmt_ { id: elt.id(), span: elt.span(), - cat: cat_comp(cmt, comp_tuple), - lp: cmt.lp.map(|l| @lp_comp(*l, comp_tuple) ), + cat: cat_interior(cmt, interior_tuple), mutbl: cmt.mutbl.inherit(), ty: self.tcx.ty(elt) } @@ -828,26 +775,12 @@ pub impl mem_categorization_ctxt { @cmt_ { id: elt.id(), span: elt.span(), - cat: cat_comp(cmt, comp_anon_field), - lp: cmt.lp.map(|l| @lp_comp(*l, comp_anon_field)), + cat: cat_interior(cmt, interior_anon_field), mutbl: cmt.mutbl.inherit(), ty: self.tcx.ty(elt) } } - fn cat_method_ref(&self, - expr: @ast::expr, - expr_ty: ty::t) -> cmt { - @cmt_ { - id:expr.id, - span:expr.span, - cat:cat_special(sk_method), - lp:None, - mutbl:McImmutable, - ty:expr_ty - } - } - fn cat_pattern(&self, cmt: cmt, pat: @ast::pat, @@ -890,7 +823,7 @@ pub impl mem_categorization_ctxt { let tcx = self.tcx; debug!("cat_pattern: id=%d pat=%s cmt=%s", pat.id, pprust::pat_to_str(pat, tcx.sess.intr()), - self.cmt_to_repr(cmt)); + cmt.repr(tcx)); let _i = indenter(); op(cmt, pat); @@ -986,29 +919,6 @@ pub impl mem_categorization_ctxt { } } - fn cat_to_repr(&self, cat: categorization) -> ~str { - match cat { - cat_special(sk_method) => ~"method", - cat_special(sk_static_item) => ~"static_item", - cat_special(sk_implicit_self) => ~"implicit-self", - cat_special(sk_heap_upvar) => ~"heap-upvar", - cat_stack_upvar(_) => ~"stack-upvar", - cat_rvalue => ~"rvalue", - cat_local(node_id) => fmt!("local(%d)", node_id), - cat_binding(node_id) => fmt!("binding(%d)", node_id), - cat_arg(node_id) => fmt!("arg(%d)", node_id), - cat_self(node_id) => fmt!("self(%d)", node_id), - cat_deref(cmt, derefs, ptr) => { - fmt!("%s->(%s, %u)", self.cat_to_repr(cmt.cat), - self.ptr_sigil(ptr), derefs) - } - cat_comp(cmt, comp) => { - fmt!("%s.%s", self.cat_to_repr(cmt.cat), *self.comp_to_repr(comp)) - } - cat_discr(cmt, _) => self.cat_to_repr(cmt.cat) - } - } - fn mut_to_str(&self, mutbl: ast::mutability) -> ~str { match mutbl { m_mutbl => ~"mutable", @@ -1017,84 +927,33 @@ pub impl mem_categorization_ctxt { } } - fn ptr_sigil(&self, ptr: ptr_kind) -> ~str { - match ptr { - uniq_ptr => ~"~", - gc_ptr(_) => ~"@", - region_ptr(_, _) => ~"&", - unsafe_ptr => ~"*" - } - } - - fn comp_to_repr(&self, comp: comp_kind) -> @~str { - match comp { - comp_field(fld, _) => self.tcx.sess.str_of(fld), - comp_index(*) => @~"[]", - comp_tuple => @~"()", - comp_anon_field => @~"", - comp_variant(_) => @~"" - } - } - - fn lp_to_str(&self, lp: @loan_path) -> ~str { - match *lp { - lp_local(node_id) => { - fmt!("local(%d)", node_id) - } - lp_arg(node_id) => { - fmt!("arg(%d)", node_id) - } - lp_self => ~"self", - lp_deref(lp, ptr) => { - fmt!("%s->(%s)", self.lp_to_str(lp), - self.ptr_sigil(ptr)) - } - lp_comp(lp, comp) => { - fmt!("%s.%s", self.lp_to_str(lp), - *self.comp_to_repr(comp)) - } - } - } - - fn cmt_to_repr(&self, cmt: cmt) -> ~str { - fmt!("{%s id:%d m:%? lp:%s ty:%s}", - self.cat_to_repr(cmt.cat), - cmt.id, - cmt.mutbl, - cmt.lp.map_default(~"none", |p| self.lp_to_str(*p) ), - ty_to_str(self.tcx, cmt.ty)) - } - fn cmt_to_str(&self, cmt: cmt) -> ~str { - let mut_str = cmt.mutbl.to_user_str(); match cmt.cat { - cat_special(sk_method) => ~"method", - cat_special(sk_static_item) => ~"static item", - cat_special(sk_implicit_self) => ~"self reference", - cat_special(sk_heap_upvar) => { + cat_static_item => ~"static item", + cat_implicit_self => ~"self reference", + cat_copied_upvar(_) => { ~"captured outer variable in a heap closure" } cat_rvalue => ~"non-lvalue", - cat_local(_) => mut_str + ~" local variable", - cat_binding(_) => ~"pattern binding", + cat_local(_) => ~"local variable", cat_self(_) => ~"self value", - cat_arg(_) => ~"argument", - cat_deref(_, _, pk) => fmt!("dereference of %s %s pointer", - mut_str, self.ptr_sigil(pk)), - cat_stack_upvar(_) => { - ~"captured outer " + mut_str + ~" variable in a stack closure" - } - cat_comp(_, comp_field(*)) => mut_str + ~" field", - cat_comp(_, comp_tuple) => ~"tuple content", - cat_comp(_, comp_anon_field) => ~"anonymous field", - cat_comp(_, comp_variant(_)) => ~"enum content", - cat_comp(_, comp_index(t, _)) => { + cat_arg(*) => ~"argument", + cat_deref(_, _, pk) => fmt!("dereference of %s pointer", + ptr_sigil(pk)), + cat_interior(_, interior_field(*)) => ~"field", + cat_interior(_, interior_tuple) => ~"tuple content", + cat_interior(_, interior_anon_field) => ~"anonymous field", + cat_interior(_, interior_variant(_)) => ~"enum content", + cat_interior(_, interior_index(t, _)) => { match ty::get(t).sty { - ty::ty_evec(*) => mut_str + ~" vec content", - ty::ty_estr(*) => mut_str + ~" str content", - _ => mut_str + ~" indexed content" + ty::ty_evec(*) => ~"vec content", + ty::ty_estr(*) => ~"str content", + _ => ~"indexed content" } } + cat_stack_upvar(_) => { + ~"captured outer variable" + } cat_discr(cmt, _) => { self.cmt_to_str(cmt) } @@ -1149,33 +1008,142 @@ pub fn field_mutbl(tcx: ty::ctxt, return None; } -pub impl categorization { - fn derefs_through_mutable_box(&const self) -> bool { - match *self { - cat_deref(_, _, gc_ptr(ast::m_mutbl)) => { - true +pub enum AliasableReason { + AliasableManaged(ast::mutability), + AliasableBorrowed(ast::mutability), + AliasableOther +} + +pub impl cmt_ { + fn guarantor(@self) -> cmt { + //! Returns `self` after stripping away any owned pointer derefs or + //! interior content. The return value is basically the `cmt` which + //! determines how long the value in `self` remains live. + + match self.cat { + cat_rvalue | + cat_static_item | + cat_implicit_self | + cat_copied_upvar(*) | + cat_local(*) | + cat_self(*) | + cat_arg(*) | + cat_deref(_, _, unsafe_ptr(*)) | + cat_deref(_, _, gc_ptr(*)) | + cat_deref(_, _, region_ptr(*)) => { + self } - cat_deref(subcmt, _, _) | - cat_comp(subcmt, _) | - cat_discr(subcmt, _) | - cat_stack_upvar(subcmt) => { - subcmt.cat.derefs_through_mutable_box() + cat_stack_upvar(b) | + cat_discr(b, _) | + cat_interior(b, _) | + cat_deref(b, _, uniq_ptr(*)) => { + b.guarantor() } + } + } + + fn is_freely_aliasable(&self) -> bool { + self.freely_aliasable().is_some() + } + + fn freely_aliasable(&self) -> Option { + //! True if this lvalue resides in an area that is + //! freely aliasable, meaning that rustc cannot track + //! the alias//es with precision. + + // Maybe non-obvious: copied upvars can only be considered + // non-aliasable in once closures, since any other kind can be + // aliased and eventually recused. + + match self.cat { + cat_copied_upvar(CopiedUpvar {onceness: ast::Once, _}) | + cat_rvalue(*) | + cat_local(*) | + cat_arg(_, ast::by_copy) | + cat_self(*) | + cat_deref(_, _, unsafe_ptr(*)) | // of course it is aliasable, but... + cat_deref(_, _, region_ptr(m_mutbl, _)) => { + None + } + + cat_copied_upvar(CopiedUpvar {onceness: ast::Many, _}) | + cat_static_item(*) | + cat_implicit_self(*) | + cat_arg(_, ast::by_ref) => { + Some(AliasableOther) + } + + cat_deref(_, _, gc_ptr(m)) => { + Some(AliasableManaged(m)) + } + + cat_deref(_, _, region_ptr(m @ m_const, _)) | + cat_deref(_, _, region_ptr(m @ m_imm, _)) => { + Some(AliasableBorrowed(m)) + } + + cat_stack_upvar(b) | + cat_deref(b, _, uniq_ptr(*)) | + cat_interior(b, _) | + cat_discr(b, _) => { + b.freely_aliasable() + } + } + } +} + +impl Repr for cmt { + fn repr(&self, tcx: ty::ctxt) -> ~str { + fmt!("{%s id:%d m:%? ty:%s}", + self.cat.repr(tcx), + self.id, + self.mutbl, + self.ty.repr(tcx)) + } +} + +impl Repr for categorization { + fn repr(&self, tcx: ty::ctxt) -> ~str { + match *self { + cat_static_item | + cat_implicit_self | cat_rvalue | - cat_special(*) | + cat_copied_upvar(*) | cat_local(*) | - cat_binding(*) | - cat_arg(*) | - cat_self(*) => { - false + cat_self(*) | + cat_arg(*) => fmt!("%?", *self), + cat_deref(cmt, derefs, ptr) => { + fmt!("%s->(%s, %u)", cmt.cat.repr(tcx), + ptr_sigil(ptr), derefs) + } + cat_interior(cmt, interior) => { + fmt!("%s.%s", + cmt.cat.repr(tcx), + interior.repr(tcx)) } + cat_stack_upvar(cmt) | + cat_discr(cmt, _) => cmt.cat.repr(tcx) } } +} + +pub fn ptr_sigil(ptr: ptr_kind) -> ~str { + match ptr { + uniq_ptr(_) => ~"~", + gc_ptr(_) => ~"@", + region_ptr(_, _) => ~"&", + unsafe_ptr => ~"*" + } +} - fn is_mutable_box(&const self) -> bool { +impl Repr for interior_kind { + fn repr(&self, tcx: ty::ctxt) -> ~str { match *self { - cat_deref(_, _, gc_ptr(ast::m_mutbl)) => true, - _ => false + interior_field(fld, _) => copy *tcx.sess.str_of(fld), + interior_index(*) => ~"[]", + interior_tuple => ~"()", + interior_anon_field => ~"", + interior_variant(_) => ~"" } } } diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index fe1466bf808a3..d8a0e6bacf489 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -246,10 +246,19 @@ pub type MovesMap = @mut HashSet; * expression */ pub type VariableMovesMap = @mut HashMap; +/** + * Set of variable node-ids that are moved. + * + * Note: The `VariableMovesMap` stores expression ids that + * are moves, whereas this set stores the ids of the variables + * that are moved at some point */ +pub type MovedVariablesSet = @mut HashSet; + /** See the section Output on the module comment for explanation. */ pub struct MoveMaps { moves_map: MovesMap, variable_moves_map: VariableMovesMap, + moved_variables_set: MovedVariablesSet, capture_map: CaptureMap } @@ -279,13 +288,25 @@ pub fn compute_moves(tcx: ty::ctxt, move_maps: MoveMaps { moves_map: @mut HashSet::new(), variable_moves_map: @mut HashMap::new(), - capture_map: @mut HashMap::new() + capture_map: @mut HashMap::new(), + moved_variables_set: @mut HashSet::new() } }; visit::visit_crate(crate, visit_cx, visitor); return visit_cx.move_maps; } +pub fn moved_variable_node_id_from_def(def: def) -> Option { + match def { + def_binding(nid, _) | + def_arg(nid, _, _) | + def_local(nid, _) | + def_self(nid, _) => Some(nid), + + _ => None + } +} + // ______________________________________________________________________ // Expressions @@ -419,6 +440,11 @@ pub impl VisitContext { MoveInPart(entire_expr) => { self.move_maps.variable_moves_map.insert( expr.id, entire_expr); + + let def = *self.tcx.def_map.get(&expr.id); + for moved_variable_node_id_from_def(def).each |&id| { + self.move_maps.moved_variables_set.insert(id); + } } Read => {} MoveInWhole => { diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index f32998281711f..ea21ab0527b4d 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -47,59 +47,27 @@ The region maps encode information about region relationships. - the free region map is populated during type check as we check each function. See the function `relate_free_regions` for more information. +- `cleanup_scopes` includes scopes where trans cleanups occur + - this is intended to reflect the current state of trans, not + necessarily how I think things ought to work */ pub struct RegionMaps { priv scope_map: HashMap, priv free_region_map: HashMap, + priv cleanup_scopes: HashSet } -pub struct ctxt { +pub struct Context { sess: Session, def_map: resolve::DefMap, // Generated maps: region_maps: @mut RegionMaps, - // Generally speaking, expressions are parented to their innermost - // enclosing block. But some kinds of expressions serve as - // parents: calls, methods, etc. In addition, some expressions - // serve as parents by virtue of where they appear. For example, - // the condition in a while loop is always a parent. In those - // cases, we add the node id of such an expression to this set so - // that when we visit it we can view it as a parent. - root_exprs: @mut HashSet, - - // The parent scope is the innermost block, statement, call, or match - // expression during the execution of which the current expression - // will be evaluated. Generally speaking, the innermost parent - // scope is also the closest suitable ancestor in the AST tree. - // - // There is a subtle point concerning call arguments. Imagine - // you have a call: - // - // { // block a - // foo( // call b - // x, - // y); - // } - // - // In what lifetime are the expressions `x` and `y` evaluated? At - // first, I imagine the answer was the block `a`, as the arguments - // are evaluated before the call takes place. But this turns out - // to be wrong. The lifetime of the call must encompass the - // argument evaluation as well. - // - // The reason is that evaluation of an earlier argument could - // create a borrow which exists during the evaluation of later - // arguments. Consider this torture test, for example, - // - // fn test1(x: @mut ~int) { - // foo(&**x, *x = ~5); - // } - // - // Here, the first argument `&**x` will be a borrow of the `~int`, - // but the second argument overwrites that very value! Bad. - // (This test is borrowck-pure-scope-in-call.rs, btw) + // Scope where variables should be parented to + var_parent: parent, + + // Innermost enclosing expression parent: parent, } @@ -128,10 +96,22 @@ pub impl RegionMaps { sup: ast::node_id) { debug!("record_parent(sub=%?, sup=%?)", sub, sup); + assert!(sub != sup); self.scope_map.insert(sub, sup); } + pub fn record_cleanup_scope(&mut self, + scope_id: ast::node_id) + { + //! Records that a scope is a CLEANUP SCOPE. This is invoked + //! from within regionck. We wait until regionck because we do + //! not know which operators are overloaded until that point, + //! and only overloaded operators result in cleanup scopes. + + self.cleanup_scopes.insert(scope_id); + } + fn opt_encl_scope(&self, id: ast::node_id) -> Option { @@ -151,6 +131,22 @@ pub impl RegionMaps { } } + fn is_cleanup_scope(&self, scope_id: ast::node_id) -> bool { + self.cleanup_scopes.contains(&scope_id) + } + + fn cleanup_scope(&self, + expr_id: ast::node_id) -> ast::node_id + { + //! Returns the scope when temps in expr will be cleaned up + + let mut id = self.encl_scope(expr_id); + while !self.cleanup_scopes.contains(&id) { + id = self.encl_scope(id); + } + return id; + } + fn encl_region(&self, id: ast::node_id) -> ty::Region { @@ -159,22 +155,38 @@ pub impl RegionMaps { ty::re_scope(self.encl_scope(id)) } - fn is_sub_scope(&self, - sub_scope: ast::node_id, - superscope: ast::node_id) -> bool + pub fn scopes_intersect(&self, + scope1: ast::node_id, + scope2: ast::node_id) -> bool + { + self.is_subscope_of(scope1, scope2) || self.is_subscope_of(scope2, scope1) + } + + fn is_subscope_of(&self, + subscope: ast::node_id, + superscope: ast::node_id) -> bool { /*! - * Returns true if `sub_scope` is equal to or is lexically + * Returns true if `subscope` is equal to or is lexically * nested inside `superscope` and false otherwise. */ - let mut sub_scope = sub_scope; - while superscope != sub_scope { - match self.scope_map.find(&sub_scope) { - None => return false, - Some(&scope) => sub_scope = scope + let mut s = subscope; + while superscope != s { + match self.scope_map.find(&s) { + None => { + debug!("is_subscope_of(%?, %?, s=%?)=false", + subscope, superscope, s); + + return false; + } + Some(&scope) => s = scope } } + + debug!("is_subscope_of(%?, %?)=true", + subscope, superscope); + return true; } @@ -239,11 +251,11 @@ pub impl RegionMaps { } (ty::re_scope(sub_scope), ty::re_scope(super_scope)) => { - self.is_sub_scope(sub_scope, super_scope) + self.is_subscope_of(sub_scope, super_scope) } (ty::re_scope(sub_scope), ty::re_free(ref fr)) => { - self.is_sub_scope(sub_scope, fr.scope_id) + self.is_subscope_of(sub_scope, fr.scope_id) } (ty::re_free(sub_fr), ty::re_free(super_fr)) => { @@ -301,6 +313,7 @@ pub impl RegionMaps { fn ancestors_of(self: &RegionMaps, scope: ast::node_id) -> ~[ast::node_id] { + // debug!("ancestors_of(scope=%d)", scope); let mut result = ~[scope]; let mut scope = scope; loop { @@ -311,13 +324,14 @@ pub impl RegionMaps { scope = superscope; } } + // debug!("ancestors_of_loop(scope=%d)", scope); } } } } /// Extracts that current parent from cx, failing if there is none. -pub fn parent_id(cx: ctxt, span: span) -> ast::node_id { +pub fn parent_id(cx: Context, span: span) -> ast::node_id { match cx.parent { None => { cx.sess.span_bug(span, ~"crate should not be parent here"); @@ -329,144 +343,137 @@ pub fn parent_id(cx: ctxt, span: span) -> ast::node_id { } /// Records the current parent (if any) as the parent of `child_id`. -pub fn record_parent(cx: ctxt, child_id: ast::node_id) { +pub fn parent_to_expr(cx: Context, child_id: ast::node_id) { for cx.parent.each |parent_id| { cx.region_maps.record_parent(child_id, *parent_id); } } -pub fn resolve_block(blk: &ast::blk, cx: ctxt, visitor: visit::vt) { +pub fn resolve_block(blk: &ast::blk, cx: Context, visitor: visit::vt) { // Record the parent of this block. - record_parent(cx, blk.node.id); + parent_to_expr(cx, blk.node.id); // Descend. - let new_cx: ctxt = ctxt {parent: Some(blk.node.id),.. cx}; + let new_cx = Context {var_parent: Some(blk.node.id), + parent: Some(blk.node.id), + ..cx}; visit::visit_block(blk, new_cx, visitor); } -pub fn resolve_arm(arm: &ast::arm, cx: ctxt, visitor: visit::vt) { +pub fn resolve_arm(arm: &ast::arm, cx: Context, visitor: visit::vt) { visit::visit_arm(arm, cx, visitor); } -pub fn resolve_pat(pat: @ast::pat, cx: ctxt, visitor: visit::vt) { - match pat.node { - ast::pat_ident(*) => { - let defn_opt = cx.def_map.find(&pat.id); - match defn_opt { - Some(&ast::def_variant(_,_)) => { - /* Nothing to do; this names a variant. */ - } - _ => { - /* This names a local. Bind it to the containing scope. */ - record_parent(cx, pat.id); - } - } - } - _ => { /* no-op */ } - } - +pub fn resolve_pat(pat: @ast::pat, cx: Context, visitor: visit::vt) { + assert!(cx.var_parent == cx.parent); + parent_to_expr(cx, pat.id); visit::visit_pat(pat, cx, visitor); } -pub fn resolve_stmt(stmt: @ast::stmt, cx: ctxt, visitor: visit::vt) { +pub fn resolve_stmt(stmt: @ast::stmt, cx: Context, visitor: visit::vt) { match stmt.node { - ast::stmt_decl(*) => { - visit::visit_stmt(stmt, cx, visitor); - } - // This code has to be kept consistent with trans::base::trans_stmt - ast::stmt_expr(_, stmt_id) | - ast::stmt_semi(_, stmt_id) => { - record_parent(cx, stmt_id); - let mut expr_cx = cx; - expr_cx.parent = Some(stmt_id); - visit::visit_stmt(stmt, expr_cx, visitor); - } - ast::stmt_mac(*) => cx.sess.bug(~"unexpanded macro") + ast::stmt_decl(*) => { + visit::visit_stmt(stmt, cx, visitor); + } + ast::stmt_expr(_, stmt_id) | + ast::stmt_semi(_, stmt_id) => { + parent_to_expr(cx, stmt_id); + let expr_cx = Context {parent: Some(stmt_id), ..cx}; + visit::visit_stmt(stmt, expr_cx, visitor); + } + ast::stmt_mac(*) => cx.sess.bug(~"unexpanded macro") } } -pub fn resolve_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt) { - record_parent(cx, expr.id); +pub fn resolve_expr(expr: @ast::expr, cx: Context, visitor: visit::vt) { + parent_to_expr(cx, expr.id); let mut new_cx = cx; + new_cx.parent = Some(expr.id); match expr.node { - // Calls or overloadable operators - // FIXME #3387 - // ast::expr_index(*) | ast::expr_binary(*) | - // ast::expr_unary(*) | - ast::expr_call(*) | ast::expr_method_call(*) => { - debug!("node %d: %s", expr.id, pprust::expr_to_str(expr, - cx.sess.intr())); - new_cx.parent = Some(expr.id); - } - ast::expr_match(*) => { - debug!("node %d: %s", expr.id, pprust::expr_to_str(expr, - cx.sess.intr())); - new_cx.parent = Some(expr.id); - } - ast::expr_while(cond, _) => { - new_cx.root_exprs.insert(cond.id); - } - _ => {} + ast::expr_assign_op(*) | ast::expr_index(*) | ast::expr_binary(*) | + ast::expr_unary(*) | ast::expr_call(*) | ast::expr_method_call(*) => { + // FIXME(#5074) Nested method calls + // + // The lifetimes for a call or method call look as follows: + // + // call.id + // - arg0.id + // - ... + // - argN.id + // - call.callee_id + // + // The idea is that call.callee_id represents *the time when + // the invoked function is actually running* and call.id + // represents *the time to prepare the arguments and make the + // call*. See the section "Borrows in Calls" borrowck/doc.rs + // for an extended explanantion of why this distinction is + // important. + // + // parent_to_expr(new_cx, expr.callee_id); + } + + ast::expr_match(*) => { + new_cx.var_parent = Some(expr.id); + } + + _ => {} }; - if new_cx.root_exprs.contains(&expr.id) { - new_cx.parent = Some(expr.id); - } visit::visit_expr(expr, new_cx, visitor); } pub fn resolve_local(local: @ast::local, - cx: ctxt, - visitor: visit::vt) { - record_parent(cx, local.node.id); + cx: Context, + visitor: visit::vt) { + assert!(cx.var_parent == cx.parent); + parent_to_expr(cx, local.node.id); visit::visit_local(local, cx, visitor); } -pub fn resolve_item(item: @ast::item, cx: ctxt, visitor: visit::vt) { +pub fn resolve_item(item: @ast::item, cx: Context, visitor: visit::vt) { // Items create a new outer block scope as far as we're concerned. - let new_cx: ctxt = ctxt {parent: None,.. cx}; + let new_cx = Context {var_parent: None, parent: None, ..cx}; visit::visit_item(item, new_cx, visitor); } pub fn resolve_fn(fk: &visit::fn_kind, decl: &ast::fn_decl, body: &ast::blk, - sp: span, + _sp: span, id: ast::node_id, - cx: ctxt, - visitor: visit::vt) { - let fn_cx = match *fk { - visit::fk_item_fn(*) | visit::fk_method(*) | - visit::fk_dtor(*) => { - // Top-level functions are a root scope. - ctxt {parent: Some(id),.. cx} - } - - visit::fk_anon(*) | visit::fk_fn_block(*) => { - // Closures continue with the inherited scope. - cx - } - }; - - // Record the ID of `self`. + cx: Context, + visitor: visit::vt) { + debug!("region::resolve_fn(id=%?, body.node.id=%?, cx.parent=%?)", + id, body.node.id, cx.parent); + + // The arguments and `self` are parented to the body of the fn. + let decl_cx = Context {parent: Some(body.node.id), + var_parent: Some(body.node.id), + ..cx}; match *fk { visit::fk_method(_, _, method) => { cx.region_maps.record_parent(method.self_id, body.node.id); } _ => {} } + visit::visit_fn_decl(decl, decl_cx, visitor); - debug!("visiting fn with body %d. cx.parent: %? \ - fn_cx.parent: %?", - body.node.id, cx.parent, fn_cx.parent); - - for decl.inputs.each |input| { - cx.region_maps.record_parent(input.id, body.node.id); - } - - visit::visit_fn(fk, decl, body, sp, id, fn_cx, visitor); + // The body of the fn itself is either a root scope (top-level fn) + // or it continues with the inherited scope (closures). + let body_cx = match *fk { + visit::fk_item_fn(*) | + visit::fk_method(*) | + visit::fk_dtor(*) => { + Context {parent: None, var_parent: None, ..cx} + } + visit::fk_anon(*) | + visit::fk_fn_block(*) => { + cx + } + }; + (visitor.visit_block)(body, body_cx, visitor); } pub fn resolve_crate(sess: Session, @@ -475,13 +482,14 @@ pub fn resolve_crate(sess: Session, { let region_maps = @mut RegionMaps { scope_map: HashMap::new(), - free_region_map: HashMap::new() + free_region_map: HashMap::new(), + cleanup_scopes: HashSet::new(), }; - let cx: ctxt = ctxt {sess: sess, - def_map: def_map, - region_maps: region_maps, - root_exprs: @mut HashSet::new(), - parent: None}; + let cx = Context {sess: sess, + def_map: def_map, + region_maps: region_maps, + parent: None, + var_parent: None}; let visitor = visit::mk_vt(@visit::Visitor { visit_block: resolve_block, visit_item: resolve_item, @@ -772,7 +780,8 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, pprust::ty_to_str(ty, sess.intr())); if cx.region_is_relevant(r) { - cx.add_rp(cx.item_id, cx.add_variance(rv_contravariant)) + let rv = cx.add_variance(rv_contravariant); + cx.add_rp(cx.item_id, rv) } } @@ -782,14 +791,14 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, match f.region { Some(_) => { if cx.region_is_relevant(f.region) { - cx.add_rp(cx.item_id, - cx.add_variance(rv_contravariant)) + let rv = cx.add_variance(rv_contravariant); + cx.add_rp(cx.item_id, rv) } } None => { if f.sigil == ast::BorrowedSigil && cx.anon_implies_rp { - cx.add_rp(cx.item_id, - cx.add_variance(rv_contravariant)); + let rv = cx.add_variance(rv_contravariant); + cx.add_rp(cx.item_id, rv) } } } @@ -820,7 +829,8 @@ pub fn determine_rp_in_ty(ty: @ast::Ty, debug!("reference to external, rp'd type %s", pprust::ty_to_str(ty, sess.intr())); if cx.region_is_relevant(path.rp) { - cx.add_rp(cx.item_id, cx.add_variance(variance)) + let rv = cx.add_variance(variance); + cx.add_rp(cx.item_id, rv) } } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 294a21fac2c23..ffc9d1488cf13 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -971,7 +971,7 @@ pub impl Resolver { module_.children.insert(name, child); return (child, new_parent); } - Some(child) => { + Some(&child) => { // Enforce the duplicate checking mode: // // * If we're requesting duplicate module checking, check that @@ -1033,7 +1033,7 @@ pub impl Resolver { *self.session.str_of(name))); } } - return (*child, new_parent); + return (child, new_parent); } } } @@ -1864,7 +1864,7 @@ pub impl Resolver { *self.session.str_of(target)); match module_.import_resolutions.find(&target) { - Some(resolution) => { + Some(&resolution) => { debug!("(building import directive) bumping \ reference"); resolution.outstanding_references += 1; @@ -2395,7 +2395,7 @@ pub impl Resolver { (*ident, new_import_resolution); } None => { /* continue ... */ } - Some(dest_import_resolution) => { + Some(&dest_import_resolution) => { // Merge the two import resolutions at a finer-grained // level. @@ -2433,8 +2433,8 @@ pub impl Resolver { module_.import_resolutions.insert (*ident, dest_import_resolution); } - Some(existing_import_resolution) => { - dest_import_resolution = *existing_import_resolution; + Some(&existing_import_resolution) => { + dest_import_resolution = existing_import_resolution; } } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 3755cca8c35e9..785bb3edc07cd 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1114,7 +1114,8 @@ pub fn compare_values(cx: block, pub fn store_non_ref_bindings(bcx: block, data: &ArmData, opt_temp_cleanups: Option<&mut ~[ValueRef]>) - -> block { + -> block +{ /*! * * For each copy/move binding, copy the value from the value @@ -1125,6 +1126,7 @@ pub fn store_non_ref_bindings(bcx: block, */ let mut bcx = bcx; + let mut opt_temp_cleanups = opt_temp_cleanups; for data.bindings_map.each_value |&binding_info| { match binding_info.trmode { TrByValue(is_move, lldest) => { @@ -1139,9 +1141,10 @@ pub fn store_non_ref_bindings(bcx: block, } }; - for opt_temp_cleanups.each |temp_cleanups| { + do opt_temp_cleanups.mutate |temp_cleanups| { add_clean_temp_mem(bcx, lldest, binding_info.ty); temp_cleanups.push(lldest); + temp_cleanups } } TrByRef | TrByImplicitRef => {} diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index efa10dfc2aa34..7be6bdb654e1f 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -391,14 +391,16 @@ pub fn get_tydesc_simple(ccx: @CrateContext, t: ty::t) -> ValueRef { pub fn get_tydesc(ccx: @CrateContext, t: ty::t) -> @mut tydesc_info { match ccx.tydescs.find(&t) { - Some(&inf) => inf, - _ => { - ccx.stats.n_static_tydescs += 1u; - let inf = glue::declare_tydesc(ccx, t); - ccx.tydescs.insert(t, inf); - inf - } + Some(&inf) => { + return inf; + } + _ => { } } + + ccx.stats.n_static_tydescs += 1u; + let inf = glue::declare_tydesc(ccx, t); + ccx.tydescs.insert(t, inf); + return inf; } pub fn set_optimize_for_size(f: ValueRef) { @@ -888,18 +890,18 @@ pub fn need_invoke(bcx: block) -> bool { let current = &mut *cur; let kind = &mut *current.kind; match *kind { - block_scope(ref mut inf) => { - for vec::each((*inf).cleanups) |cleanup| { - match *cleanup { - clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) => { - if cleanup_type == normal_exit_and_unwind { - return true; + block_scope(ref mut inf) => { + for vec::each((*inf).cleanups) |cleanup| { + match *cleanup { + clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) => { + if cleanup_type == normal_exit_and_unwind { + return true; + } + } } - } } } - } - _ => () + _ => () } cur = match current.parent { Some(next) => next, @@ -1011,12 +1013,12 @@ pub fn add_root_cleanup(bcx: block, ty=%s)", bcx.to_str(), root_info.scope, - root_info.freezes, + root_info.freeze, val_str(bcx.ccx().tn, root_loc), ppaux::ty_to_str(bcx.ccx().tcx, ty)); let bcx_scope = find_bcx_for_scope(bcx, root_info.scope); - if root_info.freezes { + if root_info.freeze.is_some() { add_clean_frozen_root(bcx_scope, root_loc, ty); } else { add_clean_temp_mem(bcx_scope, root_loc, ty); @@ -1029,6 +1031,12 @@ pub fn add_root_cleanup(bcx: block, Some(NodeInfo { id, _ }) if id == scope_id => { return bcx_sid } + + // NOTE This is messier than it ought to be and not really right + Some(NodeInfo { callee_id: Some(id), _ }) if id == scope_id => { + return bcx_sid + } + _ => { match bcx_sid.parent { None => bcx.tcx().sess.bug( @@ -2484,37 +2492,40 @@ pub fn get_dtor_symbol(ccx: @CrateContext, id: ast::node_id, substs: Option<@param_substs>) -> ~str { - let t = ty::node_id_to_type(ccx.tcx, id); - match ccx.item_symbols.find(&id) { - Some(s) => (/*bad*/copy *s), - None if substs.is_none() => { - let s = mangle_exported_name( - ccx, - vec::append(path, ~[path_name((ccx.names)(~"dtor"))]), - t); - // XXX: Bad copy, use `@str`? - ccx.item_symbols.insert(id, copy s); - s - } - None => { - // Monomorphizing, so just make a symbol, don't add - // this to item_symbols - match substs { - Some(ss) => { - let mono_ty = ty::subst_tps(ccx.tcx, ss.tys, ss.self_ty, t); - mangle_exported_name( - ccx, - vec::append(path, - ~[path_name((ccx.names)(~"dtor"))]), - mono_ty) - } - None => { - ccx.sess.bug(fmt!("get_dtor_symbol: not monomorphizing and \ - couldn't find a symbol for dtor %?", path)); - } - } - } - } + let t = ty::node_id_to_type(ccx.tcx, id); + match ccx.item_symbols.find(&id) { + Some(s) => { + return /*bad*/copy *s; + } + None => { } + } + + return if substs.is_none() { + let s = mangle_exported_name( + ccx, + vec::append(path, ~[path_name((ccx.names)(~"dtor"))]), + t); + // XXX: Bad copy, use `@str`? + ccx.item_symbols.insert(id, copy s); + s + } else { + // Monomorphizing, so just make a symbol, don't add + // this to item_symbols + match substs { + Some(ss) => { + let mono_ty = ty::subst_tps(ccx.tcx, ss.tys, ss.self_ty, t); + mangle_exported_name( + ccx, + vec::append(path, + ~[path_name((ccx.names)(~"dtor"))]), + mono_ty) + } + None => { + ccx.sess.bug(fmt!("get_dtor_symbol: not monomorphizing and \ + couldn't find a symbol for dtor %?", path)); + } + } + }; } pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef { diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index ad0fea3b4b4af..af00257fe1603 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -39,7 +39,6 @@ use middle::trans::monomorphize; use middle::trans::type_of; use middle::ty; use middle::typeck; -use util::common::indenter; use util::ppaux::Repr; use syntax::ast; @@ -689,7 +688,6 @@ pub fn trans_arg_expr(bcx: block, self_mode, arg_expr.repr(bcx.tcx()), ret_flag.map(|v| bcx.val_str(*v))); - let _indenter = indenter(); // translate the arg expr to a datum let arg_datumblock = match ret_flag { diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index f8fb0f4b7cf31..2ebd696dbfdef 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -574,13 +574,17 @@ pub trait get_node_info { impl get_node_info for @ast::expr { fn info(&self) -> Option { - Some(NodeInfo { id: self.id, span: self.span }) + Some(NodeInfo {id: self.id, + callee_id: Some(self.callee_id), + span: self.span}) } } impl get_node_info for ast::blk { fn info(&self) -> Option { - Some(NodeInfo { id: self.node.id, span: self.span }) + Some(NodeInfo {id: self.node.id, + callee_id: None, + span: self.span}) } } @@ -592,6 +596,7 @@ impl get_node_info for Option<@ast::expr> { pub struct NodeInfo { id: ast::node_id, + callee_id: Option, span: span } diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 25f34b8eaa9d1..3a331e8791ba2 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -195,18 +195,19 @@ pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef { match adj.autoref { None => { } Some(ref autoref) => { - assert!(autoref.region == ty::re_static); - assert!(autoref.mutbl != ast::m_mutbl); // Don't copy data to do a deref+ref. let llptr = match maybe_ptr { Some(ptr) => ptr, None => const_addr_of(cx, llconst) }; - match autoref.kind { - ty::AutoPtr => { + match *autoref { + ty::AutoUnsafe(m) | + ty::AutoPtr(ty::re_static, m) => { + assert!(m != ast::m_mutbl); llconst = llptr; } - ty::AutoBorrowVec => { + ty::AutoBorrowVec(ty::re_static, m) => { + assert!(m != ast::m_mutbl); let size = machine::llsize_of(cx, val_ty(llconst)); assert!(abi::slice_elt_base == 0); diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index fa27f652ac880..705d443b1155d 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -524,8 +524,8 @@ pub impl Datum { * case, we will call this function, which will stash a copy * away until we exit the scope `scope_id`. */ - debug!("root(scope_id=%?, freezes=%?, self=%?)", - root_info.scope, root_info.freezes, self.to_str(bcx.ccx())); + debug!("root(root_info=%?, self=%?)", + root_info, self.to_str(bcx.ccx())); if bcx.sess().trace() { trans_trace( @@ -539,7 +539,8 @@ pub impl Datum { add_root_cleanup(bcx, root_info, scratch.val, scratch.ty); // If we need to freeze the box, do that now. - if root_info.freezes { + if root_info.freeze.is_some() { + // NOTE distinguish the two kinds of freezing here callee::trans_lang_call( bcx, bcx.tcx().lang_items.borrow_as_imm_fn(), diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index f83562add3169..ac6fa7a5a1c4f 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -146,9 +146,9 @@ use middle::trans::type_of; use middle::ty; use middle::ty::struct_mutable_fields; use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowVecRef, AutoBorrowFn, - AutoDerefRef, AutoAddEnv}; + AutoDerefRef, AutoAddEnv, AutoUnsafe}; use util::common::indenter; -use util::ppaux::ty_to_str; +use util::ppaux::Repr; use core::cast::transmute; use core::hashmap::HashMap; @@ -201,6 +201,8 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { trans_to_datum_unadjusted(bcx, expr) }); + debug!("unadjusted datum: %s", datum.to_str(bcx.ccx())); + if adj.autoderefs > 0 { let DatumBlock { bcx: new_bcx, datum: new_datum } = datum.autoderef(bcx, expr.id, adj.autoderefs); @@ -209,25 +211,24 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { } datum = match adj.autoref { - None => datum, - Some(ref autoref) => { - match autoref.kind { - AutoPtr => { - unpack_datum!(bcx, auto_ref(bcx, datum)) - } - AutoBorrowVec => { - unpack_datum!(bcx, auto_slice(bcx, datum)) - } - AutoBorrowVecRef => { - unpack_datum!(bcx, auto_slice_and_ref(bcx, datum)) - } - AutoBorrowFn => { - // currently, all closure types are - // represented precisely the same, so no - // runtime adjustment is required: - datum - } - } + None => { + datum + } + Some(AutoUnsafe(*)) | // region + unsafe ptrs have same repr + Some(AutoPtr(*)) => { + unpack_datum!(bcx, auto_ref(bcx, datum)) + } + Some(AutoBorrowVec(*)) => { + unpack_datum!(bcx, auto_slice(bcx, datum)) + } + Some(AutoBorrowVecRef(*)) => { + unpack_datum!(bcx, auto_slice_and_ref(bcx, datum)) + } + Some(AutoBorrowFn(*)) => { + // currently, all closure types are + // represented precisely the same, so no + // runtime adjustment is required: + datum } }; @@ -273,7 +274,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { let tcx = bcx.tcx(); let closure_ty = expr_ty_adjusted(bcx, expr); - debug!("add_env(closure_ty=%s)", ty_to_str(tcx, closure_ty)); + debug!("add_env(closure_ty=%s)", closure_ty.repr(tcx)); let scratch = scratch_datum(bcx, closure_ty, false); let llfn = GEPi(bcx, scratch.val, [0u, abi::fn_field_code]); assert!(datum.appropriate_mode() == ByValue); @@ -612,7 +613,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, let sigil = ty::ty_closure_sigil(expr_ty); debug!("translating fn_block %s with type %s", expr_to_str(expr, tcx.sess.intr()), - ty_to_str(tcx, expr_ty)); + expr_ty.repr(tcx)); return closure::trans_expr_fn(bcx, sigil, decl, body, expr.id, expr.id, None, dest); @@ -1088,6 +1089,9 @@ pub fn trans_local_var(bcx: block, def: ast::def) -> Datum { } }; + debug!("def_self() reference, self_info.t=%s", + self_info.t.repr(bcx.tcx())); + // This cast should not be necessary. We should cast self *once*, // but right now this conflicts with default methods. let real_self_ty = monomorphize_type(bcx, self_info.t); @@ -1151,7 +1155,7 @@ pub fn with_field_tys(tcx: ty::ctxt, tcx.sess.bug(fmt!( "cannot get field types from the enum type %s \ without a node ID", - ty_to_str(tcx, ty))); + ty.repr(tcx))); } Some(node_id) => { match *tcx.def_map.get(&node_id) { @@ -1173,7 +1177,7 @@ pub fn with_field_tys(tcx: ty::ctxt, _ => { tcx.sess.bug(fmt!( "cannot get field types from the type %s", - ty_to_str(tcx, ty))); + ty.repr(tcx))); } } } diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index 7a7f03c2273e1..40b7a444a3e97 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -29,26 +29,33 @@ pub fn maybe_instantiate_inline(ccx: @CrateContext, fn_id: ast::def_id, -> ast::def_id { let _icx = ccx.insn_ctxt("maybe_instantiate_inline"); match ccx.external.find(&fn_id) { - Some(&Some(node_id)) => { - // Already inline - debug!("maybe_instantiate_inline(%s): already inline as node id %d", - ty::item_path_str(ccx.tcx, fn_id), node_id); - local_def(node_id) - } - Some(&None) => fn_id, // Not inlinable - None => { // Not seen yet - match csearch::maybe_get_item_ast( + Some(&Some(node_id)) => { + // Already inline + debug!("maybe_instantiate_inline(%s): already inline as node id %d", + ty::item_path_str(ccx.tcx, fn_id), node_id); + return local_def(node_id); + } + Some(&None) => { + return fn_id; // Not inlinable + } + None => { + // Not seen yet + } + } + + let csearch_result = + csearch::maybe_get_item_ast( ccx.tcx, fn_id, |a,b,c,d| { astencode::decode_inlined_item(a, b, ccx.maps, /*bad*/ copy c, d) - }) { - - csearch::not_found => { + }); + return match csearch_result { + csearch::not_found => { ccx.external.insert(fn_id, None); fn_id - } - csearch::found(ast::ii_item(item)) => { + } + csearch::found(ast::ii_item(item)) => { ccx.external.insert(fn_id, Some(item.id)); ccx.stats.n_inlines += 1; if translate { trans_item(ccx, item); } @@ -122,8 +129,6 @@ pub fn maybe_instantiate_inline(ccx: @CrateContext, fn_id: ast::def_id, ccx.external.insert(fn_id, Some((*dtor).node.id)); local_def((*dtor).node.id) } - } - } - } + }; } diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 90f9f93be2b48..86b087b937f25 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -44,6 +44,11 @@ pub fn trans_impl(ccx: @CrateContext, path: path, name: ast::ident, methods: &[@ast::method], generics: &ast::Generics, self_ty: Option, id: ast::node_id) { let _icx = ccx.insn_ctxt("impl::trans_impl"); + let tcx = ccx.tcx; + + debug!("trans_impl(path=%s, name=%s, self_ty=%s, id=%?)", + path.repr(tcx), name.repr(tcx), self_ty.repr(tcx), id); + if !generics.ty_params.is_empty() { return; } let sub_path = vec::append_one(path, path_name(name)); for vec::each(methods) |method| { diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 72ad6dde4f17d..98db829370c0c 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -137,6 +137,9 @@ pub fn monomorphic_fn(ccx: @CrateContext, ast_map::node_local(*) => { ccx.tcx.sess.bug(~"Can't monomorphize a local") } + ast_map::node_callee_scope(*) => { + ccx.tcx.sess.bug(~"Can't monomorphize a callee-scope") + } ast_map::node_struct_ctor(_, i, pt) => (pt, i.ident, i.span) }; @@ -279,6 +282,7 @@ pub fn monomorphic_fn(ccx: @CrateContext, ast_map::node_trait_method(*) | ast_map::node_arg(*) | ast_map::node_block(*) | + ast_map::node_callee_scope(*) | ast_map::node_local(*) => { ccx.tcx.sess.bug(fmt!("Can't monomorphize a %?", map_node)) } diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs index 3ccef0dbc4aca..a446408d00a10 100644 --- a/src/librustc/middle/trans/reachable.rs +++ b/src/librustc/middle/trans/reachable.rs @@ -42,19 +42,19 @@ pub fn find_reachable(crate_mod: &_mod, exp_map2: resolve::ExportMap2, tcx: ty::ctxt, method_map: typeck::method_map) -> map { let mut rmap = HashSet::new(); { - let cx = ctx { + let mut cx = @mut ctx { exp_map2: exp_map2, tcx: tcx, method_map: method_map, rmap: &mut rmap }; - traverse_public_mod(&cx, ast::crate_node_id, crate_mod); - traverse_all_resources_and_impls(&cx, crate_mod); + traverse_public_mod(cx, ast::crate_node_id, crate_mod); + traverse_all_resources_and_impls(cx, crate_mod); } return @rmap; } -fn traverse_exports(cx: &ctx, mod_id: node_id) -> bool { +fn traverse_exports(cx: @mut ctx, mod_id: node_id) -> bool { let mut found_export = false; match cx.exp_map2.find(&mod_id) { Some(ref exp2s) => { @@ -68,23 +68,25 @@ fn traverse_exports(cx: &ctx, mod_id: node_id) -> bool { return found_export; } -fn traverse_def_id(cx: &ctx, did: def_id) { +fn traverse_def_id(cx: @mut ctx, did: def_id) { if did.crate != local_crate { return; } match cx.tcx.items.find(&did.node) { None => (), // This can happen for self, for example Some(&ast_map::node_item(item, _)) => traverse_public_item(cx, item), Some(&ast_map::node_method(_, impl_id, _)) => traverse_def_id(cx, impl_id), Some(&ast_map::node_foreign_item(item, _, _, _)) => { + let cx = &mut *cx; // NOTE reborrow @mut cx.rmap.insert(item.id); } Some(&ast_map::node_variant(ref v, _, _)) => { + let cx = &mut *cx; // NOTE reborrow @mut cx.rmap.insert(v.node.id); } _ => () } } -fn traverse_public_mod(cx: &ctx, mod_id: node_id, m: &_mod) { +fn traverse_public_mod(cx: @mut ctx, mod_id: node_id, m: &_mod) { if !traverse_exports(cx, mod_id) { // No exports, so every local item is exported for m.items.each |item| { @@ -93,17 +95,21 @@ fn traverse_public_mod(cx: &ctx, mod_id: node_id, m: &_mod) { } } -fn traverse_public_item(cx: &ctx, item: @item) { - // FIXME #6021: naming rmap shouldn't be necessary - let rmap: &mut HashSet = cx.rmap; - if rmap.contains(&item.id) { return; } - rmap.insert(item.id); +fn traverse_public_item(cx: @mut ctx, item: @item) { + { + // FIXME #6021: naming rmap shouldn't be necessary + let cx = &mut *cx; + let rmap: &mut HashSet = cx.rmap; + if rmap.contains(&item.id) { return; } + rmap.insert(item.id); + } + match item.node { item_mod(ref m) => traverse_public_mod(cx, item.id, m), item_foreign_mod(ref nm) => { if !traverse_exports(cx, item.id) { for nm.items.each |item| { - cx.rmap.insert(item.id); + (&mut *cx).rmap.insert(item.id); // NOTE reborrow @mut } } } @@ -119,17 +125,17 @@ fn traverse_public_item(cx: &ctx, item: @item) { m.generics.ty_params.len() > 0u || attr::find_inline_attr(m.attrs) != attr::ia_none { - cx.rmap.insert(m.id); + (&mut *cx).rmap.insert(m.id); // NOTE reborrow @mut traverse_inline_body(cx, &m.body); } } } item_struct(ref struct_def, ref generics) => { for struct_def.ctor_id.each |&ctor_id| { - cx.rmap.insert(ctor_id); + (&mut *cx).rmap.insert(ctor_id); // NOTE reborrow @mut } for struct_def.dtor.each |dtor| { - cx.rmap.insert(dtor.node.id); + (&mut *cx).rmap.insert(dtor.node.id); if generics.ty_params.len() > 0u || attr::find_inline_attr(dtor.node.attrs) != attr::ia_none { @@ -148,11 +154,13 @@ fn traverse_public_item(cx: &ctx, item: @item) { } } -fn traverse_ty<'a, 'b>(ty: @Ty, cx: &'b ctx<'a>, v: visit::vt<&'b ctx<'a>>) { - // FIXME #6021: naming rmap shouldn't be necessary - let rmap: &mut HashSet = cx.rmap; - if rmap.contains(&ty.id) { return; } - rmap.insert(ty.id); +fn traverse_ty<'a>(ty: @Ty, cx: @mut ctx<'a>, v: visit::vt<@mut ctx<'a>>) { + { + // FIXME #6021: naming rmap shouldn't be necessary + let cx = &mut *cx; + if cx.rmap.contains(&ty.id) { return; } + cx.rmap.insert(ty.id); + } match ty.node { ty_path(p, p_id) => { @@ -171,9 +179,9 @@ fn traverse_ty<'a, 'b>(ty: @Ty, cx: &'b ctx<'a>, v: visit::vt<&'b ctx<'a>>) { } } -fn traverse_inline_body(cx: &ctx, body: &blk) { - fn traverse_expr<'a, 'b>(e: @expr, cx: &'b ctx<'a>, - v: visit::vt<&'b ctx<'a>>) { +fn traverse_inline_body(cx: @mut ctx, body: &blk) { + fn traverse_expr<'a>(e: @expr, cx: @mut ctx<'a>, + v: visit::vt<@mut ctx<'a>>) { match e.node { expr_path(_) => { match cx.tcx.def_map.find(&e.id) { @@ -218,7 +226,7 @@ fn traverse_inline_body(cx: &ctx, body: &blk) { // Don't ignore nested items: for example if a generic fn contains a // generic impl (as in deque::create), we need to monomorphize the // impl as well - fn traverse_item(i: @item, cx: &ctx, _v: visit::vt<&ctx>) { + fn traverse_item(i: @item, cx: @mut ctx, _v: visit::vt<@mut ctx>) { traverse_public_item(cx, i); } visit::visit_block(body, cx, visit::mk_vt(@visit::Visitor { @@ -228,7 +236,7 @@ fn traverse_inline_body(cx: &ctx, body: &blk) { })); } -fn traverse_all_resources_and_impls(cx: &ctx, crate_mod: &_mod) { +fn traverse_all_resources_and_impls(cx: @mut ctx, crate_mod: &_mod) { visit::visit_mod( crate_mod, codemap::dummy_sp(), diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c7fb1e94adf4c..28705ac49320a 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -183,26 +183,21 @@ pub struct AutoDerefRef { #[auto_encode] #[auto_decode] -pub struct AutoRef { - kind: AutoRefKind, - region: Region, - mutbl: ast::mutability -} - -#[auto_encode] -#[auto_decode] -pub enum AutoRefKind { +pub enum AutoRef { /// Convert from T to &T - AutoPtr, + AutoPtr(Region, ast::mutability), /// Convert from @[]/~[]/&[] to &[] (or str) - AutoBorrowVec, + AutoBorrowVec(Region, ast::mutability), /// Convert from @[]/~[]/&[] to &&[] (or str) - AutoBorrowVecRef, + AutoBorrowVecRef(Region, ast::mutability), /// Convert from @fn()/~fn()/&fn() to &fn() - AutoBorrowFn + AutoBorrowFn(Region), + + /// Convert from T to *T + AutoUnsafe(ast::mutability) } // Stores information about provided methods (a.k.a. default methods) in @@ -432,11 +427,20 @@ pub enum Region { /// A concrete region naming some expression within the current function. re_scope(node_id), - /// Static data that has an "infinite" lifetime. + /// Static data that has an "infinite" lifetime. Top in the region lattice. re_static, /// A region variable. Should not exist after typeck. - re_infer(InferRegion) + re_infer(InferRegion), + + /// Empty lifetime is for data that is never accessed. + /// Bottom in the region lattice. We treat re_empty somewhat + /// specially; at least right now, we do not generate instances of + /// it during the GLB computations, but rather + /// generate an error instead. This is to improve error messages. + /// The only way to get an instance of re_empty is to have a region + /// variable with no constraints. + re_empty, } pub impl Region { @@ -2874,6 +2878,17 @@ pub fn ty_region(tcx: ctxt, } } +pub fn replace_fn_sig(cx: ctxt, fsty: &sty, new_sig: FnSig) -> t { + match *fsty { + ty_bare_fn(ref f) => mk_bare_fn(cx, BareFnTy {sig: new_sig, ..*f}), + ty_closure(ref f) => mk_closure(cx, ClosureTy {sig: new_sig, ..*f}), + ref s => { + cx.sess.bug( + fmt!("ty_fn_sig() called on non-fn type: %?", s)); + } + } +} + pub fn replace_closure_return_type(tcx: ctxt, fn_type: t, ret_type: t) -> t { /*! * @@ -2993,26 +3008,26 @@ pub fn adjust_ty(cx: ctxt, match adj.autoref { None => adjusted_ty, Some(ref autoref) => { - match autoref.kind { - AutoPtr => { - mk_rptr(cx, autoref.region, - mt {ty: adjusted_ty, - mutbl: autoref.mutbl}) + match *autoref { + AutoPtr(r, m) => { + mk_rptr(cx, r, mt {ty: adjusted_ty, mutbl: m}) } - AutoBorrowVec => { - borrow_vec(cx, span, autoref, adjusted_ty) + AutoBorrowVec(r, m) => { + borrow_vec(cx, span, r, m, adjusted_ty) } - AutoBorrowVecRef => { - adjusted_ty = borrow_vec(cx, span, autoref, - adjusted_ty); - mk_rptr(cx, autoref.region, - mt {ty: adjusted_ty, mutbl: ast::m_imm}) + AutoBorrowVecRef(r, m) => { + adjusted_ty = borrow_vec(cx, span, r, m, adjusted_ty); + mk_rptr(cx, r, mt {ty: adjusted_ty, mutbl: ast::m_imm}) } - AutoBorrowFn => { - borrow_fn(cx, span, autoref, adjusted_ty) + AutoBorrowFn(r) => { + borrow_fn(cx, span, r, adjusted_ty) + } + + AutoUnsafe(m) => { + mk_ptr(cx, mt {ty: adjusted_ty, mutbl: m}) } } } @@ -3021,15 +3036,15 @@ pub fn adjust_ty(cx: ctxt, }; fn borrow_vec(cx: ctxt, span: span, - autoref: &AutoRef, ty: ty::t) -> ty::t { + r: Region, m: ast::mutability, + ty: ty::t) -> ty::t { match get(ty).sty { ty_evec(mt, _) => { - ty::mk_evec(cx, mt {ty: mt.ty, mutbl: autoref.mutbl}, - vstore_slice(autoref.region)) + ty::mk_evec(cx, mt {ty: mt.ty, mutbl: m}, vstore_slice(r)) } ty_estr(_) => { - ty::mk_estr(cx, vstore_slice(autoref.region)) + ty::mk_estr(cx, vstore_slice(r)) } ref s => { @@ -3041,13 +3056,12 @@ pub fn adjust_ty(cx: ctxt, } } - fn borrow_fn(cx: ctxt, span: span, - autoref: &AutoRef, ty: ty::t) -> ty::t { + fn borrow_fn(cx: ctxt, span: span, r: Region, ty: ty::t) -> ty::t { match get(ty).sty { ty_closure(ref fty) => { ty::mk_closure(cx, ClosureTy { sigil: BorrowedSigil, - region: autoref.region, + region: r, ..copy *fty }) } @@ -3062,6 +3076,18 @@ pub fn adjust_ty(cx: ctxt, } } +pub impl AutoRef { + fn map_region(&self, f: &fn(Region) -> Region) -> AutoRef { + match *self { + ty::AutoPtr(r, m) => ty::AutoPtr(f(r), m), + ty::AutoBorrowVec(r, m) => ty::AutoBorrowVec(f(r), m), + ty::AutoBorrowVecRef(r, m) => ty::AutoBorrowVecRef(f(r), m), + ty::AutoBorrowFn(r) => ty::AutoBorrowFn(f(r)), + ty::AutoUnsafe(m) => ty::AutoUnsafe(m), + } + } +} + pub struct ParamsTy { params: ~[t], ty: t @@ -3986,7 +4012,7 @@ pub fn lookup_field_type(tcx: ctxt, } else { match tcx.tcache.find(&id) { - Some(tpt) => tpt.ty, + Some(&ty_param_bounds_and_ty {ty, _}) => ty, None => { let tpt = csearch::get_field_type(tcx, struct_id, id); tcx.tcache.insert(id, tpt); diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 7f0066a1aa272..0c9b61164d231 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -118,8 +118,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, // Assign the pattern the type of the *enum*, not the variant. let enum_tpt = ty::lookup_item_type(tcx, enm); - instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id, - pcx.block_region); + instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id); // check that the type of the value being matched is a subtype // of the type of the pattern: @@ -159,8 +158,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, } else { ctor_tpt }; - instantiate_path(pcx.fcx, path, struct_tpt, pat.span, pat.id, - pcx.block_region); + instantiate_path(pcx.fcx, path, struct_tpt, pat.span, pat.id); // Check that the type of the value being matched is a subtype of // the type of the pattern. diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index fb5b53d9400fb..0cc2ddd32b46a 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -119,7 +119,8 @@ pub fn lookup( // In a call `a.b::(...)`: expr: @ast::expr, // The expression `a.b(...)`. self_expr: @ast::expr, // The expression `a`. - callee_id: node_id, // Where to store `a.b`'s type + callee_id: node_id, /* Where to store `a.b`'s type, + * also the scope of the call */ m_name: ast::ident, // The ident `b`. self_ty: ty::t, // The type of `a`. supplied_tps: &[ty::t], // The list of types X, Y, ... . @@ -127,7 +128,7 @@ pub fn lookup( check_traits: CheckTraitsFlag, // Whether we check traits only. autoderef_receiver: AutoderefReceiverFlag) -> Option { - let mut impl_dups = HashSet::new(); + let mut impl_dups = @mut HashSet::new(); let lcx = LookupContext { fcx: fcx, expr: expr, @@ -135,7 +136,7 @@ pub fn lookup( callee_id: callee_id, m_name: m_name, supplied_tps: supplied_tps, - impl_dups: &mut impl_dups, + impl_dups: impl_dups, inherent_candidates: @mut ~[], extension_candidates: @mut ~[], deref_args: deref_args, @@ -154,7 +155,7 @@ pub struct LookupContext<'self> { callee_id: node_id, m_name: ast::ident, supplied_tps: &'self [ty::t], - impl_dups: &'self mut HashSet, + impl_dups: @mut HashSet, inherent_candidates: @mut ~[Candidate], extension_candidates: @mut ~[Candidate], deref_args: check::DerefArgs, @@ -640,7 +641,7 @@ pub impl<'self> LookupContext<'self> { /*! * * In the event that we are invoking a method with a receiver - * of a linear borrowed type like `&mut T` or `&mut [T]`, + * of a borrowed type like `&T`, `&mut T`, or `&mut [T]`, * we will "reborrow" the receiver implicitly. For example, if * you have a call `r.inc()` and where `r` has type `&mut T`, * then we treat that like `(&mut *r).inc()`. This avoids @@ -657,26 +658,19 @@ pub impl<'self> LookupContext<'self> { let tcx = self.tcx(); return match ty::get(self_ty).sty { - ty::ty_rptr(_, self_mt) if self_mt.mutbl == m_mutbl => { - let region = self.infcx().next_region_var(self.expr.span, - self.expr.id); + ty::ty_rptr(_, self_mt) => { + let region = self.infcx().next_region_var_nb(self.expr.span); (ty::mk_rptr(tcx, region, self_mt), ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: autoderefs+1, - autoref: Some(ty::AutoRef {kind: AutoPtr, - region: region, - mutbl: self_mt.mutbl})})) + autoref: Some(ty::AutoPtr(region, self_mt.mutbl))})) } - ty::ty_evec(self_mt, vstore_slice(_)) - if self_mt.mutbl == m_mutbl => { - let region = self.infcx().next_region_var(self.expr.span, - self.expr.id); + ty::ty_evec(self_mt, vstore_slice(_)) => { + let region = self.infcx().next_region_var_nb(self.expr.span); (ty::mk_evec(tcx, self_mt, vstore_slice(region)), ty::AutoDerefRef(ty::AutoDerefRef { - autoderefs: autoderefs, - autoref: Some(ty::AutoRef {kind: AutoBorrowVec, - region: region, - mutbl: self_mt.mutbl})})) + autoderefs: autoderefs, + autoref: Some(ty::AutoBorrowVec(region, self_mt.mutbl))})) } _ => { (self_ty, @@ -793,7 +787,7 @@ pub impl<'self> LookupContext<'self> { fn search_for_some_kind_of_autorefd_method( &self, - kind: AutoRefKind, + kind: &fn(Region, ast::mutability) -> ty::AutoRef, autoderefs: uint, mutbls: &[ast::mutability], mk_autoref_ty: &fn(ast::mutability, ty::Region) -> ty::t) @@ -801,8 +795,7 @@ pub impl<'self> LookupContext<'self> { { // This is hokey. We should have mutability inference as a // variable. But for now, try &const, then &, then &mut: - let region = self.infcx().next_region_var(self.expr.span, - self.expr.id); + let region = self.infcx().next_region_var_nb(self.expr.span); for mutbls.each |mutbl| { let autoref_ty = mk_autoref_ty(*mutbl, region); match self.search_for_method(autoref_ty) { @@ -812,12 +805,7 @@ pub impl<'self> LookupContext<'self> { self.self_expr.id, @ty::AutoDerefRef(ty::AutoDerefRef { autoderefs: autoderefs, - autoref: Some(ty::AutoRef { - kind: kind, - region: region, - mutbl: *mutbl, - }), - })); + autoref: Some(kind(region, *mutbl))})); return Some(mme); } } @@ -1024,8 +1012,7 @@ pub impl<'self> LookupContext<'self> { let (_, opt_transformed_self_ty, fn_sig) = replace_bound_regions_in_fn_sig( tcx, @Nil, Some(transformed_self_ty), &bare_fn_ty.sig, - |_br| self.fcx.infcx().next_region_var( - self.expr.span, self.expr.id)); + |_br| self.fcx.infcx().next_region_var_nb(self.expr.span)); let transformed_self_ty = opt_transformed_self_ty.get(); let fty = ty::mk_bare_fn(tcx, ty::BareFnTy {sig: fn_sig, ..bare_fn_ty}); debug!("after replacing bound regions, fty=%s", self.ty_to_str(fty)); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index b9f3de873cf07..84fc40f6954a8 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -923,11 +923,9 @@ pub impl FnCtxt { fn region_var_if_parameterized(&self, rp: Option, - span: span, - lower_bound: ty::Region) + span: span) -> Option { - rp.map( - |_rp| self.infcx().next_region_var_with_lb(span, lower_bound)) + rp.map(|_rp| self.infcx().next_region_var_nb(span)) } fn type_error_message(&self, @@ -1108,8 +1106,7 @@ pub fn impl_self_ty(vcx: &VtableContext, }; let self_r = if region_param.is_some() { - Some(vcx.infcx.next_region_var(location_info.span, - location_info.id)) + Some(vcx.infcx.next_region_var_nb(location_info.span)) } else { None }; @@ -1317,9 +1314,18 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // that they appear in call position. check_expr(fcx, f); + // Store the type of `f` as the type of the callee + let fn_ty = fcx.expr_ty(f); + + // NOTE here we write the callee type before regions have been + // substituted; in the method case, we write the type after + // regions have been substituted. Methods are correct, but it + // is awkward to deal with this now. Best thing would I think + // be to just have a separate "callee table" that contains the + // FnSig and not a general purpose ty::t + fcx.write_ty(call_expr.callee_id, fn_ty); // Extract the function signature from `in_fty`. - let fn_ty = fcx.expr_ty(f); let fn_sty = structure_of(fcx, f.span, fn_ty); // FIXME(#3678) For now, do not permit calls to C abi functions. @@ -1356,7 +1362,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let (_, _, fn_sig) = replace_bound_regions_in_fn_sig( fcx.tcx(), @Nil, None, &fn_sig, - |_br| fcx.infcx().next_region_var(call_expr.span, call_expr.id)); + |_br| fcx.infcx().next_region_var_nb(call_expr.span)); // Call the generic checker. check_argument_types(fcx, call_expr.span, fn_sig.inputs, f, @@ -1936,9 +1942,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // Generate the struct type. let self_region = - fcx.region_var_if_parameterized(region_parameterized, - span, - ty::re_scope(id)); + fcx.region_var_if_parameterized(region_parameterized, span); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = substs { self_r: self_region, @@ -2024,9 +2028,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // Generate the enum type. let self_region = - fcx.region_var_if_parameterized(region_parameterized, - span, - ty::re_scope(id)); + fcx.region_var_if_parameterized(region_parameterized, span); let type_parameters = fcx.infcx().next_ty_vars(type_parameter_count); let substitutions = substs { self_r: self_region, @@ -2366,13 +2368,12 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // (and how long it is valid), which we don't know yet until type // inference is complete. // - // Therefore, here we simply generate a region variable with - // the current expression as a lower bound. The region - // inferencer will then select the ultimate value. Finally, - // borrowck is charged with guaranteeing that the value whose - // address was taken can actually be made to live as long as - // it needs to live. - let region = fcx.infcx().next_region_var(expr.span, expr.id); + // Therefore, here we simply generate a region variable. The + // region inferencer will then select the ultimate value. + // Finally, borrowck is charged with guaranteeing that the + // value whose address was taken can actually be made to live + // as long as it needs to live. + let region = fcx.infcx().next_region_var_nb(expr.span); let tm = ty::mt { ty: fcx.expr_ty(oprnd), mutbl: mutbl }; let oprnd_t = if ty::type_is_error(tm.ty) { @@ -2389,8 +2390,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, let defn = lookup_def(fcx, pth.span, id); let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn); - let region_lb = ty::re_scope(expr.id); - instantiate_path(fcx, pth, tpt, expr.span, expr.id, region_lb); + instantiate_path(fcx, pth, tpt, expr.span, expr.id); } ast::expr_inline_asm(ref ia) => { fcx.require_unsafe(expr.span, ~"use of inline assembly"); @@ -3258,8 +3258,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt, pth: @ast::Path, tpt: ty_param_bounds_and_ty, span: span, - node_id: ast::node_id, - region_lb: ty::Region) { + node_id: ast::node_id) { debug!(">>> instantiate_path"); let ty_param_count = tpt.generics.type_param_defs.len(); @@ -3285,8 +3284,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt, } } None => { // no lifetime parameter supplied, insert default - fcx.region_var_if_parameterized( - tpt.generics.region_param, span, region_lb) + fcx.region_var_if_parameterized(tpt.generics.region_param, span) } }; @@ -3370,7 +3368,7 @@ pub fn ast_expr_vstore_to_vstore(fcx: @mut FnCtxt, ast::expr_vstore_uniq => ty::vstore_uniq, ast::expr_vstore_box | ast::expr_vstore_mut_box => ty::vstore_box, ast::expr_vstore_slice | ast::expr_vstore_mut_slice => { - let r = fcx.infcx().next_region_var(e.span, e.id); + let r = fcx.infcx().next_region_var_nb(e.span); ty::vstore_slice(r) } } diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index cb2b854276d6f..1c35c911b14cd 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -28,16 +28,15 @@ this point a bit better. */ use middle::freevars::get_freevars; -use middle::pat_util::pat_bindings; use middle::ty::{re_scope}; use middle::ty; use middle::typeck::check::FnCtxt; -use middle::typeck::check::lookup_def; use middle::typeck::check::regionmanip::relate_nested_regions; use middle::typeck::infer::resolve_and_force_all_but_regions; use middle::typeck::infer::resolve_type; use util::ppaux::{note_and_explain_region, ty_to_str, region_to_str}; +use middle::pat_util; use syntax::ast::{ManagedSigil, OwnedSigil, BorrowedSigil}; use syntax::ast::{def_arg, def_binding, def_local, def_self, def_upvar}; @@ -73,7 +72,11 @@ fn encl_region_of_def(fcx: @mut FnCtxt, def: ast::def) -> ty::Region { } pub impl Rcx { - fn resolve_type(@mut self, unresolved_ty: ty::t) -> ty::t { + fn tcx(&self) -> ty::ctxt { + self.fcx.ccx.tcx + } + + fn resolve_type(&mut self, unresolved_ty: ty::t) -> ty::t { /*! * Try to resolve the type for the given node, returning * t_err if an error results. Note that we never care @@ -149,10 +152,17 @@ pub fn regionck_fn(fcx: @mut FnCtxt, blk: &ast::blk) { fn regionck_visitor() -> rvt { visit::mk_vt(@visit::Visitor {visit_item: visit_item, - visit_stmt: visit_stmt, visit_expr: visit_expr, - visit_block: visit_block, + + // NOTE this should be visit_pat + // but causes errors in formal + // arguments in closures due to + // #XYZ! + //visit_pat: visit_pat, + visit_arm: visit_arm, visit_local: visit_local, + + visit_block: visit_block, .. *visit::default_visitor()}) } @@ -160,44 +170,103 @@ fn visit_item(_item: @ast::item, _rcx: @mut Rcx, _v: rvt) { // Ignore items } -fn visit_local(l: @ast::local, rcx: @mut Rcx, v: rvt) { - // Check to make sure that the regions in all local variables are - // within scope. - // - // Note: we do this here rather than in visit_pat because we do - // not wish to constrain the regions in *patterns* in quite the - // same way. `visit_node()` guarantees that the region encloses - // the node in question, which ultimately constrains the regions - // in patterns to enclose the match expression as a whole. But we - // want them to enclose the *arm*. However, regions in patterns - // must either derive from the discriminant or a ref pattern: in - // the case of the discriminant, the regions will be constrained - // when the type of the discriminant is checked. In the case of a - // ref pattern, the variable is created with a suitable lower - // bound. - let e = rcx.errors_reported; - (v.visit_pat)(l.node.pat, rcx, v); - let def_map = rcx.fcx.ccx.tcx.def_map; - do pat_bindings(def_map, l.node.pat) |_bm, id, sp, _path| { - visit_node(id, sp, rcx); - } - if e != rcx.errors_reported { - return; // if decl has errors, skip initializer expr - } +fn visit_block(b: &ast::blk, rcx: @mut Rcx, v: rvt) { + rcx.fcx.tcx().region_maps.record_cleanup_scope(b.node.id); + visit::visit_block(b, rcx, v); +} - (v.visit_ty)(l.node.ty, rcx, v); - for l.node.init.each |i| { - (v.visit_expr)(*i, rcx, v); +fn visit_arm(arm: &ast::arm, rcx: @mut Rcx, v: rvt) { + // see above + for arm.pats.each |&p| { + constrain_bindings_in_pat(p, rcx); } + + visit::visit_arm(arm, rcx, v); } -fn visit_block(b: &ast::blk, rcx: @mut Rcx, v: rvt) { - visit::visit_block(b, rcx, v); +fn visit_local(l: @ast::local, rcx: @mut Rcx, v: rvt) { + // see above + constrain_bindings_in_pat(l.node.pat, rcx); + visit::visit_local(l, rcx, v); +} + +fn constrain_bindings_in_pat(pat: @ast::pat, rcx: @mut Rcx) { + let tcx = rcx.fcx.tcx(); + debug!("regionck::visit_pat(pat=%s)", pat.repr(tcx)); + do pat_util::pat_bindings(tcx.def_map, pat) |_, id, span, _| { + // If we have a variable that contains region'd data, that + // data will be accessible from anywhere that the variable is + // accessed. We must be wary of loops like this: + // + // // from src/test/compile-fail/borrowck-lend-flow.rs + // let mut v = ~3, w = ~4; + // let mut x = &mut w; + // loop { + // **x += 1; // (2) + // borrow(v); //~ ERROR cannot borrow + // x = &mut v; // (1) + // } + // + // Typically, we try to determine the region of a borrow from + // those points where it is dereferenced. In this case, one + // might imagine that the lifetime of `x` need only be the + // body of the loop. But of course this is incorrect because + // the pointer that is created at point (1) is consumed at + // point (2), meaning that it must be live across the loop + // iteration. The easiest way to guarantee this is to require + // that the lifetime of any regions that appear in a + // variable's type enclose at least the variable's scope. + + let encl_region = tcx.region_maps.encl_region(id); + constrain_regions_in_type_of_node(rcx, id, encl_region, span); + } } fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { debug!("regionck::visit_expr(e=%s)", rcx.fcx.expr_to_str(expr)); + let has_method_map = rcx.fcx.inh.method_map.contains_key(&expr.id); + + // Record cleanup scopes, which are used by borrowck to decide the + // maximum lifetime of a temporary rvalue. These were derived by + // examining where trans creates block scopes, not because this + // reflects some principled decision around temporary lifetimes. + // Ordinarily this would seem like something that should be setup + // in region, but we need to know which uses of operators are + // overloaded. See #3511. + let tcx = rcx.fcx.tcx(); + match expr.node { + ast::expr_index(*) | + ast::expr_binary(*) | + ast::expr_assign_op(*) | + ast::expr_unary(*) if has_method_map => { + tcx.region_maps.record_cleanup_scope(expr.id); + } + ast::expr_binary(ast::and, lhs, rhs) | + ast::expr_binary(ast::or, lhs, rhs) => { + tcx.region_maps.record_cleanup_scope(lhs.id); + tcx.region_maps.record_cleanup_scope(rhs.id); + } + ast::expr_call(*) | + ast::expr_method_call(*) => { + tcx.region_maps.record_cleanup_scope(expr.id); + } + ast::expr_match(_, ref arms) => { + tcx.region_maps.record_cleanup_scope(expr.id); + for arms.each |arm| { + for arm.guard.each |guard| { + tcx.region_maps.record_cleanup_scope(guard.id); + } + } + } + ast::expr_while(cond, ref body) => { + tcx.region_maps.record_cleanup_scope(cond.id); + tcx.region_maps.record_cleanup_scope(body.node.id); + } + _ => {} + } + + // Check any autoderefs or autorefs that appear. for rcx.fcx.inh.adjustments.find(&expr.id).each |&adjustment| { debug!("adjustment=%?", adjustment); match *adjustment { @@ -208,6 +277,13 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { constrain_derefs(rcx, expr, autoderefs, expr_ty); for opt_autoref.each |autoref| { guarantor::for_autoref(rcx, expr, autoderefs, autoref); + + // Require that the resulting region encompasses + // the current node. + // + // FIXME(#5074) remove to support nested method calls + constrain_regions_in_type_of_node( + rcx, expr.id, ty::re_scope(expr.id), expr.span); } } _ => {} @@ -215,58 +291,40 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { } match expr.node { - ast::expr_path(*) => { - // Avoid checking the use of local variables, as we - // already check their definitions. The def'n always - // encloses the use. So if the def'n is enclosed by the - // region, then the uses will also be enclosed (and - // otherwise, an error will have been reported at the - // def'n site). - match lookup_def(rcx.fcx, expr.span, expr.id) { - ast::def_local(*) | ast::def_arg(*) | - ast::def_upvar(*) => return, - _ => () - } + ast::expr_call(callee, ref args, _) => { + constrain_callee(rcx, expr, callee); + constrain_call(rcx, expr, None, *args, false); } - ast::expr_call(callee, ref args, _) => { - // Check for a.b() where b is a method. Ensure that - // any types in the callee are valid for the entire - // method call. - - // FIXME(#3387)--we should really invoke - // `constrain_auto_ref()` on all exprs. But that causes a - // lot of spurious errors because of how the region - // hierarchy is setup. - if rcx.fcx.inh.method_map.contains_key(&callee.id) { - match callee.node { - ast::expr_field(base, _, _) => { - constrain_auto_ref(rcx, base); - } - _ => { - // This can happen if you have code like - // (x[0])() where `x[0]` is overloaded. Just - // ignore it. - } - } - } else { - constrain_auto_ref(rcx, callee); - } + ast::expr_method_call(arg0, _, _, ref args, _) => { + constrain_call(rcx, expr, Some(arg0), *args, false); + } - for args.each |arg| { - constrain_auto_ref(rcx, *arg); - } + ast::expr_index(lhs, rhs) | + ast::expr_assign_op(_, lhs, rhs) | + ast::expr_binary(_, lhs, rhs) if has_method_map => { + // As `expr_method_call`, but the call is via an + // overloaded op. Note that we (sadly) currently use an + // implicit "by ref" sort of passing style here. This + // should be converted to an adjustment! + constrain_call(rcx, expr, Some(lhs), [rhs], true); } - ast::expr_method_call(rcvr, _, _, ref args, _) => { - // Check for a.b() where b is a method. Ensure that - // any types in the callee are valid for the entire - // method call. + ast::expr_unary(_, lhs) if has_method_map => { + // As above. + constrain_call(rcx, expr, Some(lhs), [], true); + } - constrain_auto_ref(rcx, rcvr); - for args.each |arg| { - constrain_auto_ref(rcx, *arg); - } + ast::expr_unary(ast::deref, base) => { + // For *a, the lifetime of a must enclose the deref + let base_ty = rcx.resolve_node_type(base.id); + constrain_derefs(rcx, expr, 1, base_ty); + } + + ast::expr_index(vec_expr, _) => { + // For a[b], the lifetime of a must enclose the deref + let vec_type = rcx.resolve_expr_type_adjusted(vec_expr); + constrain_index(rcx, expr, vec_type); } ast::expr_cast(source, _) => { @@ -294,18 +352,18 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { } } - ast::expr_index(vec_expr, _) => { - let vec_type = rcx.resolve_expr_type_adjusted(vec_expr); - constrain_index(rcx, expr, vec_type); - } - - ast::expr_unary(ast::deref, base) => { - let base_ty = rcx.resolve_node_type(base.id); - constrain_derefs(rcx, expr, 1, base_ty); - } - ast::expr_addr_of(_, base) => { guarantor::for_addr_of(rcx, expr, base); + + // Require that when you write a `&expr` expression, the + // resulting pointer has a lifetime that encompasses the + // `&expr` expression itself. Note that we constraining + // the type of the node expr.id here *before applying + // adjustments*. + // + // FIXME(#5074) nested method calls requires that this rule change + let ty0 = rcx.resolve_node_type(expr.id); + constrain_regions_in_type(rcx, ty::re_scope(expr.id), expr.span, ty0); } ast::expr_match(discr, ref arms) => { @@ -313,6 +371,8 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { } ast::expr_fn_block(*) => { + // The lifetime of a block fn must not outlive the variables + // it closes over let function_type = rcx.resolve_node_type(expr.id); match ty::get(function_type).sty { ty::ty_closure(ty::ClosureTy {sigil: ast::BorrowedSigil, @@ -326,46 +386,107 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { _ => () } - if !visit_node(expr.id, expr.span, rcx) { return; } visit::visit_expr(expr, rcx, v); } -fn visit_stmt(s: @ast::stmt, rcx: @mut Rcx, v: rvt) { - visit::visit_stmt(s, rcx, v); -} +fn constrain_callee(rcx: @mut Rcx, + call_expr: @ast::expr, + callee_expr: @ast::expr) +{ + let tcx = rcx.fcx.tcx(); -fn visit_node(id: ast::node_id, span: span, rcx: @mut Rcx) -> bool { - /*! - * - * checks the type of the node `id` and reports an error if it - * references a region that is not in scope for that node. - * Returns false if an error is reported; this is used to cause us - * to cut off region checking for that subtree to avoid reporting - * tons of errors. */ - - let fcx = rcx.fcx; - - // find the region where this expr evaluation is taking place - let tcx = fcx.ccx.tcx; - let encl_region = match tcx.region_maps.opt_encl_scope(id) { - None => ty::re_static, - Some(r) => ty::re_scope(r) - }; - - // Otherwise, look at the type and see if it is a region pointer. - constrain_regions_in_type_of_node(rcx, id, encl_region, span) + let call_region = ty::re_scope(call_expr.id); + + let callee_ty = rcx.resolve_node_type(call_expr.callee_id); + if ty::type_is_error(callee_ty) { + return; + } + + match ty::get(callee_ty).sty { + ty::ty_bare_fn(*) => { } + ty::ty_closure(ref closure_ty) => { + match rcx.fcx.mk_subr(true, callee_expr.span, + call_region, closure_ty.region) { + result::Err(_) => { + tcx.sess.span_err( + callee_expr.span, + fmt!("cannot invoke closure outside of its lifetime")); + note_and_explain_region( + tcx, + "the closure is only valid for ", + closure_ty.region, + ""); + } + result::Ok(_) => {} + } + } + _ => { + tcx.sess.span_bug( + callee_expr.span, + fmt!("Calling non-function: %s", callee_ty.repr(tcx))); + } + } } -fn encl_region_or_static(rcx: @mut Rcx, expr: @ast::expr) -> ty::Region { - // FIXME(#3850) --- interactions with modes compel overly large granularity - // that is, we would probably prefer to just return re_scope(expr.id) - // here but we cannot just yet. +fn constrain_call(rcx: @mut Rcx, + // might be expr_call, expr_method_call, or an overloaded + // operator + call_expr: @ast::expr, + receiver: Option<@ast::expr>, + arg_exprs: &[@ast::expr], + implicitly_ref_args: bool) +{ + //! Invoked on every call site (i.e., normal calls, method calls, + //! and overloaded operators). Constrains the regions which appear + //! in the type of the function. Also constrains the regions that + //! appear in the arguments appropriately. let tcx = rcx.fcx.tcx(); - match tcx.region_maps.opt_encl_scope(expr.id) { - Some(s) => ty::re_scope(s), - None => ty::re_static // occurs in constants + debug!("constrain_call(call_expr=%s, implicitly_ref_args=%?)", + call_expr.repr(tcx), implicitly_ref_args); + let callee_ty = rcx.resolve_node_type(call_expr.callee_id); + if ty::type_is_error(callee_ty) { + return; } + let fn_sig = ty::ty_fn_sig(callee_ty); + + // `callee_region` is the scope representing the time in which the + // call occurs. + // + // FIXME(#5074) to support nested method calls, should be callee_id + let callee_scope = call_expr.id; + let callee_region = ty::re_scope(callee_scope); + + for fn_sig.inputs.eachi |i, input| { + // ensure that any regions appearing in the argument type are + // valid for at least the lifetime of the function: + constrain_regions_in_type_of_node( + rcx, arg_exprs[i].id, callee_region, arg_exprs[i].span); + + // unfortunately, there are two means of taking implicit + // references, and we need to propagate constraints as a + // result. modes are going away and the "DerefArgs" code + // should be ported to use adjustments + ty::set_default_mode(tcx, input.mode, ast::by_copy); + let is_by_ref = ty::resolved_mode(tcx, input.mode) == ast::by_ref; + if implicitly_ref_args || is_by_ref { + guarantor::for_by_ref(rcx, arg_exprs[i], callee_scope); + } + } + + // as loop above, but for receiver + for receiver.each |&r| { + constrain_regions_in_type_of_node( + rcx, r.id, callee_region, r.span); + if implicitly_ref_args { + guarantor::for_by_ref(rcx, r, callee_scope); + } + } + + // constrain regions that may appear in the return type to be + // valid for the function call: + constrain_regions_in_type( + rcx, callee_region, call_expr.span, fn_sig.output); } fn constrain_derefs(rcx: @mut Rcx, @@ -379,9 +500,8 @@ fn constrain_derefs(rcx: @mut Rcx, * pointer being derefenced, the lifetime of the pointer includes * the deref expr. */ - let tcx = rcx.fcx.tcx(); - let r_deref_expr = encl_region_or_static(rcx, deref_expr); + let r_deref_expr = ty::re_scope(deref_expr.id); for uint::range(0, derefs) |i| { debug!("constrain_derefs(deref_expr=%s, derefd_ty=%s, derefs=%?/%?", rcx.fcx.expr_to_str(deref_expr), @@ -390,19 +510,8 @@ fn constrain_derefs(rcx: @mut Rcx, match ty::get(derefd_ty).sty { ty::ty_rptr(r_ptr, _) => { - match rcx.fcx.mk_subr(true, deref_expr.span, r_deref_expr, r_ptr) { - result::Ok(*) => {} - result::Err(*) => { - tcx.sess.span_err( - deref_expr.span, - fmt!("dereference of reference outside its lifetime")); - note_and_explain_region( - tcx, - "the reference is only valid for ", - r_ptr, - ""); - } - } + mk_subregion_due_to_derefence(rcx, deref_expr.span, + r_deref_expr, r_ptr); } _ => {} @@ -417,6 +526,27 @@ fn constrain_derefs(rcx: @mut Rcx, } } +pub fn mk_subregion_due_to_derefence(rcx: @mut Rcx, + deref_span: span, + minimum_lifetime: ty::Region, + maximum_lifetime: ty::Region) { + match rcx.fcx.mk_subr(true, deref_span, + minimum_lifetime, maximum_lifetime) { + result::Ok(*) => {} + result::Err(*) => { + rcx.tcx().sess.span_err( + deref_span, + fmt!("dereference of reference outside its lifetime")); + note_and_explain_region( + rcx.tcx(), + "the reference is only valid for ", + maximum_lifetime, + ""); + } + } +} + + fn constrain_index(rcx: @mut Rcx, index_expr: @ast::expr, indexed_ty: ty::t) @@ -433,7 +563,7 @@ fn constrain_index(rcx: @mut Rcx, rcx.fcx.expr_to_str(index_expr), rcx.fcx.infcx().ty_to_str(indexed_ty)); - let r_index_expr = encl_region_or_static(rcx, index_expr); + let r_index_expr = ty::re_scope(index_expr.id); match ty::get(indexed_ty).sty { ty::ty_estr(ty::vstore_slice(r_ptr)) | ty::ty_evec(_, ty::vstore_slice(r_ptr)) => { @@ -456,66 +586,22 @@ fn constrain_index(rcx: @mut Rcx, } } -fn constrain_auto_ref(rcx: @mut Rcx, expr: @ast::expr) { - /*! - * - * If `expr` is auto-ref'd (e.g., as part of a borrow), then this - * function ensures that the lifetime of the resulting borrowed - * ptr includes at least the expression `expr`. */ - - debug!("constrain_auto_ref(expr=%s)", rcx.fcx.expr_to_str(expr)); - - let adjustment = rcx.fcx.inh.adjustments.find(&expr.id); - let region = match adjustment { - Some(&@ty::AutoDerefRef( - ty::AutoDerefRef { - autoref: Some(ref auto_ref), _})) => { - auto_ref.region - } - _ => { return; } - }; - - let tcx = rcx.fcx.tcx(); - let encl_region = tcx.region_maps.encl_region(expr.id); - match rcx.fcx.mk_subr(true, expr.span, encl_region, region) { - result::Ok(()) => {} - result::Err(_) => { - // In practice, this cannot happen: `region` is always a - // region variable, and constraints on region variables - // are collected and then resolved later. However, I - // included the span_err() here (rather than, say, - // span_bug()) because it seemed more future-proof: if, - // for some reason, the code were to change so that in - // some cases `region` is not a region variable, then - // reporting an error would be the correct path. - tcx.sess.span_err( - expr.span, - ~"lifetime of borrowed pointer does not include \ - the expression being borrowed"); - note_and_explain_region( - tcx, - ~"lifetime of the borrowed pointer is", - region, - ~""); - rcx.errors_reported += 1; - } - } -} - -fn constrain_free_variables( - rcx: @mut Rcx, - region: ty::Region, - expr: @ast::expr) { +fn constrain_free_variables(rcx: @mut Rcx, + region: ty::Region, + expr: @ast::expr) { /*! - * * Make sure that all free variables referenced inside the closure - * outlive the closure itself. */ + * outlive the closure itself. + */ let tcx = rcx.fcx.ccx.tcx; + debug!("constrain_free_variables(%s, %s)", + region.repr(tcx), expr.repr(tcx)); for get_freevars(tcx, expr.id).each |freevar| { debug!("freevar def is %?", freevar.def); let def = freevar.def; let en_region = encl_region_of_def(rcx.fcx, def); + debug!("en_region = %s", en_region.repr(tcx)); match rcx.fcx.mk_subr(true, freevar.span, region, en_region) { result::Ok(()) => {} @@ -541,9 +627,13 @@ fn constrain_free_variables( fn constrain_regions_in_type_of_node( rcx: @mut Rcx, id: ast::node_id, - encl_region: ty::Region, + minimum_lifetime: ty::Region, span: span) -> bool { + //! Guarantees that any lifetimes which appear in the type of + //! the node `id` (after applying adjustments) are valid for at + //! least `minimum_lifetime` + let tcx = rcx.fcx.tcx(); // Try to resolve the type. If we encounter an error, then typeck @@ -553,22 +643,21 @@ fn constrain_regions_in_type_of_node( let adjustment = rcx.fcx.inh.adjustments.find(&id); let ty = ty::adjust_ty(tcx, span, ty0, adjustment); debug!("constrain_regions_in_type_of_node(\ - ty=%s, ty0=%s, id=%d, encl_region=%?, adjustment=%?)", + ty=%s, ty0=%s, id=%d, minimum_lifetime=%?, adjustment=%?)", ty_to_str(tcx, ty), ty_to_str(tcx, ty0), - id, encl_region, adjustment); - constrain_regions_in_type(rcx, encl_region, span, ty) + id, minimum_lifetime, adjustment); + constrain_regions_in_type(rcx, minimum_lifetime, span, ty) } fn constrain_regions_in_type( rcx: @mut Rcx, - encl_region: ty::Region, + minimum_lifetime: ty::Region, span: span, ty: ty::t) -> bool { /*! - * * Requires that any regions which appear in `ty` must be - * superregions of `encl_region`. Also enforces the constraint + * superregions of `minimum_lifetime`. Also enforces the constraint * that given a pointer type `&'r T`, T must not contain regions * that outlive 'r, as well as analogous constraints for other * lifetime'd types. @@ -583,11 +672,11 @@ fn constrain_regions_in_type( let e = rcx.errors_reported; let tcx = rcx.fcx.ccx.tcx; - debug!("constrain_regions_in_type(encl_region=%s, ty=%s)", - region_to_str(tcx, encl_region), + debug!("constrain_regions_in_type(minimum_lifetime=%s, ty=%s)", + region_to_str(tcx, minimum_lifetime), ty_to_str(tcx, ty)); - do relate_nested_regions(tcx, Some(encl_region), ty) |r_sub, r_sup| { + do relate_nested_regions(tcx, Some(minimum_lifetime), ty) |r_sub, r_sup| { debug!("relate(r_sub=%s, r_sup=%s)", region_to_str(tcx, r_sub), region_to_str(tcx, r_sup)); @@ -595,12 +684,12 @@ fn constrain_regions_in_type( if r_sup.is_bound() || r_sub.is_bound() { // a bound region is one which appears inside an fn type. // (e.g., the `&` in `fn(&T)`). Such regions need not be - // constrained by `encl_region` as they are placeholders + // constrained by `minimum_lifetime` as they are placeholders // for regions that are as-yet-unknown. } else { match rcx.fcx.mk_subr(true, span, r_sub, r_sup) { result::Err(_) => { - if r_sub == encl_region { + if r_sub == minimum_lifetime { tcx.sess.span_err( span, fmt!("reference is not valid outside of its lifetime")); @@ -639,7 +728,6 @@ fn constrain_regions_in_type( pub mod guarantor { /*! - * * The routines in this module are aiming to deal with the case * where a the contents of a borrowed pointer are re-borrowed. * Imagine you have a borrowed pointer `b` with lifetime L1 and @@ -686,6 +774,7 @@ pub mod guarantor { */ use middle::typeck::check::regionck::{Rcx, infallibly_mk_subr}; + use middle::typeck::check::regionck::mk_subregion_due_to_derefence; use middle::ty; use syntax::ast; use syntax::codemap::span; @@ -693,14 +782,12 @@ pub mod guarantor { pub fn for_addr_of(rcx: @mut Rcx, expr: @ast::expr, base: @ast::expr) { /*! - * * Computes the guarantor for an expression `&base` and then * ensures that the lifetime of the resulting pointer is linked * to the lifetime of its guarantor (if any). */ debug!("guarantor::for_addr_of(base=%s)", rcx.fcx.expr_to_str(base)); - let _i = ::util::common::indenter(); let guarantor = guarantor(rcx, base); link(rcx, expr.span, expr.id, guarantor); @@ -708,13 +795,14 @@ pub mod guarantor { pub fn for_match(rcx: @mut Rcx, discr: @ast::expr, arms: &[ast::arm]) { /*! - * * Computes the guarantors for any ref bindings in a match and * then ensures that the lifetime of the resulting pointer is * linked to the lifetime of its guarantor (if any). */ + debug!("regionck::for_match()"); let discr_guarantor = guarantor(rcx, discr); + debug!("discr_guarantor=%s", discr_guarantor.repr(rcx.tcx())); for arms.each |arm| { for arm.pats.each |pat| { link_ref_bindings_in_pat(rcx, *pat, discr_guarantor); @@ -727,7 +815,6 @@ pub mod guarantor { autoderefs: uint, autoref: &ty::AutoRef) { /*! - * * Computes the guarantor for an expression that has an * autoref adjustment and links it to the lifetime of the * autoref. This is only important when auto re-borrowing @@ -736,30 +823,30 @@ pub mod guarantor { debug!("guarantor::for_autoref(expr=%s, autoref=%?)", rcx.fcx.expr_to_str(expr), autoref); - let _i = ::util::common::indenter(); let mut expr_ct = categorize_unadjusted(rcx, expr); debug!(" unadjusted cat=%?", expr_ct.cat); expr_ct = apply_autoderefs( rcx, expr, autoderefs, expr_ct); - match autoref.kind { - ty::AutoPtr => { + match *autoref { + ty::AutoPtr(r, _) => { // In this case, we are implicitly adding an `&`. - maybe_make_subregion(rcx, expr, autoref.region, - expr_ct.cat.guarantor); + maybe_make_subregion(rcx, expr, r, expr_ct.cat.guarantor); } - ty::AutoBorrowVec | - ty::AutoBorrowVecRef | - ty::AutoBorrowFn => { + ty::AutoBorrowVec(r, _) | + ty::AutoBorrowVecRef(r, _) | + ty::AutoBorrowFn(r) => { // In each of these cases, what is being borrowed is // not the (autoderef'd) expr itself but rather the // contents of the autoderef'd expression (i.e., what // the pointer points at). - maybe_make_subregion(rcx, expr, autoref.region, + maybe_make_subregion(rcx, expr, r, guarantor_of_deref(&expr_ct.cat)); } + + ty::AutoUnsafe(_) => {} } fn maybe_make_subregion( @@ -774,6 +861,28 @@ pub mod guarantor { } } + pub fn for_by_ref(rcx: @mut Rcx, + expr: @ast::expr, + callee_scope: ast::node_id) { + /*! + * Computes the guarantor for cases where the `expr` is + * being passed by implicit reference and must outlive + * `callee_scope`. + */ + + let tcx = rcx.tcx(); + debug!("guarantor::for_by_ref(expr=%s, callee_scope=%?)", + expr.repr(tcx), callee_scope); + let mut expr_cat = categorize(rcx, expr); + debug!("guarantor::for_by_ref(expr=%?, callee_scope=%?) category=%?", + expr.id, callee_scope, expr_cat); + let minimum_lifetime = ty::re_scope(callee_scope); + for expr_cat.guarantor.each |guarantor| { + mk_subregion_due_to_derefence(rcx, expr.span, + minimum_lifetime, *guarantor); + } + } + fn link( rcx: @mut Rcx, span: span, @@ -907,7 +1016,6 @@ pub mod guarantor { fn categorize(rcx: @mut Rcx, expr: @ast::expr) -> ExprCategorization { debug!("categorize(expr=%s)", rcx.fcx.expr_to_str(expr)); - let _i = ::util::common::indenter(); let mut expr_ct = categorize_unadjusted(rcx, expr); debug!("before adjustments, cat=%?", expr_ct.cat); @@ -928,12 +1036,24 @@ pub mod guarantor { expr_ct = apply_autoderefs( rcx, expr, adjustment.autoderefs, expr_ct); - for adjustment.autoref.each |autoref| { - // If there is an autoref, then the result of this - // expression will be some sort of borrowed pointer. - expr_ct.cat.guarantor = None; - expr_ct.cat.pointer = BorrowedPointer(autoref.region); - debug!("autoref, cat=%?", expr_ct.cat); + match adjustment.autoref { + None => { + } + Some(ty::AutoUnsafe(_)) => { + expr_ct.cat.guarantor = None; + expr_ct.cat.pointer = OtherPointer; + debug!("autoref, cat=%?", expr_ct.cat); + } + Some(ty::AutoPtr(r, _)) | + Some(ty::AutoBorrowVec(r, _)) | + Some(ty::AutoBorrowVecRef(r, _)) | + Some(ty::AutoBorrowFn(r)) => { + // If there is an autoref, then the result of this + // expression will be some sort of borrowed pointer. + expr_ct.cat.guarantor = None; + expr_ct.cat.pointer = BorrowedPointer(r); + debug!("autoref, cat=%?", expr_ct.cat); + } } } @@ -948,7 +1068,6 @@ pub mod guarantor { expr: @ast::expr) -> ExprCategorizationType { debug!("categorize_unadjusted(expr=%s)", rcx.fcx.expr_to_str(expr)); - let _i = ::util::common::indenter(); let guarantor = { if rcx.fcx.inh.method_map.contains_key(&expr.id) { @@ -1053,7 +1172,6 @@ pub mod guarantor { debug!("link_ref_bindings_in_pat(pat=%s, guarantor=%?)", rcx.fcx.pat_to_str(pat), guarantor); - let _i = ::util::common::indenter(); match pat.node { ast::pat_wild => {} @@ -1069,7 +1187,10 @@ pub mod guarantor { link_ref_bindings_in_pat(rcx, *p, guarantor); } } - ast::pat_enum(*) => {} + ast::pat_enum(_, None) => {} + ast::pat_enum(_, Some(ref pats)) => { + link_ref_bindings_in_pats(rcx, pats, guarantor); + } ast::pat_struct(_, ref fpats, _) => { for fpats.each |fpat| { link_ref_bindings_in_pat(rcx, fpat.pat, guarantor); diff --git a/src/librustc/middle/typeck/check/regionmanip.rs b/src/librustc/middle/typeck/check/regionmanip.rs index f293893bc131f..cfbd012b7b7cd 100644 --- a/src/librustc/middle/typeck/check/regionmanip.rs +++ b/src/librustc/middle/typeck/check/regionmanip.rs @@ -87,7 +87,7 @@ pub fn replace_bound_regions_in_fn_sig( to_r: &fn(ty::bound_region) -> ty::Region, r: ty::Region) -> isr_alist { match r { - ty::re_free(*) | ty::re_static | ty::re_scope(_) | + ty::re_empty | ty::re_free(*) | ty::re_static | ty::re_scope(_) | ty::re_infer(_) => { isr } @@ -153,6 +153,7 @@ pub fn replace_bound_regions_in_fn_sig( } // Free regions like these just stay the same: + ty::re_empty | ty::re_static | ty::re_scope(_) | ty::re_free(*) | diff --git a/src/librustc/middle/typeck/check/writeback.rs b/src/librustc/middle/typeck/check/writeback.rs index d6b09d1e7f453..b7713eaa2fd6e 100644 --- a/src/librustc/middle/typeck/check/writeback.rs +++ b/src/librustc/middle/typeck/check/writeback.rs @@ -134,23 +134,22 @@ fn resolve_type_vars_for_node(wbcx: @mut WbCtxt, sp: span, id: ast::node_id) } Some(&@ty::AutoDerefRef(adj)) => { - let resolved_autoref = match adj.autoref { - Some(ref autoref) => { - match resolve_region(fcx.infcx(), autoref.region, - resolve_all | force_all) { - Err(e) => { - // This should not, I think, happen. - fcx.ccx.tcx.sess.span_err( - sp, fmt!("cannot resolve scope of borrow: %s", - infer::fixup_err_to_str(e))); - Some(*autoref) - } - Ok(r) => { - Some(ty::AutoRef {region: r, ..*autoref}) - } + let fixup_region = |r| { + match resolve_region(fcx.infcx(), r, resolve_all | force_all) { + Ok(r1) => r1, + Err(e) => { + // This should not, I think, happen. + fcx.ccx.tcx.sess.span_err( + sp, fmt!("cannot resolve scope of borrow: %s", + infer::fixup_err_to_str(e))); + r } } - None => None + }; + + let resolved_autoref = match adj.autoref { + None => None, + Some(ref r) => Some(r.map_region(fixup_region)) }; let resolved_adj = @ty::AutoDerefRef(ty::AutoDerefRef { diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 05b2f6f577b82..573e4bd579011 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -393,7 +393,7 @@ pub impl CoherenceChecker { let pmm = self.crate_context.tcx.provided_methods; match pmm.find(&local_def(impl_id)) { - Some(mis) => { + Some(&mis) => { // If the trait already has an entry in the // provided_methods_map, we just need to add this // method to that entry. @@ -426,8 +426,8 @@ pub impl CoherenceChecker { self.crate_context.coherence_info.inherent_methods .insert(base_def_id, implementation_list); } - Some(existing_implementation_list) => { - implementation_list = *existing_implementation_list; + Some(&existing_implementation_list) => { + implementation_list = existing_implementation_list; } } @@ -443,8 +443,8 @@ pub impl CoherenceChecker { self.crate_context.coherence_info.extension_methods .insert(trait_id, implementation_list); } - Some(existing_implementation_list) => { - implementation_list = *existing_implementation_list; + Some(&existing_implementation_list) => { + implementation_list = existing_implementation_list; } } @@ -507,7 +507,7 @@ pub impl CoherenceChecker { m.insert(self_t, the_impl); self.crate_context.tcx.trait_impls.insert(trait_t, m); } - Some(m) => { + Some(&m) => { m.insert(self_t, the_impl); } } diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs index dcd1c861540f4..3620b609edf3b 100644 --- a/src/librustc/middle/typeck/infer/coercion.rs +++ b/src/librustc/middle/typeck/infer/coercion.rs @@ -65,7 +65,7 @@ we may want to adjust precisely when coercions occur. */ use middle::ty::{AutoPtr, AutoBorrowVec, AutoBorrowFn}; -use middle::ty::{AutoDerefRef, AutoRef}; +use middle::ty::{AutoDerefRef}; use middle::ty::{vstore_slice, vstore_box, vstore_uniq}; use middle::ty::{mt}; use middle::ty; @@ -120,9 +120,9 @@ pub impl Coerce { }; } - ty::ty_ptr(_) => { + ty::ty_ptr(mt_b) => { return do self.unpack_actual_value(a) |sty_a| { - self.coerce_unsafe_ptr(a, sty_a, b) + self.coerce_unsafe_ptr(a, sty_a, b, mt_b) }; } @@ -205,11 +205,7 @@ pub impl Coerce { if_ok!(sub.tys(a_borrowed, b)); Ok(Some(@AutoDerefRef(AutoDerefRef { autoderefs: 1, - autoref: Some(AutoRef { - kind: AutoPtr, - region: r_borrow, - mutbl: mt_b.mutbl - }) + autoref: Some(AutoPtr(r_borrow, mt_b.mutbl)) }))) } @@ -235,11 +231,7 @@ pub impl Coerce { if_ok!(self.subtype(a_borrowed, b)); Ok(Some(@AutoDerefRef(AutoDerefRef { autoderefs: 0, - autoref: Some(AutoRef { - kind: AutoBorrowVec, - region: r_a, - mutbl: m_imm - }) + autoref: Some(AutoBorrowVec(r_a, m_imm)) }))) } @@ -268,11 +260,7 @@ pub impl Coerce { if_ok!(sub.tys(a_borrowed, b)); Ok(Some(@AutoDerefRef(AutoDerefRef { autoderefs: 0, - autoref: Some(AutoRef { - kind: AutoBorrowVec, - region: r_borrow, - mutbl: mt_b.mutbl - }) + autoref: Some(AutoBorrowVec(r_borrow, mt_b.mutbl)) }))) } @@ -308,11 +296,7 @@ pub impl Coerce { if_ok!(self.subtype(a_borrowed, b)); Ok(Some(@AutoDerefRef(AutoDerefRef { autoderefs: 0, - autoref: Some(AutoRef { - kind: AutoBorrowFn, - region: r_borrow, - mutbl: m_imm - }) + autoref: Some(AutoBorrowFn(r_borrow)) }))) } @@ -363,7 +347,8 @@ pub impl Coerce { fn coerce_unsafe_ptr(&self, a: ty::t, sty_a: &ty::sty, - b: ty::t) -> CoerceResult + b: ty::t, + mt_b: ty::mt) -> CoerceResult { debug!("coerce_unsafe_ptr(a=%s, sty_a=%?, b=%s)", a.inf_str(self.infcx), sty_a, @@ -376,10 +361,17 @@ pub impl Coerce { } }; - // borrowed pointers and unsafe pointers have the same - // representation, so just check that the types which they - // point at are compatible: + // check that the types which they point at are compatible let a_unsafe = ty::mk_ptr(self.infcx.tcx, mt_a); - self.subtype(a_unsafe, b) + if_ok!(self.subtype(a_unsafe, b)); + + // although borrowed ptrs and unsafe ptrs have the same + // representation, we still register an AutoDerefRef so that + // regionck knows that that the region for `a` must be valid + // here + Ok(Some(@AutoDerefRef(AutoDerefRef { + autoderefs: 1, + autoref: Some(ty::AutoUnsafe(mt_b.mutbl)) + }))) } } diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 7b5a93d4cad88..4491b04b382ec 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -339,7 +339,7 @@ pub fn fixup_err_to_str(f: fixup_err) -> ~str { fn new_ValsAndBindings() -> ValsAndBindings { ValsAndBindings { - vals: @mut SmallIntMap::new(), + vals: SmallIntMap::new(), bindings: ~[] } } @@ -469,28 +469,6 @@ pub fn resolve_region(cx: @mut InferCtxt, r: ty::Region, modes: uint) resolver.resolve_region_chk(r) } -/* -fn resolve_borrowings(cx: @mut InferCtxt) { - for cx.borrowings.each |item| { - match resolve_region(cx, item.scope, resolve_all|force_all) { - Ok(region) => { - debug!("borrowing for expr %d resolved to region %?, mutbl %?", - item.expr_id, region, item.mutbl); - cx.tcx.borrowings.insert( - item.expr_id, {region: region, mutbl: item.mutbl}); - } - - Err(e) => { - let str = fixup_err_to_str(e); - cx.tcx.sess.span_err( - item.span, - fmt!("could not resolve lifetime for borrow: %s", str)); - } - } - } -} -*/ - trait then { fn then(&self, f: &fn() -> Result) -> Result; @@ -554,7 +532,8 @@ struct Snapshot { } pub impl InferCtxt { - fn combine_fields(@mut self, a_is_expected: bool, + fn combine_fields(@mut self, + a_is_expected: bool, span: span) -> CombineFields { CombineFields {infcx: self, a_is_expected: a_is_expected, @@ -565,25 +544,24 @@ pub impl InferCtxt { Sub(self.combine_fields(a_is_expected, span)) } - fn in_snapshot(@mut self) -> bool { + fn in_snapshot(&self) -> bool { self.region_vars.in_snapshot() } - fn start_snapshot(@mut self) -> Snapshot { - let this = &mut *self; + fn start_snapshot(&mut self) -> Snapshot { Snapshot { ty_var_bindings_len: - this.ty_var_bindings.bindings.len(), + self.ty_var_bindings.bindings.len(), int_var_bindings_len: - this.int_var_bindings.bindings.len(), + self.int_var_bindings.bindings.len(), float_var_bindings_len: - this.float_var_bindings.bindings.len(), + self.float_var_bindings.bindings.len(), region_vars_snapshot: - this.region_vars.start_snapshot(), + self.region_vars.start_snapshot(), } } - fn rollback_to(@mut self, snapshot: &Snapshot) { + fn rollback_to(&mut self, snapshot: &Snapshot) { debug!("rollback!"); rollback_to(&mut self.ty_var_bindings, snapshot.ty_var_bindings_len); @@ -596,7 +574,7 @@ pub impl InferCtxt { } /// Execute `f` and commit the bindings if successful - fn commit(@mut self, f: &fn() -> Result) -> Result { + fn commit(&mut self, f: &fn() -> Result) -> Result { assert!(!self.in_snapshot()); debug!("commit()"); @@ -611,7 +589,7 @@ pub impl InferCtxt { } /// Execute `f`, unroll bindings on failure - fn try(@mut self, f: &fn() -> Result) -> Result { + fn try(&mut self, f: &fn() -> Result) -> Result { debug!("try()"); do indent { let snapshot = self.start_snapshot(); @@ -625,7 +603,7 @@ pub impl InferCtxt { } /// Execute `f` then unroll any bindings it creates - fn probe(@mut self, f: &fn() -> Result) -> Result { + fn probe(&mut self, f: &fn() -> Result) -> Result { debug!("probe()"); do indent { let snapshot = self.start_snapshot(); @@ -647,45 +625,47 @@ fn next_simple_var( } pub impl InferCtxt { - fn next_ty_var_id(@mut self) -> TyVid { + fn next_ty_var_id(&mut self) -> TyVid { let id = self.ty_var_counter; self.ty_var_counter += 1; - let vals = self.ty_var_bindings.vals; - vals.insert(id, Root(Bounds { lb: None, ub: None }, 0u)); + { + let vals = &mut self.ty_var_bindings.vals; + vals.insert(id, Root(Bounds { lb: None, ub: None }, 0u)); + } return TyVid(id); } - fn next_ty_var(@mut self) -> ty::t { + fn next_ty_var(&mut self) -> ty::t { ty::mk_var(self.tcx, self.next_ty_var_id()) } - fn next_ty_vars(@mut self, n: uint) -> ~[ty::t] { + fn next_ty_vars(&mut self, n: uint) -> ~[ty::t] { vec::from_fn(n, |_i| self.next_ty_var()) } - fn next_int_var_id(@mut self) -> IntVid { + fn next_int_var_id(&mut self) -> IntVid { IntVid(next_simple_var(&mut self.int_var_counter, &mut self.int_var_bindings)) } - fn next_int_var(@mut self) -> ty::t { + fn next_int_var(&mut self) -> ty::t { ty::mk_int_var(self.tcx, self.next_int_var_id()) } - fn next_float_var_id(@mut self) -> FloatVid { + fn next_float_var_id(&mut self) -> FloatVid { FloatVid(next_simple_var(&mut self.float_var_counter, &mut self.float_var_bindings)) } - fn next_float_var(@mut self) -> ty::t { + fn next_float_var(&mut self) -> ty::t { ty::mk_float_var(self.tcx, self.next_float_var_id()) } - fn next_region_var_nb(@mut self, span: span) -> ty::Region { + fn next_region_var_nb(&mut self, span: span) -> ty::Region { ty::re_infer(ty::ReVar(self.region_vars.new_region_var(span))) } - fn next_region_var_with_lb(@mut self, span: span, + fn next_region_var_with_lb(&mut self, span: span, lb_region: ty::Region) -> ty::Region { let region_var = self.next_region_var_nb(span); @@ -697,12 +677,12 @@ pub impl InferCtxt { return region_var; } - fn next_region_var(@mut self, span: span, scope_id: ast::node_id) + fn next_region_var(&mut self, span: span, scope_id: ast::node_id) -> ty::Region { self.next_region_var_with_lb(span, ty::re_scope(scope_id)) } - fn resolve_regions(@mut self) { + fn resolve_regions(&mut self) { self.region_vars.resolve_regions(); } @@ -722,7 +702,6 @@ pub impl InferCtxt { result::Err(_) => typ } } - fn resolve_type_vars_in_trait_ref_if_possible(@mut self, trait_ref: &ty::TraitRef) -> ty::TraitRef @@ -786,7 +765,7 @@ pub impl InferCtxt { self.type_error_message(sp, mk_msg, a, Some(err)); } - fn replace_bound_regions_with_fresh_regions(@mut self, + fn replace_bound_regions_with_fresh_regions(&mut self, span: span, fsig: &ty::FnSig) -> (ty::FnSig, isr_alist) { @@ -806,7 +785,7 @@ pub impl InferCtxt { } fn fold_regions_in_sig( - @mut self, + &mut self, fn_sig: &ty::FnSig, fldr: &fn(r: ty::Region, in_fn: bool) -> ty::Region) -> ty::FnSig { diff --git a/src/librustc/middle/typeck/infer/region_inference.rs b/src/librustc/middle/typeck/infer/region_inference.rs index e12a3f2e97522..0761ad5c7b819 100644 --- a/src/librustc/middle/typeck/infer/region_inference.rs +++ b/src/librustc/middle/typeck/infer/region_inference.rs @@ -24,7 +24,7 @@ it's worth spending more time on a more involved analysis. Moreover, regions are a simpler case than types: they don't have aggregate structure, for example. -Unlike normal type inference, which is similar in spirit H-M and thus +Unlike normal type inference, which is similar in spirit to H-M and thus works progressively, the region type inference works by accumulating constraints over the course of a function. Finally, at the end of processing a function, we process and solve the constraints all at @@ -130,7 +130,7 @@ of these variables can effectively be unified into a single variable. Once SCCs are removed, we are left with a DAG. At this point, we can walk the DAG in toplogical order once to compute the expanding nodes, and again in reverse topological order to compute the contracting -nodes.The main reason I did not write it this way is that I did not +nodes. The main reason I did not write it this way is that I did not feel like implementing the SCC and toplogical sort algorithms at the moment. @@ -538,7 +538,7 @@ more convincing in the future. use middle::ty; use middle::ty::{FreeRegion, Region, RegionVid}; -use middle::ty::{re_static, re_infer, re_free, re_bound}; +use middle::ty::{re_empty, re_static, re_infer, re_free, re_bound}; use middle::ty::{re_scope, ReVar, ReSkolemized, br_fresh}; use middle::typeck::infer::cres; use util::common::indenter; @@ -547,6 +547,9 @@ use util::ppaux::note_and_explain_region; use core::cell::{Cell, empty_cell}; use core::hashmap::{HashMap, HashSet}; use core::to_bytes; +use core::uint; +use core::vec; +use core; use syntax::codemap::span; use syntax::ast; @@ -572,18 +575,12 @@ impl to_bytes::IterBytes for Constraint { } } -#[deriving(Eq)] +#[deriving(Eq, IterBytes)] struct TwoRegions { a: Region, b: Region, } -impl to_bytes::IterBytes for TwoRegions { - fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { - to_bytes::iter_bytes_2(&self.a, &self.b, lsb0, f) - } -} - enum UndoLogEntry { Snapshot, AddVar(RegionVid), @@ -637,7 +634,7 @@ pub fn RegionVarBindings(tcx: ty::ctxt) -> RegionVarBindings { } pub impl RegionVarBindings { - fn in_snapshot(&mut self) -> bool { + fn in_snapshot(&self) -> bool { self.undo_log.len() > 0 } @@ -832,7 +829,6 @@ pub impl RegionVarBindings { } fn resolve_var(&mut self, rid: RegionVid) -> ty::Region { - debug!("RegionVarBindings: resolve_var(%?=%u)", rid, rid.to_uint()); if self.values.is_empty() { self.tcx.sess.span_bug( self.var_spans[rid.to_uint()], @@ -841,29 +837,14 @@ pub impl RegionVarBindings { } let v = self.values.with_ref(|values| values[rid.to_uint()]); + debug!("RegionVarBindings: resolve_var(%?=%u)=%?", + rid, rid.to_uint(), v); match v { Value(r) => r, NoValue => { - // No constraints, report an error. It is plausible - // that we could select an arbitrary region here - // instead. At the moment I am not doing this because - // this generally masks bugs in the inference - // algorithm, and given our syntax one cannot create - // generally create a lifetime variable that isn't - // used in some type, and hence all lifetime variables - // should ultimately have some bounds. - - self.tcx.sess.span_err( - self.var_spans[rid.to_uint()], - fmt!("Unconstrained region variable #%u", rid.to_uint())); - - // Touch of a hack: to suppress duplicate messages, - // replace the NoValue entry with ErrorValue. - let mut values = self.values.take(); - values[rid.to_uint()] = ErrorValue; - self.values.put_back(values); - re_static + // No constraints, return ty::re_empty + re_empty } ErrorValue => { @@ -1031,6 +1012,10 @@ priv impl RegionVarBindings { re_static // nothing lives longer than static } + (re_empty, r) | (r, re_empty) => { + r // everything lives longer than empty + } + (re_infer(ReVar(v_id)), _) | (_, re_infer(ReVar(v_id))) => { self.tcx.sess.span_bug( self.var_spans[v_id.to_uint()], @@ -1127,6 +1112,11 @@ priv impl RegionVarBindings { Ok(r) } + (re_empty, _) | (_, re_empty) => { + // nothing lives shorter than everything else + Ok(re_empty) + } + (re_infer(ReVar(v_id)), _) | (_, re_infer(ReVar(v_id))) => { self.tcx.sess.span_bug( @@ -1266,8 +1256,6 @@ struct SpannedRegion { span: span, } -type TwoRegionsMap = HashSet; - pub impl RegionVarBindings { fn infer_variable_values(&mut self) -> ~[GraphNodeValue] { let mut graph = self.construct_graph(); @@ -1329,11 +1317,15 @@ pub impl RegionVarBindings { node_id: RegionVid, edge_dir: Direction, edge_idx: uint) { + //! Insert edge `edge_idx` on the link list of edges in direction + //! `edge_dir` for the node `node_id` let edge_dir = edge_dir as uint; - graph.edges[edge_idx].next_edge[edge_dir] = - graph.nodes[node_id.to_uint()].head_edge[edge_dir]; - graph.nodes[node_id.to_uint()].head_edge[edge_dir] = - edge_idx; + assert_eq!(graph.edges[edge_idx].next_edge[edge_dir], + uint::max_value); + let n = node_id.to_uint(); + let prev_head = graph.nodes[n].head_edge[edge_dir]; + graph.edges[edge_idx].next_edge[edge_dir] = prev_head; + graph.nodes[n].head_edge[edge_dir] = edge_idx; } } @@ -1484,6 +1476,8 @@ pub impl RegionVarBindings { } } Err(_) => { + debug!("Setting %? to ErrorValue: no glb of %?, %?", + a_vid, a_region, b_region); a_node.value = ErrorValue; false } @@ -1495,7 +1489,21 @@ pub impl RegionVarBindings { &mut self, graph: &Graph) -> ~[GraphNodeValue] { - let mut dup_map = HashSet::new(); + debug!("extract_values_and_report_conflicts()"); + + // This is the best way that I have found to suppress + // duplicate and related errors. Basically we keep a set of + // flags for every node. Whenever an error occurs, we will + // walk some portion of the graph looking to find pairs of + // conflicting regions to report to the user. As we walk, we + // trip the flags from false to true, and if we find that + // we've already reported an error involving any particular + // node we just stop and don't report the current error. The + // idea is to report errors that derive from independent + // regions of the graph, but not those that derive from + // overlapping locations. + let mut dup_vec = graph.nodes.map(|_| uint::max_value); + graph.nodes.mapi(|idx, node| { match node.value { Value(_) => { @@ -1530,15 +1538,16 @@ pub impl RegionVarBindings { that is not used is not a problem, so if this rule starts to create problems we'll have to revisit this portion of the code and think hard about it. =) */ + let node_vid = RegionVid { id: idx }; match node.classification { Expanding => { self.report_error_for_expanding_node( - graph, &mut dup_map, node_vid); + graph, dup_vec, node_vid); } Contracting => { self.report_error_for_contracting_node( - graph, &mut dup_map, node_vid); + graph, dup_vec, node_vid); } } } @@ -1548,38 +1557,26 @@ pub impl RegionVarBindings { }) } - // Used to suppress reporting the same basic error over and over - fn is_reported(&mut self, - dup_map: &mut TwoRegionsMap, - r_a: Region, - r_b: Region) - -> bool { - let key = TwoRegions { a: r_a, b: r_b }; - !dup_map.insert(key) - } - fn report_error_for_expanding_node(&mut self, graph: &Graph, - dup_map: &mut TwoRegionsMap, + dup_vec: &mut [uint], node_idx: RegionVid) { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. - let lower_bounds = - self.collect_concrete_regions(graph, node_idx, Incoming); - let upper_bounds = - self.collect_concrete_regions(graph, node_idx, Outgoing); + let (lower_bounds, lower_dup) = + self.collect_concrete_regions(graph, node_idx, Incoming, dup_vec); + let (upper_bounds, upper_dup) = + self.collect_concrete_regions(graph, node_idx, Outgoing, dup_vec); + + if lower_dup || upper_dup { + return; + } for vec::each(lower_bounds) |lower_bound| { for vec::each(upper_bounds) |upper_bound| { if !self.is_subregion_of(lower_bound.region, upper_bound.region) { - if self.is_reported(dup_map, - lower_bound.region, - upper_bound.region) { - return; - } - self.tcx.sess.span_err( self.var_spans[node_idx.to_uint()], fmt!("cannot infer an appropriate lifetime \ @@ -1609,16 +1606,28 @@ pub impl RegionVarBindings { } } } + + self.tcx.sess.span_bug( + self.var_spans[node_idx.to_uint()], + fmt!("report_error_for_expanding_node() could not find error \ + for var %?, lower_bounds=%s, upper_bounds=%s", + node_idx, + lower_bounds.map(|x| x.region).repr(self.tcx), + upper_bounds.map(|x| x.region).repr(self.tcx))); } fn report_error_for_contracting_node(&mut self, graph: &Graph, - dup_map: &mut TwoRegionsMap, + dup_vec: &mut [uint], node_idx: RegionVid) { // Errors in contracting nodes result from two upper-bounds // that have no intersection. - let upper_bounds = self.collect_concrete_regions(graph, node_idx, - Outgoing); + let (upper_bounds, dup_found) = + self.collect_concrete_regions(graph, node_idx, Outgoing, dup_vec); + + if dup_found { + return; + } for vec::each(upper_bounds) |upper_bound_1| { for vec::each(upper_bounds) |upper_bound_2| { @@ -1627,12 +1636,6 @@ pub impl RegionVarBindings { Ok(_) => {} Err(_) => { - if self.is_reported(dup_map, - upper_bound_1.region, - upper_bound_2.region) { - return; - } - self.tcx.sess.span_err( self.var_spans[node_idx.to_uint()], fmt!("cannot infer an appropriate lifetime \ @@ -1663,50 +1666,94 @@ pub impl RegionVarBindings { } } } + + self.tcx.sess.span_bug( + self.var_spans[node_idx.to_uint()], + fmt!("report_error_for_contracting_node() could not find error \ + for var %?, upper_bounds=%s", + node_idx, + upper_bounds.map(|x| x.region).repr(self.tcx))); } fn collect_concrete_regions(&mut self, graph: &Graph, orig_node_idx: RegionVid, - dir: Direction) - -> ~[SpannedRegion] { - let mut set = HashSet::new(); - let mut stack = ~[orig_node_idx]; - set.insert(orig_node_idx.to_uint()); - let mut result = ~[]; - while !vec::is_empty(stack) { - let node_idx = stack.pop(); - for self.each_edge(graph, node_idx, dir) |edge| { + dir: Direction, + dup_vec: &mut [uint]) + -> (~[SpannedRegion], bool) { + struct WalkState { + set: HashSet, + stack: ~[RegionVid], + result: ~[SpannedRegion], + dup_found: bool + } + let mut state = WalkState { + set: HashSet::new(), + stack: ~[orig_node_idx], + result: ~[], + dup_found: false + }; + state.set.insert(orig_node_idx); + + // to start off the process, walk the source node in the + // direction specified + process_edges(self, &mut state, graph, orig_node_idx, dir); + + while !state.stack.is_empty() { + let node_idx = state.stack.pop(); + let classification = graph.nodes[node_idx.to_uint()].classification; + + // check whether we've visited this node on some previous walk + if dup_vec[node_idx.to_uint()] == uint::max_value { + dup_vec[node_idx.to_uint()] = orig_node_idx.to_uint(); + } else if dup_vec[node_idx.to_uint()] != orig_node_idx.to_uint() { + state.dup_found = true; + } + + debug!("collect_concrete_regions(orig_node_idx=%?, node_idx=%?, \ + classification=%?)", + orig_node_idx, node_idx, classification); + + // figure out the direction from which this node takes its + // values, and search for concrete regions etc in that direction + let dir = match classification { + Expanding => Incoming, + Contracting => Outgoing + }; + + process_edges(self, &mut state, graph, node_idx, dir); + } + + let WalkState {result, dup_found, _} = state; + return (result, dup_found); + + fn process_edges(self: &mut RegionVarBindings, + state: &mut WalkState, + graph: &Graph, + source_vid: RegionVid, + dir: Direction) { + debug!("process_edges(source_vid=%?, dir=%?)", source_vid, dir); + + for self.each_edge(graph, source_vid, dir) |edge| { match edge.constraint { - ConstrainVarSubVar(from_vid, to_vid) => { - let vid = match dir { - Incoming => from_vid, - Outgoing => to_vid - }; - if set.insert(vid.to_uint()) { - stack.push(vid); + ConstrainVarSubVar(from_vid, to_vid) => { + let opp_vid = + if from_vid == source_vid {to_vid} else {from_vid}; + if state.set.insert(opp_vid) { + state.stack.push(opp_vid); + } } - } - - ConstrainRegSubVar(region, _) => { - assert!(dir == Incoming); - result.push(SpannedRegion { - region: region, - span: edge.span - }); - } - ConstrainVarSubReg(_, region) => { - assert!(dir == Outgoing); - result.push(SpannedRegion { - region: region, - span: edge.span - }); - } + ConstrainRegSubVar(region, _) | + ConstrainVarSubReg(_, region) => { + state.result.push(SpannedRegion { + region: region, + span: edge.span + }); + } } } } - return result; } fn each_edge(&mut self, diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index bc13074422450..8db4774322a05 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -23,7 +23,7 @@ pub enum VarValue { } pub struct ValsAndBindings { - vals: @mut SmallIntMap>, + vals: SmallIntMap>, bindings: ~[(V, VarValue)], } @@ -60,26 +60,25 @@ pub impl InferCtxt { vid: V) -> Node { let vid_u = vid.to_uint(); - match vb.vals.find(&vid_u) { + let var_val = match vb.vals.find(&vid_u) { + Some(&var_val) => var_val, None => { tcx.sess.bug(fmt!( "failed lookup of vid `%u`", vid_u)); } - Some(var_val) => { - match *var_val { - Redirect(vid) => { - let node: Node = helper(tcx, vb, vid); - if node.root != vid { - // Path compression - vb.vals.insert(vid.to_uint(), - Redirect(node.root)); - } - node - } - Root(ref pt, rk) => { - Node {root: vid, possible_types: *pt, rank: rk} - } + }; + match var_val { + Redirect(vid) => { + let node: Node = helper(tcx, vb, vid); + if node.root != vid { + // Path compression + vb.vals.insert(vid.to_uint(), + Redirect(node.root)); } + node + } + Root(pt, rk) => { + Node {root: vid, possible_types: pt, rank: rk} } } } @@ -99,8 +98,8 @@ pub impl InferCtxt { { // FIXME(#4903)---borrow checker is not flow sensitive let vb = UnifyVid::appropriate_vals_and_bindings(self); - let old_v = vb.vals.get(&vid.to_uint()); - vb.bindings.push((vid, *old_v)); + let old_v = { *vb.vals.get(&vid.to_uint()) }; // FIXME(#4903) + vb.bindings.push((vid, old_v)); vb.vals.insert(vid.to_uint(), new_v); } } diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index aa8c3f8fd1b7e..d99d87231bece 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -65,6 +65,9 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) Some(&ast_map::node_block(ref blk)) => { explain_span(cx, "block", blk.span) } + Some(&ast_map::node_callee_scope(expr)) => { + explain_span(cx, "callee", expr.span) + } Some(&ast_map::node_expr(expr)) => { match expr.node { ast::expr_call(*) => explain_span(cx, "call", expr.span), @@ -113,6 +116,8 @@ pub fn explain_region_and_span(cx: ctxt, region: ty::Region) re_static => { (~"the static lifetime", None) } + re_empty => { (~"the empty lifetime", None) } + // I believe these cases should not occur (except when debugging, // perhaps) re_infer(_) | re_bound(_) => { @@ -212,7 +217,8 @@ pub fn region_to_str_space(cx: ctxt, prefix: &str, region: Region) -> ~str { bound_region_to_str_space(cx, prefix, br) } re_infer(ReVar(_)) => prefix.to_str(), - re_static => fmt!("%s'static ", prefix) + re_static => fmt!("%s'static ", prefix), + re_empty => fmt!("%s' ", prefix) } } @@ -740,6 +746,15 @@ impl Repr for ty::vstore { } } +impl Repr for ast_map::path_elt { + fn repr(&self, tcx: ctxt) -> ~str { + match *self { + ast_map::path_mod(id) => id.repr(tcx), + ast_map::path_name(id) => id.repr(tcx) + } + } +} + // Local Variables: // mode: rust // fill-column: 78; diff --git a/src/libstd/arc.rs b/src/libstd/arc.rs index f45fb4e765833..027bf93b4814f 100644 --- a/src/libstd/arc.rs +++ b/src/libstd/arc.rs @@ -419,26 +419,26 @@ pub struct RWReadMode<'self, T> { pub impl<'self, T:Const + Owned> RWWriteMode<'self, T> { /// Access the pre-downgrade RWARC in write mode. - fn write(&self, blk: &fn(x: &mut T) -> U) -> U { + fn write(&mut self, blk: &fn(x: &mut T) -> U) -> U { match *self { RWWriteMode { - data: ref data, + data: &ref mut data, token: ref token, poison: _ } => { do token.write { - blk(&mut **data) + blk(data) } } } } /// Access the pre-downgrade RWARC in write mode with a condvar. - fn write_cond<'x, 'c, U>(&self, + fn write_cond<'x, 'c, U>(&mut self, blk: &fn(x: &'x mut T, c: &'c Condvar) -> U) -> U { match *self { RWWriteMode { - data: ref data, + data: &ref mut data, token: ref token, poison: ref poison } => { @@ -449,7 +449,7 @@ pub impl<'self, T:Const + Owned> RWWriteMode<'self, T> { failed: &mut *poison.failed, cond: cond }; - blk(&mut **data, &cvar) + blk(data, &cvar) } } } diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index 5314c35419cc5..d48d7af354b41 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -215,16 +215,16 @@ pub struct Bitv { nbits: uint } -priv impl Bitv { +fn die() -> ! { + fail!(~"Tried to do operation on bit vectors with different sizes"); +} - fn die(&self) -> ! { - fail!(~"Tried to do operation on bit vectors with different sizes"); - } +priv impl Bitv { #[inline(always)] fn do_op(&mut self, op: Op, other: &Bitv) -> bool { if self.nbits != other.nbits { - self.die(); + die(); } match self.rep { Small(ref mut s) => match other.rep { @@ -234,10 +234,10 @@ priv impl Bitv { Assign => s.become(*s1, self.nbits), Difference => s.difference(*s1, self.nbits) }, - Big(_) => self.die() + Big(_) => die() }, Big(ref mut s) => match other.rep { - Small(_) => self.die(), + Small(_) => die(), Big(ref s1) => match op { Union => s.union(*s1, self.nbits), Intersect => s.intersect(*s1, self.nbits), diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 764152d6812c5..ec4c025180c7f 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -885,8 +885,8 @@ impl io::Reader for TcpSocketBuf { let ncopy = uint::min(nbuffered, needed); let dst = ptr::mut_offset( vec::raw::to_mut_ptr(buf), count); - let src = ptr::const_offset( - vec::raw::to_const_ptr(self.data.buf), + let src = ptr::offset( + vec::raw::to_ptr(self.data.buf), self.data.buf_off); ptr::copy_memory(dst, src, ncopy); self.data.buf_off += ncopy; @@ -969,7 +969,7 @@ impl io::Reader for TcpSocketBuf { /// Implementation of `io::Reader` trait for a buffered `net::tcp::TcpSocket` impl io::Writer for TcpSocketBuf { - pub fn write(&self, data: &const [u8]) { + pub fn write(&self, data: &[u8]) { unsafe { let socket_data_ptr: *TcpSocketData = &(*((*(self.data)).sock).socket_data); diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index 032df4c819cdd..29d108e3ac2b1 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -20,9 +20,6 @@ use core::hashmap::{HashMap, HashSet}; use core::trie::{TrieMap, TrieSet}; use deque::Deque; use dlist::DList; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] use treemap::{TreeMap, TreeSet}; pub trait Encoder { @@ -730,9 +727,6 @@ impl Decodable for TrieSet { } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl< E: Encoder, K: Encodable + Eq + TotalOrd, @@ -750,9 +744,6 @@ impl< } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl< D: Decoder, K: Decodable + Eq + TotalOrd, @@ -771,9 +762,6 @@ impl< } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl< S: Encoder, T: Encodable + Eq + TotalOrd @@ -789,9 +777,6 @@ impl< } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl< D: Decoder, T: Decodable + Eq + TotalOrd diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index 3e6011e80df81..c153d7f22c034 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -61,6 +61,7 @@ pub fn merge_sort(v: &const [T], le: Le) -> ~[T] { } } +#[cfg(stage0)] fn part(arr: &mut [T], left: uint, right: uint, pivot: uint, compare_func: Le) -> uint { arr[pivot] <-> arr[right]; @@ -79,6 +80,23 @@ fn part(arr: &mut [T], left: uint, return storage_index; } +#[cfg(not(stage0))] +fn part(arr: &mut [T], left: uint, + right: uint, pivot: uint, compare_func: Le) -> uint { + arr[pivot] <-> arr[right]; + let mut storage_index: uint = left; + let mut i: uint = left; + while i < right { + if compare_func(&arr[i], &arr[right]) { + arr[i] <-> arr[storage_index]; + storage_index += 1; + } + i += 1; + } + arr[storage_index] <-> arr[right]; + return storage_index; +} + fn qsort(arr: &mut [T], left: uint, right: uint, compare_func: Le) { if right > left { @@ -162,7 +180,8 @@ fn qsort3(arr: &mut [T], left: int, right: int) { */ pub fn quick_sort3(arr: &mut [T]) { if arr.len() <= 1 { return; } - qsort3(arr, 0, (arr.len() - 1) as int); + let len = arr.len() - 1; // FIXME(#5074) nested calls + qsort3(arr, 0, (len - 1) as int); } pub trait Sort { @@ -195,15 +214,20 @@ pub fn tim_sort(array: &mut [T]) { let mut idx = 0; let mut remaining = size; loop { - let arr = vec::mut_slice(array, idx, size); - let mut run_len: uint = count_run_ascending(arr); - - if run_len < min_run { - let force = if remaining <= min_run {remaining} else {min_run}; - let slice = vec::mut_slice(arr, 0, force); - binarysort(slice, run_len); - run_len = force; - } + let run_len: uint = { + // This scope contains the slice `arr` here: + let arr = vec::mut_slice(array, idx, size); + let mut run_len: uint = count_run_ascending(arr); + + if run_len < min_run { + let force = if remaining <= min_run {remaining} else {min_run}; + let slice = vec::mut_slice(arr, 0, force); + binarysort(slice, run_len); + run_len = force; + } + + run_len + }; ms.push_run(idx, run_len); ms.merge_collapse(array); @@ -250,7 +274,7 @@ fn binarysort(array: &mut [T], start: uint) { fn reverse_slice(v: &mut [T], start: uint, end:uint) { let mut i = start; while i < end / 2 { - util::swap(&mut v[i], &mut v[end - i - 1]); + v[i] <-> v[end - i - 1]; i += 1; } } @@ -433,14 +457,17 @@ impl MergeState { self.runs[n+1].len = self.runs[n+2].len; } - let slice = vec::mut_slice(array, b1, b1+l1); - let k = gallop_right(&const array[b2], slice, 0); + let k = { // constrain lifetime of slice below + let slice = vec::mut_slice(array, b1, b1+l1); + gallop_right(&const array[b2], slice, 0) + }; b1 += k; l1 -= k; if l1 != 0 { - let slice = vec::mut_slice(array, b2, b2+l2); - let l2 = gallop_left( - &const array[b1+l1-1],slice,l2-1); + let l2 = { // constrain lifetime of slice below + let slice = vec::mut_slice(array, b2, b2+l2); + gallop_left(&const array[b1+l1-1],slice,l2-1) + }; if l2 > 0 { if l1 <= l2 { self.merge_lo(array, b1, l1, b2, l2); @@ -621,9 +648,11 @@ impl MergeState { loop { assert!(len2 > 1 && len1 != 0); - let tmp_view = vec::mut_slice(array, base1, base1+len1); - count1 = len1 - gallop_right( - &const tmp[c2], tmp_view, len1-1); + { // constrain scope of tmp_view: + let tmp_view = vec::mut_slice (array, base1, base1+len1); + count1 = len1 - gallop_right( + &const tmp[c2], tmp_view, len1-1); + } if count1 != 0 { dest -= count1; c1 -= count1; len1 -= count1; @@ -636,12 +665,11 @@ impl MergeState { if len2 == 1 { break_outer = true; break; } let count2; - { + { // constrain scope of tmp_view let tmp_view = vec::mut_slice(tmp, 0, len2); count2 = len2 - gallop_left(&const array[c1], tmp_view, len2-1); - // Make tmp_view go out of scope to appease borrowck. } if count2 != 0 { diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 40db9f89d0fd7..d9af8b111bba7 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -71,7 +71,6 @@ pub mod rope; pub mod smallintmap; pub mod sort; pub mod dlist; -#[cfg(not(stage0))] pub mod treemap; // And ... other stuff diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index f9828ad2b9e4e..eb131b17c2f39 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -19,6 +19,7 @@ use diagnostic::span_handler; use parse::token::ident_interner; use print::pprust; use visit; +use syntax::parse::token::special_idents; use core::hashmap::HashMap; @@ -89,14 +90,13 @@ pub enum ast_node { node_variant(variant, @item, @path), node_expr(@expr), node_stmt(@stmt), - // Locals are numbered, because the alias analysis needs to know in which - // order they are introduced. - node_arg(arg, uint), - node_local(uint), + node_arg, + node_local(ident), // Destructor for a struct node_dtor(Generics, @struct_dtor, def_id, @path), node_block(blk), node_struct_ctor(@struct_def, @item, @path), + node_callee_scope(@expr) } pub type map = @mut HashMap; @@ -104,7 +104,6 @@ pub type map = @mut HashMap; pub struct Ctx { map: map, path: path, - local_id: uint, diag: @span_handler, } @@ -120,9 +119,8 @@ pub fn mk_ast_map_visitor() -> vt { visit_expr: map_expr, visit_stmt: map_stmt, visit_fn: map_fn, - visit_local: map_local, - visit_arm: map_arm, visit_block: map_block, + visit_pat: map_pat, .. *visit::default_visitor() }); } @@ -131,7 +129,6 @@ pub fn map_crate(diag: @span_handler, c: @crate) -> map { let cx = @mut Ctx { map: @mut HashMap::new(), path: ~[], - local_id: 0u, diag: diag, }; visit::visit_crate(c, cx, mk_ast_map_visitor()); @@ -154,7 +151,6 @@ pub fn map_decoded_item(diag: @span_handler, let cx = @mut Ctx { map: map, path: copy path, - local_id: 0, diag: diag, }; let v = mk_ast_map_visitor(); @@ -189,9 +185,7 @@ pub fn map_fn( v: visit::vt<@mut Ctx> ) { for decl.inputs.each |a| { - cx.map.insert(a.id, - node_arg(/* FIXME (#2543) */ copy *a, cx.local_id)); - cx.local_id += 1u; + cx.map.insert(a.id, node_arg); } match *fk { visit::fk_dtor(generics, ref attrs, self_id, parent_id) => { @@ -222,33 +216,22 @@ pub fn map_block(b: &blk, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { visit::visit_block(b, cx, v); } -pub fn number_pat(cx: @mut Ctx, pat: @pat) { - do ast_util::walk_pat(pat) |p| { - match p.node { - pat_ident(*) => { - cx.map.insert(p.id, node_local(cx.local_id)); - cx.local_id += 1u; - } - _ => () +pub fn map_pat(pat: @pat, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { + match pat.node { + pat_ident(_, path, _) => { + // Note: this is at least *potentially* a pattern... + cx.map.insert(pat.id, node_local(ast_util::path_to_ident(path))); } - }; -} - -pub fn map_local(loc: @local, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { - number_pat(cx, loc.node.pat); - visit::visit_local(loc, cx, v); -} + _ => () + } -pub fn map_arm(arm: &arm, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { - number_pat(cx, arm.pats[0]); - visit::visit_arm(arm, cx, v); + visit::visit_pat(pat, cx, v); } pub fn map_method(impl_did: def_id, impl_path: @path, m: @method, cx: @mut Ctx) { cx.map.insert(m.id, node_method(m, impl_did, impl_path)); - cx.map.insert(m.self_id, node_local(cx.local_id)); - cx.local_id += 1u; + cx.map.insert(m.self_id, node_local(special_idents::self_)); } pub fn map_item(i: @item, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { @@ -317,6 +300,7 @@ pub fn map_item(i: @item, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { } _ => () } + match i.node { item_mod(_) | item_foreign_mod(_) => { cx.path.push(path_mod(i.ident)); @@ -352,6 +336,18 @@ pub fn map_struct_def( pub fn map_expr(ex: @expr, cx: @mut Ctx, v: visit::vt<@mut Ctx>) { cx.map.insert(ex.id, node_expr(ex)); + match ex.node { + // Expressions which are or might be calls: + ast::expr_call(*) | + ast::expr_method_call(*) | + ast::expr_index(*) | + ast::expr_binary(*) | + ast::expr_assign_op(*) | + ast::expr_unary(*) => { + cx.map.insert(ex.callee_id, node_callee_scope(ex)); + } + _ => {} + } visit::visit_expr(ex, cx, v); } @@ -401,15 +397,18 @@ pub fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str { Some(&node_expr(expr)) => { fmt!("expr %s (id=%?)", pprust::expr_to_str(expr, itr), id) } + Some(&node_callee_scope(expr)) => { + fmt!("callee_scope %s (id=%?)", pprust::expr_to_str(expr, itr), id) + } Some(&node_stmt(stmt)) => { fmt!("stmt %s (id=%?)", pprust::stmt_to_str(stmt, itr), id) } - Some(&node_arg(_, _)) => { // add more info here + Some(&node_arg) => { fmt!("arg (id=%?)", id) } - Some(&node_local(_)) => { // add more info here - fmt!("local (id=%?)", id) + Some(&node_local(ident)) => { + fmt!("local (id=%?, name=%s)", id, *itr.get(ident)) } Some(&node_dtor(*)) => { // add more info here fmt!("node_dtor (id=%?)", id) diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 148b713a4f58f..7e24adabdb048 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -388,8 +388,20 @@ pub struct id_range { max: node_id, } -pub fn empty(range: id_range) -> bool { - range.min >= range.max +pub impl id_range { + fn max() -> id_range { + id_range {min: int::max_value, + max: int::min_value} + } + + fn empty(&self) -> bool { + self.min >= self.max + } + + fn add(&mut self, id: node_id) { + self.min = int::min(self.min, id); + self.max = int::max(self.max, id + 1); + } } pub fn id_visitor(vfn: @fn(node_id)) -> visit::vt<()> { @@ -493,13 +505,11 @@ pub fn visit_ids_for_inlined_item(item: &inlined_item, vfn: @fn(node_id)) { } pub fn compute_id_range(visit_ids_fn: &fn(@fn(node_id))) -> id_range { - let min = @mut int::max_value; - let max = @mut int::min_value; + let result = @mut id_range::max(); do visit_ids_fn |id| { - *min = int::min(*min, id); - *max = int::max(*max, id + 1); + result.add(id); } - id_range { min: *min, max: *max } + *result } pub fn compute_id_range_for_inlined_item(item: &inlined_item) -> id_range { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 1194506a8876f..7facc181effec 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -246,7 +246,7 @@ pub impl FileMap { // the new charpos must be > the last one (or it's the first one). let lines = &mut *self.lines; assert!((lines.len() == 0) || (lines[lines.len() - 1] < pos)); - self.lines.push(pos); + lines.push(pos); } // get a line from the list of pre-computed line-beginnings @@ -308,7 +308,7 @@ pub impl CodeMap { multibyte_chars: @mut ~[], }; - self.files.push(filemap); + files.push(filemap); return filemap; } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 5bad9ecae3ed7..7d058f22e4c45 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -210,29 +210,29 @@ pub fn syntax_expander_table() -> SyntaxEnv { // when a macro expansion occurs, the resulting nodes have the backtrace() // -> expn_info of their expansion context stored into their span. pub trait ext_ctxt { - fn codemap(@mut self) -> @CodeMap; - fn parse_sess(@mut self) -> @mut parse::ParseSess; - fn cfg(@mut self) -> ast::crate_cfg; - fn call_site(@mut self) -> span; - fn print_backtrace(@mut self); - fn backtrace(@mut self) -> Option<@ExpnInfo>; - fn mod_push(@mut self, mod_name: ast::ident); - fn mod_pop(@mut self); - fn mod_path(@mut self) -> ~[ast::ident]; - fn bt_push(@mut self, ei: codemap::ExpnInfo); - fn bt_pop(@mut self); - fn span_fatal(@mut self, sp: span, msg: &str) -> !; - fn span_err(@mut self, sp: span, msg: &str); - fn span_warn(@mut self, sp: span, msg: &str); - fn span_unimpl(@mut self, sp: span, msg: &str) -> !; - fn span_bug(@mut self, sp: span, msg: &str) -> !; - fn bug(@mut self, msg: &str) -> !; - fn next_id(@mut self) -> ast::node_id; - fn trace_macros(@mut self) -> bool; - fn set_trace_macros(@mut self, x: bool); + fn codemap(&self) -> @CodeMap; + fn parse_sess(&self) -> @mut parse::ParseSess; + fn cfg(&self) -> ast::crate_cfg; + fn call_site(&self) -> span; + fn print_backtrace(&self); + fn backtrace(&self) -> Option<@ExpnInfo>; + fn mod_push(&self, mod_name: ast::ident); + fn mod_pop(&self); + fn mod_path(&self) -> ~[ast::ident]; + fn bt_push(&self, ei: codemap::ExpnInfo); + fn bt_pop(&self); + fn span_fatal(&self, sp: span, msg: &str) -> !; + fn span_err(&self, sp: span, msg: &str); + fn span_warn(&self, sp: span, msg: &str); + fn span_unimpl(&self, sp: span, msg: &str) -> !; + fn span_bug(&self, sp: span, msg: &str) -> !; + fn bug(&self, msg: &str) -> !; + fn next_id(&self) -> ast::node_id; + fn trace_macros(&self) -> bool; + fn set_trace_macros(&self, x: bool); /* for unhygienic identifier transformation */ - fn str_of(@mut self, id: ast::ident) -> ~str; - fn ident_of(@mut self, st: ~str) -> ast::ident; + fn str_of(&self, id: ast::ident) -> ~str; + fn ident_of(&self, st: ~str) -> ast::ident; } pub fn mk_ctxt(parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg) @@ -241,25 +241,31 @@ pub fn mk_ctxt(parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg) parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg, backtrace: @mut Option<@ExpnInfo>, - mod_path: ~[ast::ident], - trace_mac: bool + + // These two @mut's should really not be here, + // but the self types for CtxtRepr are all wrong + // and there are bugs in the code for object + // types that make this hard to get right at the + // moment. - nmatsakis + mod_path: @mut ~[ast::ident], + trace_mac: @mut bool } impl ext_ctxt for CtxtRepr { - fn codemap(@mut self) -> @CodeMap { self.parse_sess.cm } - fn parse_sess(@mut self) -> @mut parse::ParseSess { self.parse_sess } - fn cfg(@mut self) -> ast::crate_cfg { copy self.cfg } - fn call_site(@mut self) -> span { + fn codemap(&self) -> @CodeMap { self.parse_sess.cm } + fn parse_sess(&self) -> @mut parse::ParseSess { self.parse_sess } + fn cfg(&self) -> ast::crate_cfg { copy self.cfg } + fn call_site(&self) -> span { match *self.backtrace { Some(@ExpandedFrom(CallInfo {call_site: cs, _})) => cs, None => self.bug(~"missing top span") } } - fn print_backtrace(@mut self) { } - fn backtrace(@mut self) -> Option<@ExpnInfo> { *self.backtrace } - fn mod_push(@mut self, i: ast::ident) { self.mod_path.push(i); } - fn mod_pop(@mut self) { self.mod_path.pop(); } - fn mod_path(@mut self) -> ~[ast::ident] { copy self.mod_path } - fn bt_push(@mut self, ei: codemap::ExpnInfo) { + fn print_backtrace(&self) { } + fn backtrace(&self) -> Option<@ExpnInfo> { *self.backtrace } + fn mod_push(&self, i: ast::ident) { self.mod_path.push(i); } + fn mod_pop(&self) { self.mod_path.pop(); } + fn mod_path(&self) -> ~[ast::ident] { copy *self.mod_path } + fn bt_push(&self, ei: codemap::ExpnInfo) { match ei { ExpandedFrom(CallInfo {call_site: cs, callee: ref callee}) => { *self.backtrace = @@ -270,7 +276,7 @@ pub fn mk_ctxt(parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg) } } } - fn bt_pop(@mut self) { + fn bt_pop(&self) { match *self.backtrace { Some(@ExpandedFrom(CallInfo { call_site: span {expn_info: prev, _}, _ @@ -280,52 +286,52 @@ pub fn mk_ctxt(parse_sess: @mut parse::ParseSess, cfg: ast::crate_cfg) _ => self.bug(~"tried to pop without a push") } } - fn span_fatal(@mut self, sp: span, msg: &str) -> ! { + fn span_fatal(&self, sp: span, msg: &str) -> ! { self.print_backtrace(); self.parse_sess.span_diagnostic.span_fatal(sp, msg); } - fn span_err(@mut self, sp: span, msg: &str) { + fn span_err(&self, sp: span, msg: &str) { self.print_backtrace(); self.parse_sess.span_diagnostic.span_err(sp, msg); } - fn span_warn(@mut self, sp: span, msg: &str) { + fn span_warn(&self, sp: span, msg: &str) { self.print_backtrace(); self.parse_sess.span_diagnostic.span_warn(sp, msg); } - fn span_unimpl(@mut self, sp: span, msg: &str) -> ! { + fn span_unimpl(&self, sp: span, msg: &str) -> ! { self.print_backtrace(); self.parse_sess.span_diagnostic.span_unimpl(sp, msg); } - fn span_bug(@mut self, sp: span, msg: &str) -> ! { + fn span_bug(&self, sp: span, msg: &str) -> ! { self.print_backtrace(); self.parse_sess.span_diagnostic.span_bug(sp, msg); } - fn bug(@mut self, msg: &str) -> ! { + fn bug(&self, msg: &str) -> ! { self.print_backtrace(); self.parse_sess.span_diagnostic.handler().bug(msg); } - fn next_id(@mut self) -> ast::node_id { + fn next_id(&self) -> ast::node_id { return parse::next_node_id(self.parse_sess); } - fn trace_macros(@mut self) -> bool { - self.trace_mac + fn trace_macros(&self) -> bool { + *self.trace_mac } - fn set_trace_macros(@mut self, x: bool) { - self.trace_mac = x + fn set_trace_macros(&self, x: bool) { + *self.trace_mac = x } - fn str_of(@mut self, id: ast::ident) -> ~str { + fn str_of(&self, id: ast::ident) -> ~str { copy *self.parse_sess.interner.get(id) } - fn ident_of(@mut self, st: ~str) -> ast::ident { + fn ident_of(&self, st: ~str) -> ast::ident { self.parse_sess.interner.intern(@/*bad*/ copy st) } } - let imp: @mut CtxtRepr = @mut CtxtRepr { + let imp: @CtxtRepr = @CtxtRepr { parse_sess: parse_sess, cfg: cfg, backtrace: @mut None, - mod_path: ~[], - trace_mac: false + mod_path: @mut ~[], + trace_mac: @mut false }; ((imp) as @ext_ctxt) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index fde5a2594226e..841f64e0b0502 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -27,6 +27,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv, fld: @ast_fold, orig: @fn(&expr_, span, @ast_fold) -> (expr_, span)) -> (expr_, span) { + let mut cx = cx; match *e { // expr_mac should really be expr_ext or something; it's the // entry-point for all syntax extensions. @@ -112,6 +113,8 @@ pub fn expand_mod_items(extsbox: @mut SyntaxEnv, fld: @ast_fold, orig: @fn(&ast::_mod, @ast_fold) -> ast::_mod) -> ast::_mod { + let mut cx = cx; + // Fold the contents first: let module_ = orig(module_, fld); diff --git a/src/libsyntax/ext/pipes/liveness.rs b/src/libsyntax/ext/pipes/liveness.rs index 4597dab89cbfe..7843db5578929 100644 --- a/src/libsyntax/ext/pipes/liveness.rs +++ b/src/libsyntax/ext/pipes/liveness.rs @@ -38,11 +38,11 @@ updating the states using rule (2) until there are no changes. */ use ext::base::ext_ctxt; -use ext::pipes::proto::protocol; +use ext::pipes::proto::{protocol_}; use std::bitv::Bitv; -pub fn analyze(proto: protocol, _cx: @ext_ctxt) { +pub fn analyze(proto: &mut protocol_, _cx: @ext_ctxt) { debug!("initializing colive analysis"); let num_states = proto.num_states(); let mut colive = do (copy proto.states).map_to_vec |state| { diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs index 79072a2f577ff..ffb55ee50d992 100644 --- a/src/libsyntax/ext/pipes/proto.rs +++ b/src/libsyntax/ext/pipes/proto.rs @@ -138,26 +138,26 @@ pub struct protocol_ { pub impl protocol_ { /// Get a state. - fn get_state(&mut self, name: ~str) -> state { + fn get_state(&self, name: ~str) -> state { self.states.find(|i| i.name == name).get() } - fn get_state_by_id(&mut self, id: uint) -> state { self.states[id] } + fn get_state_by_id(&self, id: uint) -> state { self.states[id] } - fn has_state(&mut self, name: ~str) -> bool { + fn has_state(&self, name: ~str) -> bool { self.states.find(|i| i.name == name).is_some() } - fn filename(&mut self) -> ~str { + fn filename(&self) -> ~str { ~"proto://" + self.name } - fn num_states(&mut self) -> uint { + fn num_states(&self) -> uint { let states = &mut *self.states; states.len() } - fn has_ty_params(&mut self) -> bool { + fn has_ty_params(&self) -> bool { for self.states.each |s| { if s.generics.ty_params.len() > 0 { return true; @@ -165,7 +165,7 @@ pub impl protocol_ { } false } - fn is_bounded(&mut self) -> bool { + fn is_bounded(&self) -> bool { let bounded = self.bounded.get(); bounded } @@ -179,7 +179,7 @@ pub impl protocol_ { generics: ast::Generics) -> state { let messages = @mut ~[]; - let states = &*self.states; + let states = &mut *self.states; let state = @state_ { id: states.len(), @@ -192,7 +192,7 @@ pub impl protocol_ { proto: self }; - self.states.push(state); + states.push(state); state } } diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index e2ad5becb123b..c1acee8e2cd96 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -491,9 +491,9 @@ pub impl Printer { } END => { debug!("print END -> pop END"); - let print_stack = &*self.print_stack; + let print_stack = &mut *self.print_stack; assert!((print_stack.len() != 0u)); - self.print_stack.pop(); + print_stack.pop(); } BREAK(b) => { let top = self.get_top(); diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index d5645ada9294a..ff8259e899699 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -72,6 +72,12 @@ pub fn end(s: @ps) { } pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps { + return rust_printer_annotated(writer, intr, no_ann()); +} + +pub fn rust_printer_annotated(writer: @io::Writer, + intr: @ident_interner, + ann: pp_ann) -> @ps { return @ps { s: pp::mk_printer(writer, default_columns), cm: None::<@CodeMap>, @@ -83,7 +89,7 @@ pub fn rust_printer(writer: @io::Writer, intr: @ident_interner) -> @ps { cur_lit: 0 }, boxes: @mut ~[], - ann: no_ann() + ann: ann }; } diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs index 9ab7d4bc443ef..e3a8727762218 100644 --- a/src/libsyntax/util/interner.rs +++ b/src/libsyntax/util/interner.rs @@ -44,10 +44,10 @@ pub impl Interner { None => (), } - let vect = &*self.vect; + let vect = &mut *self.vect; let new_idx = vect.len(); self.map.insert(val, new_idx); - self.vect.push(val); + vect.push(val); new_idx } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 80df8fb91a515..a42f640a175a7 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -22,6 +22,12 @@ use opt_vec::OptVec; // children (potentially passing in different contexts to each), call // visit::visit_* to apply the default traversal algorithm (again, it can // override the context), or prevent deeper traversal by doing nothing. +// +// Note: it is an important invariant that the default visitor walks the body +// of a function in "execution order" (more concretely, reverse post-order +// with respect to the CFG implied by the AST), meaning that if AST node A may +// execute before AST node B, then A is visited first. The borrow checker in +// particular relies on this property. // Our typesystem doesn't do circular types, so the visitor record can not // hold functions that take visitors. A vt enum is used to break the cycle. diff --git a/src/test/compile-fail/access-mode-in-closures.rs b/src/test/compile-fail/access-mode-in-closures.rs index f6b9a82ec676c..61fb754f7619f 100644 --- a/src/test/compile-fail/access-mode-in-closures.rs +++ b/src/test/compile-fail/access-mode-in-closures.rs @@ -16,6 +16,6 @@ fn unpack(_unpack: &fn(v: &sty) -> ~[int]) {} fn main() { let _foo = unpack(|s| { // Test that `s` is moved here. - match *s { sty(v) => v } //~ ERROR moving out of dereference of immutable & pointer + match *s { sty(v) => v } //~ ERROR cannot move out }); } diff --git a/src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs index e2dd13a4405d1..85f60f34bdb80 100644 --- a/src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-read-mode-shouldnt-escape.rs @@ -17,6 +17,7 @@ fn main() { y = Some(x.downgrade(write_mode)); //~^ ERROR cannot infer an appropriate lifetime } + y.get(); // Adding this line causes a method unification failure instead // do (&option::unwrap(y)).read |state| { assert!(*state == 1); } } diff --git a/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs b/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs index 78a50a4f21242..c7ae6a0dc6c52 100644 --- a/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs +++ b/src/test/compile-fail/arc-rw-write-mode-shouldnt-escape.rs @@ -17,6 +17,7 @@ fn main() { do x.write_downgrade |write_mode| { y = Some(write_mode); } + y.get(); // Adding this line causes a method unification failure instead // do (&option::unwrap(y)).write |state| { assert!(*state == 1); } } diff --git a/src/test/compile-fail/attempted-access-non-fatal.rs b/src/test/compile-fail/attempted-access-non-fatal.rs index ba15abc3f8965..1d9249bc17b1f 100644 --- a/src/test/compile-fail/attempted-access-non-fatal.rs +++ b/src/test/compile-fail/attempted-access-non-fatal.rs @@ -11,6 +11,6 @@ // Check that bogus field access is non-fatal fn main() { let x = 0; - debug!(x.foo); //~ ERROR attempted access of field - debug!(x.bar); //~ ERROR attempted access of field + let _ = x.foo; //~ ERROR attempted access of field + let _ = x.bar; //~ ERROR attempted access of field } diff --git a/src/test/compile-fail/borrowck-addr-of-upvar.rs b/src/test/compile-fail/borrowck-addr-of-upvar.rs index 640bc887731f9..83baedc789277 100644 --- a/src/test/compile-fail/borrowck-addr-of-upvar.rs +++ b/src/test/compile-fail/borrowck-addr-of-upvar.rs @@ -9,12 +9,12 @@ // except according to those terms. fn foo(x: @int) -> @fn() -> &'static int { - let result: @fn() -> &'static int = || &*x; //~ ERROR illegal borrow + let result: @fn() -> &'static int = || &*x; //~ ERROR cannot root result } fn bar(x: @int) -> @fn() -> &int { - let result: @fn() -> &int = || &*x; //~ ERROR illegal borrow + let result: @fn() -> &int = || &*x; //~ ERROR cannot root result } diff --git a/src/test/compile-fail/borrowck-assign-comp-idx.rs b/src/test/compile-fail/borrowck-assign-comp-idx.rs index 25b56abb5ba00..d447d9e4a2288 100644 --- a/src/test/compile-fail/borrowck-assign-comp-idx.rs +++ b/src/test/compile-fail/borrowck-assign-comp-idx.rs @@ -17,9 +17,11 @@ fn a() { let mut p = ~[1]; // Create an immutable pointer into p's contents: - let _q: &int = &p[0]; //~ NOTE loan of mutable vec content granted here + let q: &int = &p[0]; - p[0] = 5; //~ ERROR assigning to mutable vec content prohibited due to outstanding loan + p[0] = 5; //~ ERROR cannot assign + + debug!("%d", *q); } fn borrow(_x: &[int], _f: &fn()) {} @@ -30,8 +32,8 @@ fn b() { let mut p = ~[1]; - do borrow(p) { //~ NOTE loan of mutable vec content granted here - p[0] = 5; //~ ERROR assigning to mutable vec content prohibited due to outstanding loan + do borrow(p) { + p[0] = 5; //~ ERROR cannot assign to } } diff --git a/src/test/compile-fail/borrowck-assign-comp.rs b/src/test/compile-fail/borrowck-assign-comp.rs index 283f04a283f4e..b8c0cbe97433e 100644 --- a/src/test/compile-fail/borrowck-assign-comp.rs +++ b/src/test/compile-fail/borrowck-assign-comp.rs @@ -12,12 +12,13 @@ struct point { x: int, y: int } fn a() { let mut p = point {x: 3, y: 4}; - let _q = &p; //~ NOTE loan of mutable local variable granted here + let q = &p; // This assignment is illegal because the field x is not // inherently mutable; since `p` was made immutable, `p.x` is now // immutable. Otherwise the type of &_q.x (&int) would be wrong. - p.x = 5; //~ ERROR assigning to mutable field prohibited due to outstanding loan + p.x = 5; //~ ERROR cannot assign to `p.x` + q.x; } fn c() { @@ -25,9 +26,10 @@ fn c() { // and then try to overwrite `p` as a whole. let mut p = point {x: 3, y: 4}; - let _q = &p.y; //~ NOTE loan of mutable local variable granted here - p = point {x: 5, y: 7};//~ ERROR assigning to mutable local variable prohibited due to outstanding loan - copy p; + let q = &p.y; + p = point {x: 5, y: 7};//~ ERROR cannot assign to `p` + p.x; // silence warning + *q; // stretch loan } fn d() { @@ -35,9 +37,9 @@ fn d() { // address of a subcomponent and then modify that subcomponent: let mut p = point {x: 3, y: 4}; - let _q = &p.y; //~ NOTE loan of mutable field granted here - p.y = 5; //~ ERROR assigning to mutable field prohibited due to outstanding loan - copy p; + let q = &p.y; + p.y = 5; //~ ERROR cannot assign to `p.y` + *q; } fn main() { diff --git a/src/test/compile-fail/borrowck-assign-to-constants.rs b/src/test/compile-fail/borrowck-assign-to-constants.rs index 0d65aacb65b7a..f0dc28b736d16 100644 --- a/src/test/compile-fail/borrowck-assign-to-constants.rs +++ b/src/test/compile-fail/borrowck-assign-to-constants.rs @@ -12,6 +12,6 @@ static foo: int = 5; fn main() { // assigning to various global constants - None = Some(3); //~ ERROR assigning to static item - foo = 6; //~ ERROR assigning to static item + None = Some(3); //~ ERROR cannot assign to immutable static item + foo = 6; //~ ERROR cannot assign to immutable static item } diff --git a/src/test/compile-fail/borrowck-assign-to-enum.rs b/src/test/compile-fail/borrowck-assign-to-enum.rs index a35d88a76f393..fcaba0adc46eb 100644 --- a/src/test/compile-fail/borrowck-assign-to-enum.rs +++ b/src/test/compile-fail/borrowck-assign-to-enum.rs @@ -12,5 +12,5 @@ struct foo(int); fn main() { let x = foo(3); - *x = 4; //~ ERROR assigning to anonymous field + *x = 4; //~ ERROR cannot assign to immutable anonymous field } diff --git a/src/test/compile-fail/borrowck-assign-to-subfield.rs b/src/test/compile-fail/borrowck-assign-to-subfield.rs index 610802ca68b31..2ee5ecfcb9ce0 100644 --- a/src/test/compile-fail/borrowck-assign-to-subfield.rs +++ b/src/test/compile-fail/borrowck-assign-to-subfield.rs @@ -34,6 +34,6 @@ fn main() { // in these cases we pass through a box, so the mut // of the box is dominant - p.x.a = 2; //~ ERROR assigning to immutable field + p.x.a = 2; //~ ERROR cannot assign to immutable field p.z.a = 2; } diff --git a/src/test/compile-fail/auto-ref-borrowck-failure.rs b/src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs similarity index 81% rename from src/test/compile-fail/auto-ref-borrowck-failure.rs rename to src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs index 90b9b44cfbea3..ce95ee94f4252 100644 --- a/src/test/compile-fail/auto-ref-borrowck-failure.rs +++ b/src/test/compile-fail/borrowck-auto-mut-ref-to-immut-var.rs @@ -14,18 +14,14 @@ struct Foo { x: int } -trait Stuff { - fn printme(self); -} - -impl<'self> Stuff for &'self mut Foo { - fn printme(self) { +pub impl Foo { + fn printme(&mut self) { io::println(fmt!("%d", self.x)); } } fn main() { let x = Foo { x: 3 }; - x.printme(); //~ ERROR illegal borrow + x.printme(); //~ ERROR cannot borrow } diff --git a/src/test/compile-fail/borrowck-autoref-3261.rs b/src/test/compile-fail/borrowck-autoref-3261.rs index c95b93445adca..192fe669f57ae 100644 --- a/src/test/compile-fail/borrowck-autoref-3261.rs +++ b/src/test/compile-fail/borrowck-autoref-3261.rs @@ -17,10 +17,10 @@ pub impl X { } fn main() { let mut x = X(Right(main)); - do (&mut x).with |opt| { //~ ERROR illegal borrow + do (&mut x).with |opt| { match opt { &Right(ref f) => { - x = X(Left((0,0))); //~ ERROR assigning to captured outer mutable variable + x = X(Left((0,0))); //~ ERROR cannot assign to `x` (*f)() }, _ => fail!() diff --git a/src/test/compile-fail/borrowck-bad-nested-calls-free.rs b/src/test/compile-fail/borrowck-bad-nested-calls-free.rs new file mode 100644 index 0000000000000..ff1ec38ad6406 --- /dev/null +++ b/src/test/compile-fail/borrowck-bad-nested-calls-free.rs @@ -0,0 +1,43 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we detect nested calls that could free pointers evaluated +// for earlier arguments. + +fn rewrite(v: &mut ~uint) -> uint { + *v = ~22; + **v +} + +fn add(v: &uint, w: uint) -> uint { + *v + w +} + +fn implicit() { + let mut a = ~1; + + // Note the danger here: + // + // the pointer for the first argument has already been + // evaluated, but it gets freed when evaluating the second + // argument! + add( + a, + rewrite(&mut a)); //~ ERROR cannot borrow +} + +fn explicit() { + let mut a = ~1; + add( + &*a, + rewrite(&mut a)); //~ ERROR cannot borrow +} + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/borrowck-bad-nested-calls-move.rs b/src/test/compile-fail/borrowck-bad-nested-calls-move.rs new file mode 100644 index 0000000000000..0adf486b8b3ab --- /dev/null +++ b/src/test/compile-fail/borrowck-bad-nested-calls-move.rs @@ -0,0 +1,43 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that we detect nested calls that could free pointers evaluated +// for earlier arguments. + +fn rewrite(v: &mut ~uint) -> uint { + *v = ~22; + **v +} + +fn add(v: &uint, w: ~uint) -> uint { + *v + *w +} + +fn implicit() { + let mut a = ~1; + + // Note the danger here: + // + // the pointer for the first argument has already been + // evaluated, but it gets moved when evaluating the second + // argument! + add( + a, + a); //~ ERROR cannot move +} + +fn explicit() { + let mut a = ~1; + add( + &*a, + a); //~ ERROR cannot move +} + +fn main() {} \ No newline at end of file diff --git a/src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs b/src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs index 005908f86d87d..1051c5829ec38 100644 --- a/src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs +++ b/src/test/compile-fail/borrowck-borrow-from-owned-ptr.rs @@ -22,32 +22,37 @@ fn make_foo() -> ~Foo { fail!() } fn borrow_same_field_twice_mut_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; - let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_same_field_twice_mut_imm() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; - let _bar2 = &foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1; + let _bar2 = &foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_same_field_twice_imm_mut() { let mut foo = make_foo(); - let _bar1 = &foo.bar1; - let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_same_field_twice_imm_imm() { let mut foo = make_foo(); - let _bar1 = &foo.bar1; + let bar1 = &foo.bar1; let _bar2 = &foo.bar1; + *bar1; } -fn borrow_both_mut() { +fn borrow_both_fields_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; + let bar1 = &mut foo.bar1; let _bar2 = &mut foo.bar2; + *bar1; } fn borrow_both_mut_pattern() { @@ -59,66 +64,77 @@ fn borrow_both_mut_pattern() { fn borrow_var_and_pattern() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; + let bar1 = &mut foo.bar1; match *foo { Foo { bar1: ref mut _bar1, bar2: _ } => {} - //~^ ERROR conflicts with prior loan + //~^ ERROR cannot borrow } + *bar1; } fn borrow_mut_and_base_imm() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo1 = &foo.bar1; //~ ERROR conflicts with prior loan - let _foo2 = &*foo; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1.int1; + let _foo1 = &foo.bar1; //~ ERROR cannot borrow + let _foo2 = &*foo; //~ ERROR cannot borrow + *bar1; } fn borrow_mut_and_base_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_mut_and_base_mut2() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo2 = &mut *foo; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1.int1; + let _foo2 = &mut *foo; //~ ERROR cannot borrow + *bar1; } fn borrow_imm_and_base_mut() { let mut foo = make_foo(); - let _bar1 = &foo.bar1.int1; - let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_imm_and_base_mut2() { let mut foo = make_foo(); - let _bar1 = &foo.bar1.int1; - let _foo2 = &mut *foo; //~ ERROR conflicts with prior loan + let bar1 = &foo.bar1.int1; + let _foo2 = &mut *foo; //~ ERROR cannot borrow + *bar1; } fn borrow_imm_and_base_imm() { let mut foo = make_foo(); - let _bar1 = &foo.bar1.int1; + let bar1 = &foo.bar1.int1; let _foo1 = &foo.bar1; let _foo2 = &*foo; + *bar1; } fn borrow_mut_and_imm() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; + let bar1 = &mut foo.bar1; let _foo1 = &foo.bar2; + *bar1; } fn borrow_mut_from_imm() { let foo = make_foo(); - let _bar1 = &mut foo.bar1; //~ ERROR illegal borrow + let bar1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_long_path_both_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo1 = &mut foo.bar2.int2; + let bar1 = &mut foo.bar1.int1; + let foo1 = &mut foo.bar2.int2; + *bar1; + *foo1; } fn main() {} diff --git a/src/test/compile-fail/borrowck-borrow-from-stack-variable.rs b/src/test/compile-fail/borrowck-borrow-from-stack-variable.rs index 035e293bc36b6..cdcf50c906e36 100644 --- a/src/test/compile-fail/borrowck-borrow-from-stack-variable.rs +++ b/src/test/compile-fail/borrowck-borrow-from-stack-variable.rs @@ -22,32 +22,37 @@ fn make_foo() -> Foo { fail!() } fn borrow_same_field_twice_mut_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; - let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_same_field_twice_mut_imm() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; - let _bar2 = &foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1; + let _bar2 = &foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_same_field_twice_imm_mut() { let mut foo = make_foo(); - let _bar1 = &foo.bar1; - let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &foo.bar1; + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_same_field_twice_imm_imm() { let mut foo = make_foo(); - let _bar1 = &foo.bar1; + let bar1 = &foo.bar1; let _bar2 = &foo.bar1; + *bar1; } fn borrow_both_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; + let bar1 = &mut foo.bar1; let _bar2 = &mut foo.bar2; + *bar1; } fn borrow_both_mut_pattern() { @@ -59,66 +64,76 @@ fn borrow_both_mut_pattern() { fn borrow_var_and_pattern() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; + let bar1 = &mut foo.bar1; match foo { - Foo { bar1: ref mut _bar1, bar2: _ } => {} - //~^ ERROR conflicts with prior loan + Foo { bar1: ref mut _bar1, bar2: _ } => {} // + //~^ ERROR cannot borrow } + *bar1; } fn borrow_mut_and_base_imm() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo1 = &foo.bar1; //~ ERROR conflicts with prior loan - let _foo2 = &foo; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1.int1; + let _foo1 = &foo.bar1; //~ ERROR cannot borrow + let _foo2 = &foo; //~ ERROR cannot borrow + *bar1; } fn borrow_mut_and_base_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_mut_and_base_mut2() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; - let _foo2 = &mut foo; //~ ERROR conflicts with prior loan + let bar1 = &mut foo.bar1.int1; + let _foo2 = &mut foo; //~ ERROR cannot borrow + *bar1; } fn borrow_imm_and_base_mut() { let mut foo = make_foo(); - let _bar1 = &foo.bar1.int1; - let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let bar1 = &foo.bar1.int1; + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_imm_and_base_mut2() { let mut foo = make_foo(); - let _bar1 = &foo.bar1.int1; - let _foo2 = &mut foo; //~ ERROR conflicts with prior loan + let bar1 = &foo.bar1.int1; + let _foo2 = &mut foo; //~ ERROR cannot borrow + *bar1; } fn borrow_imm_and_base_imm() { let mut foo = make_foo(); - let _bar1 = &foo.bar1.int1; + let bar1 = &foo.bar1.int1; let _foo1 = &foo.bar1; let _foo2 = &foo; + *bar1; } fn borrow_mut_and_imm() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1; + let bar1 = &mut foo.bar1; let _foo1 = &foo.bar2; + *bar1; } fn borrow_mut_from_imm() { let foo = make_foo(); - let _bar1 = &mut foo.bar1; //~ ERROR illegal borrow + let bar1 = &mut foo.bar1; //~ ERROR cannot borrow + *bar1; } fn borrow_long_path_both_mut() { let mut foo = make_foo(); - let _bar1 = &mut foo.bar1.int1; + let bar1 = &mut foo.bar1.int1; let _foo1 = &mut foo.bar2.int2; + *bar1; } fn main() {} diff --git a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs index 4a6a90ae5167f..1e5c4c5cc410c 100644 --- a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs +++ b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue-2.rs @@ -28,5 +28,6 @@ fn defer<'r>(x: &'r [&'r str]) -> defer<'r> { } fn main() { - let _x = defer(~["Goodbye", "world!"]); //~ ERROR illegal borrow + let x = defer(~["Goodbye", "world!"]); //~ ERROR borrowed value does not live long enough + x.x[0]; } diff --git a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs index bda659aa7b97e..887cb59930ebc 100644 --- a/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs +++ b/src/test/compile-fail/borrowck-borrowed-uniq-rvalue.rs @@ -15,7 +15,7 @@ use core::hashmap::HashMap; fn main() { let mut buggy_map :HashMap = HashMap::new::(); - buggy_map.insert(42, &*~1); //~ ERROR illegal borrow + buggy_map.insert(42, &*~1); //~ ERROR borrowed value does not live long enough // but it is ok if we use a temporary let tmp = ~2; diff --git a/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs b/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs index 2c68429baec92..be51091c1fd1e 100644 --- a/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs +++ b/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs @@ -27,13 +27,15 @@ fn a(x: &mut Foo) { fn b(x: &Foo) { x.f(); x.g(); - x.h(); //~ ERROR illegal borrow + x.h(); //~ ERROR cannot borrow } fn c(x: &const Foo) { - x.f(); //~ ERROR illegal borrow unless pure + x.f(); //~ ERROR cannot borrow + //~^ ERROR unsafe borrow x.g(); - x.h(); //~ ERROR illegal borrow + x.h(); //~ ERROR cannot borrow + //~^ ERROR unsafe borrow } fn main() { diff --git a/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs b/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs index 88db5f5434116..8af10231921aa 100644 --- a/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs +++ b/src/test/compile-fail/borrowck-imm-ref-to-mut-rec-field-issue-3162-c.rs @@ -10,9 +10,9 @@ fn main() { let mut _a = 3; - let _b = &mut _a; //~ NOTE loan of mutable local variable granted here + let _b = &mut _a; { let _c = &*_b; - _a = 4; //~ ERROR assigning to mutable local variable prohibited + _a = 4; //~ ERROR cannot assign to `_a` } } diff --git a/src/test/compile-fail/borrowck-insert-during-each.rs b/src/test/compile-fail/borrowck-insert-during-each.rs index 17c0efe225e4d..109753b38e70b 100644 --- a/src/test/compile-fail/borrowck-insert-during-each.rs +++ b/src/test/compile-fail/borrowck-insert-during-each.rs @@ -23,8 +23,8 @@ pub impl Foo { } fn bar(f: &mut Foo) { - do f.foo |a| { //~ NOTE prior loan as mutable granted here - f.n.insert(*a); //~ ERROR conflicts with prior loan + do f.foo |a| { + f.n.insert(*a); //~ ERROR cannot borrow } } diff --git a/src/test/compile-fail/borrowck-issue-2657-1.rs b/src/test/compile-fail/borrowck-issue-2657-1.rs index ce183c1888f13..8bcd5f9a72e70 100644 --- a/src/test/compile-fail/borrowck-issue-2657-1.rs +++ b/src/test/compile-fail/borrowck-issue-2657-1.rs @@ -10,9 +10,9 @@ fn main() { let x = Some(~1); -match x { //~ NOTE loan of immutable local variable granted here +match x { Some(ref _y) => { - let _a = x; //~ ERROR moving out of immutable local variable prohibited due to outstanding loan + let _a = x; //~ ERROR cannot move } _ => {} } diff --git a/src/test/compile-fail/borrowck-issue-2657-2.rs b/src/test/compile-fail/borrowck-issue-2657-2.rs index d2217778d4148..fac805c57ca09 100644 --- a/src/test/compile-fail/borrowck-issue-2657-2.rs +++ b/src/test/compile-fail/borrowck-issue-2657-2.rs @@ -12,7 +12,7 @@ fn main() { let x = Some(~1); match x { Some(ref y) => { - let _b = *y; //~ ERROR moving out of dereference of immutable & pointer + let _b = *y; //~ ERROR cannot move out } _ => {} } diff --git a/src/test/compile-fail/borrowck-lend-flow-if.rs b/src/test/compile-fail/borrowck-lend-flow-if.rs new file mode 100644 index 0000000000000..563f63b98be05 --- /dev/null +++ b/src/test/compile-fail/borrowck-lend-flow-if.rs @@ -0,0 +1,52 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Note: the borrowck analysis is currently flow-insensitive. +// Therefore, some of these errors are marked as spurious and could be +// corrected by a simple change to the analysis. The others are +// either genuine or would require more advanced changes. The latter +// cases are noted. + +fn borrow(_v: &int) {} +fn borrow_mut(_v: &mut int) {} +fn cond() -> bool { fail!() } +fn for_func(_f: &fn() -> bool) { fail!() } +fn produce() -> T { fail!(); } + +fn inc(v: &mut ~int) { + *v = ~(**v + 1); +} + +fn pre_freeze_cond() { + // In this instance, the freeze is conditional and starts before + // the mut borrow. + + let mut v = ~3; + let _w; + if cond() { + _w = &v; + } + borrow_mut(v); //~ ERROR cannot borrow +} + +fn pre_freeze_else() { + // In this instance, the freeze and mut borrow are on separate sides + // of the if. + + let mut v = ~3; + let _w; + if cond() { + _w = &v; + } else { + borrow_mut(v); + } +} + +fn main() {} diff --git a/src/test/compile-fail/borrowck-lend-flow-loop.rs b/src/test/compile-fail/borrowck-lend-flow-loop.rs new file mode 100644 index 0000000000000..b6384ad9590ab --- /dev/null +++ b/src/test/compile-fail/borrowck-lend-flow-loop.rs @@ -0,0 +1,164 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Note: the borrowck analysis is currently flow-insensitive. +// Therefore, some of these errors are marked as spurious and could be +// corrected by a simple change to the analysis. The others are +// either genuine or would require more advanced changes. The latter +// cases are noted. + +fn borrow(_v: &int) {} +fn borrow_mut(_v: &mut int) {} +fn cond() -> bool { fail!() } +fn for_func(_f: &fn() -> bool) { fail!() } +fn produce() -> T { fail!(); } + +fn inc(v: &mut ~int) { + *v = ~(**v + 1); +} + +fn loop_overarching_alias_mut() { + // In this instance, the borrow encompasses the entire loop. + + let mut v = ~3; + let mut x = &mut v; + **x += 1; + loop { + borrow(v); //~ ERROR cannot borrow + } +} + +fn block_overarching_alias_mut() { + // In this instance, the borrow encompasses the entire closure call. + + let mut v = ~3; + let mut x = &mut v; + for 3.times { + borrow(v); //~ ERROR cannot borrow + } + *x = ~5; +} + +fn loop_aliased_mut() { + // In this instance, the borrow is carried through the loop. + + let mut v = ~3, w = ~4; + let mut _x = &w; + loop { + borrow_mut(v); //~ ERROR cannot borrow + _x = &v; + } +} + +fn while_aliased_mut() { + // In this instance, the borrow is carried through the loop. + + let mut v = ~3, w = ~4; + let mut _x = &w; + while cond() { + borrow_mut(v); //~ ERROR cannot borrow + _x = &v; + } +} + +fn for_loop_aliased_mut() { + // In this instance, the borrow is carried through the loop. + + let mut v = ~3, w = ~4; + let mut _x = &w; + for for_func { + borrow_mut(v); //~ ERROR cannot borrow + _x = &v; + } +} + +fn loop_aliased_mut_break() { + // In this instance, the borrow is carried through the loop. + + let mut v = ~3, w = ~4; + let mut _x = &w; + loop { + borrow_mut(v); + _x = &v; + break; + } + borrow_mut(v); //~ ERROR cannot borrow +} + +fn while_aliased_mut_break() { + // In this instance, the borrow is carried through the loop. + + let mut v = ~3, w = ~4; + let mut _x = &w; + while cond() { + borrow_mut(v); + _x = &v; + break; + } + borrow_mut(v); //~ ERROR cannot borrow +} + +fn for_aliased_mut_break() { + // In this instance, the borrow is carried through the loop. + + let mut v = ~3, w = ~4; + let mut _x = &w; + for for_func { + // here we cannot be sure that `for_func` respects the break below + borrow_mut(v); //~ ERROR cannot borrow + _x = &v; + break; + } + borrow_mut(v); //~ ERROR cannot borrow +} + +fn while_aliased_mut_cond(cond: bool, cond2: bool) { + let mut v = ~3, w = ~4; + let mut x = &mut w; + while cond { + **x += 1; + borrow(v); //~ ERROR cannot borrow + if cond2 { + x = &mut v; //~ ERROR cannot borrow + } + } +} + +fn loop_break_pops_scopes<'r>(_v: &'r mut [uint], f: &fn(&'r mut uint) -> bool) { + // Here we check that when you break out of an inner loop, the + // borrows that go out of scope as you exit the inner loop are + // removed from the bitset. + + while cond() { + while cond() { + // this borrow is limited to the scope of `r`... + let r: &'r mut uint = produce(); + if !f(&mut *r) { + break; // ...so it is not live as exit the `while` loop here + } + } + } +} + +fn loop_loop_pops_scopes<'r>(_v: &'r mut [uint], f: &fn(&'r mut uint) -> bool) { + // Similar to `loop_break_pops_scopes` but for the `loop` keyword + + while cond() { + while cond() { + // this borrow is limited to the scope of `r`... + let r: &'r mut uint = produce(); + if !f(&mut *r) { + loop; // ...so it is not live as exit (and re-enter) the `while` loop here + } + } + } +} + +fn main() {} diff --git a/src/test/compile-fail/borrowck-lend-flow-match.rs b/src/test/compile-fail/borrowck-lend-flow-match.rs new file mode 100644 index 0000000000000..7603fdc82a824 --- /dev/null +++ b/src/test/compile-fail/borrowck-lend-flow-match.rs @@ -0,0 +1,60 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-pretty -- comments are infaithfully preserved + +#[allow(unused_variable)]; +#[allow(dead_assignment)]; + +fn cond() -> bool { fail!() } +fn link<'a>(v: &'a uint, w: &mut &'a uint) -> bool { *w = v; true } + +fn separate_arms() { + // Here both arms perform assignments, but only is illegal. + + let mut x = None; + match x { + None => { + // It is ok to reassign x here, because there is in + // fact no outstanding loan of x! + x = Some(0); + } + Some(ref _i) => { + x = Some(1); //~ ERROR cannot assign + } + } + copy x; // just to prevent liveness warnings +} + +fn guard() { + // Here the guard performs a borrow. This borrow "infects" all + // subsequent arms (but not the prior ones). + + let mut a = ~3; + let mut b = ~4; + let mut w = &*a; + match 22 { + _ if cond() => { + b = ~5; + } + + _ if link(&*b, &mut w) => { + b = ~6; //~ ERROR cannot assign + } + + _ => { + b = ~7; //~ ERROR cannot assign + } + } + + b = ~8; //~ ERROR cannot assign +} + +fn main() {} diff --git a/src/test/compile-fail/borrowck-lend-flow.rs b/src/test/compile-fail/borrowck-lend-flow.rs index ed6446a6311b8..59cac0c5d953a 100644 --- a/src/test/compile-fail/borrowck-lend-flow.rs +++ b/src/test/compile-fail/borrowck-lend-flow.rs @@ -15,96 +15,37 @@ // cases are noted. fn borrow(_v: &int) {} +fn borrow_mut(_v: &mut int) {} +fn cond() -> bool { fail!() } +fn for_func(_f: &fn() -> bool) { fail!() } +fn produce() -> T { fail!(); } fn inc(v: &mut ~int) { *v = ~(**v + 1); } -fn post_aliased_const() { - let mut v = ~3; - borrow(v); - let _w = &const v; -} - -fn post_aliased_mut() { - // SPURIOUS--flow - let mut v = ~3; - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - let _w = &mut v; //~ NOTE prior loan as mutable granted here -} +fn pre_freeze() { + // In this instance, the freeze starts before the mut borrow. -fn post_aliased_scope(cond: bool) { let mut v = ~3; - borrow(v); - if cond { inc(&mut v); } + let _w = &v; + borrow_mut(v); //~ ERROR cannot borrow } -fn loop_overarching_alias_mut() { - let mut v = ~3; - let mut _x = &mut v; //~ NOTE prior loan as mutable granted here - loop { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - } -} +fn pre_const() { + // In this instance, the freeze starts before the mut borrow. -fn block_overarching_alias_mut() { let mut v = ~3; - let mut _x = &mut v; //~ NOTE prior loan as mutable granted here - for 3.times { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - } -} - -fn loop_aliased_mut() { - let mut v = ~3, w = ~4; - let mut _x = &mut w; - loop { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - _x = &mut v; //~ NOTE prior loan as mutable granted here - } -} - -fn while_aliased_mut(cond: bool) { - let mut v = ~3, w = ~4; - let mut _x = &mut w; - while cond { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - _x = &mut v; //~ NOTE prior loan as mutable granted here - } -} - -fn while_aliased_mut_cond(cond: bool, cond2: bool) { - let mut v = ~3, w = ~4; - let mut _x = &mut w; - while cond { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - if cond2 { - _x = &mut v; //~ NOTE prior loan as mutable granted here - } - } -} - -fn loop_in_block() { - let mut v = ~3, w = ~4; - let mut _x = &mut w; - for uint::range(0u, 10u) |_i| { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - _x = &mut v; //~ NOTE prior loan as mutable granted here - } + let _w = &const v; + borrow_mut(v); } -fn at_most_once_block() { - fn at_most_once(f: &fn()) { f() } +fn post_freeze() { + // In this instance, the const alias starts after the borrow. - // Here, the borrow check has no way of knowing that the block is - // executed at most once. - - let mut v = ~3, w = ~4; - let mut _x = &mut w; - do at_most_once { - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - _x = &mut v; //~ NOTE prior loan as mutable granted here - } + let mut v = ~3; + borrow_mut(v); + let _w = &v; } fn main() {} diff --git a/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs b/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs index 784fce1300f76..50dd815d49302 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-move-cc.rs @@ -14,17 +14,17 @@ fn borrow(v: &int, f: &fn(x: &int)) { fn box_imm() { let v = ~3; - let _w = &v; //~ NOTE loan of immutable local variable granted here + let _w = &v; do task::spawn { debug!("v=%d", *v); - //~^ ERROR by-move capture of immutable local variable prohibited due to outstanding loan + //~^ ERROR cannot move `v` into closure } let v = ~3; - let _w = &v; //~ NOTE loan of immutable local variable granted here + let _w = &v; task::spawn(|| { debug!("v=%d", *v); - //~^ ERROR by-move capture of immutable local variable prohibited due to outstanding loan + //~^ ERROR cannot move }); } diff --git a/src/test/compile-fail/borrowck-loan-blocks-move.rs b/src/test/compile-fail/borrowck-loan-blocks-move.rs index 3af77d2df7f01..b9a79f4f3b1b1 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-move.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-move.rs @@ -13,8 +13,8 @@ fn take(_v: ~int) { fn box_imm() { let v = ~3; - let _w = &v; //~ NOTE loan of immutable local variable granted here - take(v); //~ ERROR moving out of immutable local variable prohibited due to outstanding loan + let _w = &v; + take(v); //~ ERROR cannot move out of `v` because it is borrowed } fn main() { diff --git a/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs b/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs index 14cb37d775c43..f8415a38573c4 100644 --- a/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs +++ b/src/test/compile-fail/borrowck-loan-blocks-mut-uniq.rs @@ -14,8 +14,8 @@ fn borrow(v: &int, f: &fn(x: &int)) { fn box_imm() { let mut v = ~3; - do borrow(v) |w| { //~ NOTE loan of mutable local variable granted here - v = ~4; //~ ERROR assigning to captured outer mutable variable in a stack closure prohibited due to outstanding loan + do borrow(v) |w| { + v = ~4; //~ ERROR cannot assign to `v` because it is borrowed assert!(*v == 3); assert!(*w == 4); } diff --git a/src/test/compile-fail/borrowck-loan-local-as-both-mut-and-imm.rs b/src/test/compile-fail/borrowck-loan-local-as-both-mut-and-imm.rs index a2ba5ad489167..f369bf208c2ce 100644 --- a/src/test/compile-fail/borrowck-loan-local-as-both-mut-and-imm.rs +++ b/src/test/compile-fail/borrowck-loan-local-as-both-mut-and-imm.rs @@ -22,13 +22,13 @@ use core::either::{Either, Left, Right}; fn g() { let mut x: Either = Left(3); - io::println(f(&mut x, &x).to_str()); //~ ERROR conflicts with prior loan + io::println(f(&mut x, &x).to_str()); //~ ERROR cannot borrow } fn h() { let mut x: Either = Left(3); let y: &Either = &x; - let z: &mut Either = &mut x; //~ ERROR conflicts with prior loan + let z: &mut Either = &mut x; //~ ERROR cannot borrow *z = *y; } diff --git a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs index a4ad7e69b3336..8c9d3009e5e67 100644 --- a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs +++ b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Point { +struct Point { x: int, y: int, } @@ -38,10 +38,10 @@ fn b() { // Here I create an outstanding loan and check that we get conflicts: - let q = &mut p; //~ NOTE prior loan as mutable granted here + let q = &mut p; p + 3; // ok for pure fns - p.times(3); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan + p.times(3); //~ ERROR cannot borrow `p` q.x += 1; } diff --git a/src/test/compile-fail/borrowck-loan-rcvr.rs b/src/test/compile-fail/borrowck-loan-rcvr.rs index 4473574926a34..decf6228fc658 100644 --- a/src/test/compile-fail/borrowck-loan-rcvr.rs +++ b/src/test/compile-fail/borrowck-loan-rcvr.rs @@ -13,7 +13,6 @@ struct point { x: int, y: int } trait methods { fn impurem(&self); fn blockm(&self, f: &fn()); - fn purem(&self); } impl methods for point { @@ -21,9 +20,6 @@ impl methods for point { } fn blockm(&self, f: &fn()) { f() } - - fn purem(&self) { - } } fn a() { @@ -31,12 +27,11 @@ fn a() { // Here: it's ok to call even though receiver is mutable, because we // can loan it out. - p.purem(); p.impurem(); // But in this case we do not honor the loan: - do p.blockm { //~ NOTE loan of mutable local variable granted here - p.x = 10; //~ ERROR assigning to mutable field prohibited due to outstanding loan + do p.blockm { + p.x = 10; //~ ERROR cannot assign } } @@ -45,20 +40,21 @@ fn b() { // Here I create an outstanding loan and check that we get conflicts: - let l = &mut p; //~ NOTE prior loan as mutable granted here - //~^ NOTE prior loan as mutable granted here - - p.purem(); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan - p.impurem(); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan + let l = &mut p; + p.impurem(); //~ ERROR cannot borrow l.x += 1; } fn c() { - // Loaning @mut as & is considered legal due to dynamic checks: + // Loaning @mut as & is considered legal due to dynamic checks... let q = @mut point {x: 3, y: 4}; - q.purem(); q.impurem(); + + // ...but we still detect errors statically when we can. + do q.blockm { + q.x = 10; //~ ERROR cannot assign + } } fn main() { diff --git a/src/test/compile-fail/borrowck-loan-vec-content.rs b/src/test/compile-fail/borrowck-loan-vec-content.rs index d27d690437aff..6a8e64377aab2 100644 --- a/src/test/compile-fail/borrowck-loan-vec-content.rs +++ b/src/test/compile-fail/borrowck-loan-vec-content.rs @@ -24,8 +24,8 @@ fn has_mut_vec_and_does_not_try_to_change_it() { fn has_mut_vec_but_tries_to_change_it() { let mut v = ~[1, 2, 3]; - do takes_imm_elt(&v[0]) { //~ NOTE loan of mutable vec content granted here - v[1] = 4; //~ ERROR assigning to mutable vec content prohibited due to outstanding loan + do takes_imm_elt(&v[0]) { + v[1] = 4; //~ ERROR cannot assign } } diff --git a/src/test/compile-fail/borrowck-move-by-capture.rs b/src/test/compile-fail/borrowck-move-by-capture.rs index 18b4ce0640c41..c199c8795756d 100644 --- a/src/test/compile-fail/borrowck-move-by-capture.rs +++ b/src/test/compile-fail/borrowck-move-by-capture.rs @@ -4,7 +4,7 @@ fn main() { let foo = ~3; let _pfoo = &foo; let _f: @fn() -> int = || *foo + 5; - //~^ ERROR by-move capture + //~^ ERROR cannot move `foo` let bar = ~3; let _g = || { diff --git a/src/test/compile-fail/borrowck-mut-addr-of-imm-var.rs b/src/test/compile-fail/borrowck-mut-addr-of-imm-var.rs index d0b0f51d0cf77..e4e449822768b 100644 --- a/src/test/compile-fail/borrowck-mut-addr-of-imm-var.rs +++ b/src/test/compile-fail/borrowck-mut-addr-of-imm-var.rs @@ -10,7 +10,7 @@ fn main() { let x: int = 3; - let y: &mut int = &mut x; //~ ERROR illegal borrow + let y: &mut int = &mut x; //~ ERROR cannot borrow *y = 5; debug!(*y); } diff --git a/src/test/compile-fail/borrowck-mut-boxed-vec.rs b/src/test/compile-fail/borrowck-mut-boxed-vec.rs index d4c0b5a1e9bf9..a69edebce51fb 100644 --- a/src/test/compile-fail/borrowck-mut-boxed-vec.rs +++ b/src/test/compile-fail/borrowck-mut-boxed-vec.rs @@ -10,8 +10,8 @@ fn main() { let v = @mut [ 1, 2, 3 ]; - for v.each |_x| { //~ ERROR illegal borrow - v[1] = 4; + for v.each |_x| { + v[1] = 4; //~ ERROR cannot assign } } diff --git a/src/test/compile-fail/borrowck-mut-deref-comp.rs b/src/test/compile-fail/borrowck-mut-deref-comp.rs index 540793d4135f2..d1dc296197892 100644 --- a/src/test/compile-fail/borrowck-mut-deref-comp.rs +++ b/src/test/compile-fail/borrowck-mut-deref-comp.rs @@ -11,8 +11,8 @@ struct foo(~int); fn borrow(x: @mut foo) { - let _y = &***x; //~ ERROR illegal borrow unless pure - *x = foo(~4); //~ NOTE impure due to assigning to dereference of mutable @ pointer + let _y = &***x; + *x = foo(~4); //~ ERROR cannot assign } fn main() { diff --git a/src/test/compile-fail/borrowck-mut-slice-of-imm-vec.rs b/src/test/compile-fail/borrowck-mut-slice-of-imm-vec.rs index bc0340983ae34..ec17976c5065c 100644 --- a/src/test/compile-fail/borrowck-mut-slice-of-imm-vec.rs +++ b/src/test/compile-fail/borrowck-mut-slice-of-imm-vec.rs @@ -14,5 +14,5 @@ fn write(v: &mut [int]) { fn main() { let v = ~[1, 2, 3]; - write(v); //~ ERROR illegal borrow + write(v); //~ ERROR cannot borrow } diff --git a/src/test/compile-fail/borrowck-no-cycle-in-exchange-heap.rs b/src/test/compile-fail/borrowck-no-cycle-in-exchange-heap.rs index 4af3bc17240ce..ed270de51e2ed 100644 --- a/src/test/compile-fail/borrowck-no-cycle-in-exchange-heap.rs +++ b/src/test/compile-fail/borrowck-no-cycle-in-exchange-heap.rs @@ -19,9 +19,9 @@ enum cycle { fn main() { let mut x = ~node(node_ {a: ~empty}); // Create a cycle! - match *x { //~ NOTE loan of mutable local variable granted here + match *x { node(ref mut y) => { - y.a = x; //~ ERROR moving out of mutable local variable prohibited due to outstanding loan + y.a = x; //~ ERROR cannot move out of } empty => {} }; diff --git a/src/test/compile-fail/borrowck-pat-by-value-binding.rs b/src/test/compile-fail/borrowck-pat-by-value-binding.rs index d8c8841d391a2..d60ed3d0e372b 100644 --- a/src/test/compile-fail/borrowck-pat-by-value-binding.rs +++ b/src/test/compile-fail/borrowck-pat-by-value-binding.rs @@ -12,23 +12,24 @@ fn process(_t: T) {} fn match_const_opt_by_mut_ref(v: &const Option) { match *v { - Some(ref mut i) => process(i), //~ ERROR illegal borrow + Some(ref mut i) => process(i), //~ ERROR cannot borrow + //~^ ERROR unsafe borrow of aliasable, const value None => () } } fn match_const_opt_by_const_ref(v: &const Option) { match *v { - Some(ref const i) => process(i), //~ ERROR illegal borrow unless pure - //~^ NOTE impure due to + Some(ref const i) => process(i), + //~^ ERROR unsafe borrow of aliasable, const value None => () } } fn match_const_opt_by_imm_ref(v: &const Option) { match *v { - Some(ref i) => process(i), //~ ERROR illegal borrow unless pure - //~^ NOTE impure due to + Some(ref i) => process(i), //~ ERROR cannot borrow + //~^ ERROR unsafe borrow of aliasable, const value None => () } } diff --git a/src/test/compile-fail/borrowck-pat-enum.rs b/src/test/compile-fail/borrowck-pat-enum.rs index 4aa1ecc0ce3fe..c50357e8b9c62 100644 --- a/src/test/compile-fail/borrowck-pat-enum.rs +++ b/src/test/compile-fail/borrowck-pat-enum.rs @@ -26,7 +26,8 @@ fn match_ref_unused(&&v: Option) { fn match_const_reg(v: &const Option) -> int { match *v { - Some(ref i) => {*i} // OK because this is pure + Some(ref i) => {*i} //~ ERROR cannot borrow + //~^ ERROR unsafe borrow None => {0} } } @@ -43,8 +44,8 @@ fn match_const_reg_unused(v: &const Option) { fn match_const_reg_impure(v: &const Option) { match *v { - Some(ref i) => {impure(*i)} //~ ERROR illegal borrow unless pure - //~^ NOTE impure due to access to impure function + Some(ref i) => {impure(*i)} //~ ERROR cannot borrow + //~^ ERROR unsafe borrow None => {} } } @@ -56,5 +57,12 @@ fn match_imm_reg(v: &Option) { } } +fn match_mut_reg(v: &mut Option) { + match *v { + Some(ref i) => {impure(*i)} // OK, frozen + None => {} + } +} + fn main() { } diff --git a/src/test/compile-fail/borrowck-pat-reassign-binding.rs b/src/test/compile-fail/borrowck-pat-reassign-binding.rs index ca1fdc97c22f8..d05160132c6c2 100644 --- a/src/test/compile-fail/borrowck-pat-reassign-binding.rs +++ b/src/test/compile-fail/borrowck-pat-reassign-binding.rs @@ -12,11 +12,14 @@ fn main() { let mut x: Option = None; - match x { //~ NOTE loan of mutable local variable granted here - None => {} + match x { + None => { + // Note: on this branch, no borrow has occurred. + x = Some(0); + } Some(ref i) => { - // Not ok: i is an outstanding ptr into x. - x = Some(*i+1); //~ ERROR assigning to mutable local variable prohibited due to outstanding loan + // But on this branch, `i` is an outstanding borrow + x = Some(*i+1); //~ ERROR cannot assign to `x` } } copy x; // just to prevent liveness warnings diff --git a/src/test/compile-fail/borrowck-pat-reassign-sometimes-binding.rs b/src/test/compile-fail/borrowck-pat-reassign-sometimes-binding.rs deleted file mode 100644 index dd6eca951b8f3..0000000000000 --- a/src/test/compile-fail/borrowck-pat-reassign-sometimes-binding.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-pretty -- comments are infaithfully preserved - -fn main() { - let mut x = None; - match x { //~ NOTE loan of mutable local variable granted here - None => { - // It is ok to reassign x here, because there is in - // fact no outstanding loan of x! - x = Some(0); - } - Some(ref _i) => { - x = Some(1); //~ ERROR assigning to mutable local variable prohibited due to outstanding loan - } - } - copy x; // just to prevent liveness warnings -} diff --git a/src/test/compile-fail/borrowck-reborrow-from-mut.rs b/src/test/compile-fail/borrowck-reborrow-from-mut.rs index 60f817dee0c54..b4bd64f213586 100644 --- a/src/test/compile-fail/borrowck-reborrow-from-mut.rs +++ b/src/test/compile-fail/borrowck-reborrow-from-mut.rs @@ -20,17 +20,17 @@ struct Bar { fn borrow_same_field_twice_mut_mut(foo: &mut Foo) { let _bar1 = &mut foo.bar1; - let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow } fn borrow_same_field_twice_mut_imm(foo: &mut Foo) { let _bar1 = &mut foo.bar1; - let _bar2 = &foo.bar1; //~ ERROR conflicts with prior loan + let _bar2 = &foo.bar1; //~ ERROR cannot borrow } fn borrow_same_field_twice_imm_mut(foo: &mut Foo) { let _bar1 = &foo.bar1; - let _bar2 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let _bar2 = &mut foo.bar1; //~ ERROR cannot borrow } fn borrow_same_field_twice_imm_imm(foo: &mut Foo) { @@ -53,34 +53,34 @@ fn borrow_var_and_pattern(foo: &mut Foo) { let _bar1 = &mut foo.bar1; match *foo { Foo { bar1: ref mut _bar1, bar2: _ } => {} - //~^ ERROR conflicts with prior loan + //~^ ERROR cannot borrow } } fn borrow_mut_and_base_imm(foo: &mut Foo) { let _bar1 = &mut foo.bar1.int1; - let _foo1 = &foo.bar1; //~ ERROR conflicts with prior loan - let _foo2 = &*foo; //~ ERROR conflicts with prior loan + let _foo1 = &foo.bar1; //~ ERROR cannot borrow + let _foo2 = &*foo; //~ ERROR cannot borrow } fn borrow_mut_and_base_mut(foo: &mut Foo) { let _bar1 = &mut foo.bar1.int1; - let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow } fn borrow_mut_and_base_mut2(foo: &mut Foo) { let _bar1 = &mut foo.bar1.int1; - let _foo2 = &mut *foo; //~ ERROR conflicts with prior loan + let _foo2 = &mut *foo; //~ ERROR cannot borrow } fn borrow_imm_and_base_mut(foo: &mut Foo) { let _bar1 = &foo.bar1.int1; - let _foo1 = &mut foo.bar1; //~ ERROR conflicts with prior loan + let _foo1 = &mut foo.bar1; //~ ERROR cannot borrow } fn borrow_imm_and_base_mut2(foo: &mut Foo) { let _bar1 = &foo.bar1.int1; - let _foo2 = &mut *foo; //~ ERROR conflicts with prior loan + let _foo2 = &mut *foo; //~ ERROR cannot borrow } fn borrow_imm_and_base_imm(foo: &mut Foo) { @@ -95,7 +95,7 @@ fn borrow_mut_and_imm(foo: &mut Foo) { } fn borrow_mut_from_imm(foo: &Foo) { - let _bar1 = &mut foo.bar1; //~ ERROR illegal borrow + let _bar1 = &mut foo.bar1; //~ ERROR cannot borrow } fn borrow_long_path_both_mut(foo: &mut Foo) { diff --git a/src/test/compile-fail/borrowck-ref-into-rvalue.rs b/src/test/compile-fail/borrowck-ref-into-rvalue.rs index 37ee747069ccf..18865ad7d54d8 100644 --- a/src/test/compile-fail/borrowck-ref-into-rvalue.rs +++ b/src/test/compile-fail/borrowck-ref-into-rvalue.rs @@ -10,12 +10,12 @@ fn main() { let msg; - match Some(~"Hello") { //~ ERROR illegal borrow - Some(ref m) => { + match Some(~"Hello") { + Some(ref m) => { //~ ERROR borrowed value does not live long enough msg = m; - }, + }, None => { fail!() } - } + } io::println(*msg); } diff --git a/src/test/compile-fail/borrowck-ref-mut-of-imm.rs b/src/test/compile-fail/borrowck-ref-mut-of-imm.rs index aad86241e9a43..3a37116a1664d 100644 --- a/src/test/compile-fail/borrowck-ref-mut-of-imm.rs +++ b/src/test/compile-fail/borrowck-ref-mut-of-imm.rs @@ -11,7 +11,7 @@ fn destructure(x: Option) -> int { match x { None => 0, - Some(ref mut v) => *v //~ ERROR illegal borrow + Some(ref mut v) => *v //~ ERROR cannot borrow } } diff --git a/src/test/compile-fail/borrowck-unary-move-2.rs b/src/test/compile-fail/borrowck-unary-move-2.rs index 520772f1ceea9..898830bbe55ba 100644 --- a/src/test/compile-fail/borrowck-unary-move-2.rs +++ b/src/test/compile-fail/borrowck-unary-move-2.rs @@ -28,5 +28,5 @@ struct wrapper(noncopyable); fn main() { let x1 = wrapper(noncopyable()); - let _x2 = *x1; //~ ERROR moving out of anonymous field + let _x2 = *x1; //~ ERROR cannot move out } diff --git a/src/test/compile-fail/borrowck-unary-move.rs b/src/test/compile-fail/borrowck-unary-move.rs index f95b365ee2ef9..107e478004abb 100644 --- a/src/test/compile-fail/borrowck-unary-move.rs +++ b/src/test/compile-fail/borrowck-unary-move.rs @@ -9,8 +9,8 @@ // except according to those terms. fn foo(+x: ~int) -> int { - let y = &*x; //~ NOTE loan of argument granted here - free(x); //~ ERROR moving out of argument prohibited due to outstanding loan + let y = &*x; + free(x); //~ ERROR cannot move out of `*x` because it is borrowed *y } diff --git a/src/test/compile-fail/borrowck-uniq-via-box.rs b/src/test/compile-fail/borrowck-uniq-via-box.rs deleted file mode 100644 index e1c0e67ff8dcc..0000000000000 --- a/src/test/compile-fail/borrowck-uniq-via-box.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -struct Rec { - f: ~int, -} - -struct Outer { - f: Inner -} - -struct Inner { - g: Innermost -} - -struct Innermost { - h: ~int, -} - -fn borrow(_v: &int) {} - -fn box_mut(v: @mut ~int) { - borrow(*v); //~ ERROR illegal borrow unless pure -} - -fn box_mut_rec(v: @mut Rec) { - borrow(v.f); //~ ERROR illegal borrow unless pure -} - -fn box_mut_recs(v: @mut Outer) { - borrow(v.f.g.h); //~ ERROR illegal borrow unless pure -} - -fn box_imm(v: @~int) { - borrow(*v); // OK -} - -fn box_imm_rec(v: @Rec) { - borrow(v.f); // OK -} - -fn box_imm_recs(v: @Outer) { - borrow(v.f.g.h); // OK -} - -fn main() { -} - diff --git a/src/test/compile-fail/borrowck-uniq-via-lend.rs b/src/test/compile-fail/borrowck-uniq-via-lend.rs index ee96237a26c82..80ba1968bc751 100644 --- a/src/test/compile-fail/borrowck-uniq-via-lend.rs +++ b/src/test/compile-fail/borrowck-uniq-via-lend.rs @@ -43,8 +43,8 @@ fn aliased_const() { fn aliased_mut() { let mut v = ~3; - let _w = &mut v; //~ NOTE prior loan as mutable granted here - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan + let _w = &mut v; + borrow(v); //~ ERROR cannot borrow `*v` } fn aliased_other() { @@ -56,8 +56,8 @@ fn aliased_other() { fn aliased_other_reassign() { let mut v = ~3, w = ~4; let mut _x = &mut w; - _x = &mut v; //~ NOTE prior loan as mutable granted here - borrow(v); //~ ERROR loan of mutable local variable as immutable conflicts with prior loan + _x = &mut v; + borrow(v); //~ ERROR cannot borrow `*v` } fn main() { diff --git a/src/test/compile-fail/borrowck-uniq-via-ref.rs b/src/test/compile-fail/borrowck-uniq-via-ref.rs index 2cf363e13ee09..8bf627d991911 100644 --- a/src/test/compile-fail/borrowck-uniq-via-ref.rs +++ b/src/test/compile-fail/borrowck-uniq-via-ref.rs @@ -25,6 +25,7 @@ struct Innermost { } fn borrow(_v: &int) {} +fn borrow_const(_v: &const int) {} fn box_mut(v: &mut ~int) { borrow(*v); // OK: &mut -> &imm @@ -51,15 +52,15 @@ fn box_imm_recs(v: &Outer) { } fn box_const(v: &const ~int) { - borrow(*v); //~ ERROR illegal borrow unless pure + borrow_const(*v); //~ ERROR unsafe borrow } fn box_const_rec(v: &const Rec) { - borrow(v.f); //~ ERROR illegal borrow unless pure + borrow_const(v.f); //~ ERROR unsafe borrow } fn box_const_recs(v: &const Outer) { - borrow(v.f.g.h); //~ ERROR illegal borrow unless pure + borrow_const(v.f.g.h); //~ ERROR unsafe borrow } fn main() { diff --git a/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs index c8a0dbedd5d95..0c21b64bb0fb0 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-element-loan.rs @@ -1,7 +1,7 @@ fn a() -> &[int] { let vec = [1, 2, 3, 4]; - let tail = match vec { //~ ERROR illegal borrow - [_, ..tail] => tail, + let tail = match vec { + [_, ..tail] => tail, //~ ERROR does not live long enough _ => fail!(~"a") }; tail @@ -9,8 +9,8 @@ fn a() -> &[int] { fn b() -> &[int] { let vec = [1, 2, 3, 4]; - let init = match vec { //~ ERROR illegal borrow - [..init, _] => init, + let init = match vec { + [..init, _] => init, //~ ERROR does not live long enough _ => fail!(~"b") }; init @@ -18,8 +18,8 @@ fn b() -> &[int] { fn c() -> &[int] { let vec = [1, 2, 3, 4]; - let slice = match vec { //~ ERROR illegal borrow - [_, ..slice, _] => slice, + let slice = match vec { + [_, ..slice, _] => slice, //~ ERROR does not live long enough _ => fail!(~"c") }; slice diff --git a/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs index 27902100373a9..6b51fc8f5b3d7 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs @@ -2,7 +2,7 @@ fn a() { let mut v = ~[1, 2, 3]; match v { [_a, ..tail] => { - v.push(tail[0] + tail[1]); //~ ERROR conflicts with prior loan + v.push(tail[0] + tail[1]); //~ ERROR cannot borrow } _ => {} }; diff --git a/src/test/compile-fail/borrowck-vec-pattern-move-tail.rs b/src/test/compile-fail/borrowck-vec-pattern-move-tail.rs index 16b48aedb0c7f..2898e312930fe 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-move-tail.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-move-tail.rs @@ -1,8 +1,9 @@ fn main() { let mut a = [1, 2, 3, 4]; - let _ = match a { + let t = match a { [1, 2, ..tail] => tail, _ => core::util::unreachable() }; - a[0] = 0; //~ ERROR: assigning to mutable vec content prohibited due to outstanding loan + a[0] = 0; //~ ERROR cannot assign to `a[]` because it is borrowed + t[0]; } diff --git a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs index 05ff85d612c82..16711ea61ffac 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs @@ -2,7 +2,7 @@ fn a() { let mut vec = [~1, ~2, ~3]; match vec { [~ref _a] => { - vec[0] = ~4; //~ ERROR prohibited due to outstanding loan + vec[0] = ~4; //~ ERROR cannot assign to `vec[]` because it is borrowed } _ => fail!(~"foo") } @@ -12,7 +12,7 @@ fn b() { let mut vec = [~1, ~2, ~3]; match vec { [.._b] => { - vec[0] = ~4; //~ ERROR prohibited due to outstanding loan + vec[0] = ~4; //~ ERROR cannot assign to `vec[]` because it is borrowed } } } diff --git a/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs index 714a80def9358..dbdd8f0809a6e 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-tail-element-loan.rs @@ -1,7 +1,7 @@ fn a() -> &int { let vec = [1, 2, 3, 4]; - let tail = match vec { //~ ERROR illegal borrow - [_a, ..tail] => &tail[0], + let tail = match vec { + [_a, ..tail] => &tail[0], //~ ERROR borrowed value does not live long enough _ => fail!(~"foo") }; tail diff --git a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs index e47ad721b0d7b..5ef23897ec0d3 100644 --- a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs +++ b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs @@ -1,6 +1,6 @@ fn main() { let mut b = ~3; - let _x = &mut *b; //~ NOTE prior loan as mutable granted here - let _y = &mut *b; //~ ERROR loan of dereference of mutable ~ pointer as mutable conflicts with prior loan + let _x = &mut *b; + let _y = &mut *b; //~ ERROR cannot borrow } diff --git a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs index 015f368ecb068..a744127a600db 100644 --- a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs +++ b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs @@ -1,8 +1,8 @@ fn main() { let mut a = ~3; - let mut b = &mut a; //~ NOTE loan of mutable local variable granted here + let mut b = &mut a; let _c = &mut *b; - let mut d = /*move*/ a; //~ ERROR moving out of mutable local variable prohibited due to outstanding loan + let mut d = /*move*/ a; //~ ERROR cannot move out *d += 1; } diff --git a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs index 36d32fddda150..44da00d8d1707 100644 --- a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs +++ b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs @@ -1,7 +1,7 @@ fn main() { let mut b = ~3; - let _x = &mut *b; //~ NOTE loan of mutable local variable granted here - let mut y = /*move*/ b; //~ ERROR moving out of mutable local variable prohibited + let _x = &mut *b; + let mut y = /*move*/ b; //~ ERROR cannot move out *y += 1; } diff --git a/src/test/compile-fail/borrowck-wg-move-base-2.rs b/src/test/compile-fail/borrowck-wg-move-base-2.rs index ba85616e63f28..8a2187714534a 100644 --- a/src/test/compile-fail/borrowck-wg-move-base-2.rs +++ b/src/test/compile-fail/borrowck-wg-move-base-2.rs @@ -2,7 +2,7 @@ fn foo(x: &mut int) { let mut a = 3; let mut _y = &mut *x; let _z = &mut *_y; - _y = &mut a; //~ ERROR assigning to mutable local variable prohibited + _y = &mut a; //~ ERROR cannot assign } fn main() { diff --git a/src/test/compile-fail/fn-variance-3.rs b/src/test/compile-fail/fn-variance-3.rs index 5df2007721def..4d145d3f9ea3a 100644 --- a/src/test/compile-fail/fn-variance-3.rs +++ b/src/test/compile-fail/fn-variance-3.rs @@ -31,5 +31,5 @@ fn main() { // mutability check will fail, because the // type of r has been inferred to be // fn(@const int) -> @const int - *r(@mut 3) = 4; //~ ERROR assigning to dereference of const @ pointer + *r(@mut 3) = 4; //~ ERROR cannot assign to const dereference of @ pointer } diff --git a/src/test/compile-fail/immut-function-arguments.rs b/src/test/compile-fail/immut-function-arguments.rs index 2084729372d1d..66b5bd172cace 100644 --- a/src/test/compile-fail/immut-function-arguments.rs +++ b/src/test/compile-fail/immut-function-arguments.rs @@ -9,11 +9,11 @@ // except according to those terms. fn f(y: ~int) { - *y = 5; //~ ERROR assigning to dereference of immutable ~ pointer + *y = 5; //~ ERROR cannot assign } fn g() { - let _frob: &fn(~int) = |q| { *q = 2; }; //~ ERROR assigning to dereference of immutable ~ pointer + let _frob: &fn(~int) = |q| { *q = 2; }; //~ ERROR cannot assign } diff --git a/src/test/compile-fail/index_message.rs b/src/test/compile-fail/index_message.rs index 3611dbb6866cb..26dd98757a8c2 100644 --- a/src/test/compile-fail/index_message.rs +++ b/src/test/compile-fail/index_message.rs @@ -10,5 +10,5 @@ fn main() { let z = (); - debug!(z[0]); //~ ERROR cannot index a value of type `()` + let _ = z[0]; //~ ERROR cannot index a value of type `()` } diff --git a/src/test/compile-fail/issue-1896-1.rs b/src/test/compile-fail/issue-1896-1.rs index fc5132d65104f..13adcd42da2b8 100644 --- a/src/test/compile-fail/issue-1896-1.rs +++ b/src/test/compile-fail/issue-1896-1.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Test that we require managed closures to be rooted when borrowed. + struct boxedFn<'self> { theFn: &'self fn() -> uint } fn createClosure (closedUint: uint) -> boxedFn { let theFn: @fn() -> uint = || closedUint; - boxedFn {theFn: theFn} //~ ERROR illegal borrow + boxedFn {theFn: theFn} //~ ERROR cannot root } fn main () { diff --git a/src/test/compile-fail/issue-2149.rs b/src/test/compile-fail/issue-2149.rs index 2842d884c9918..cdc8d546dd848 100644 --- a/src/test/compile-fail/issue-2149.rs +++ b/src/test/compile-fail/issue-2149.rs @@ -23,5 +23,4 @@ impl vec_monad for ~[A] { fn main() { ["hi"].bind(|x| [x] ); //~^ ERROR type `[&'static str, .. 1]` does not implement any method in scope named `bind` - //~^^ ERROR Unconstrained region variable } diff --git a/src/test/compile-fail/issue-2151.rs b/src/test/compile-fail/issue-2151.rs index e2bbda7d65a99..bb6d47a47622b 100644 --- a/src/test/compile-fail/issue-2151.rs +++ b/src/test/compile-fail/issue-2151.rs @@ -10,7 +10,6 @@ fn main() { for vec::each(fail!()) |i| { - debug!(i * 2); - //~^ ERROR the type of this value must be known + let _ = i * 2; //~ ERROR the type of this value must be known }; } diff --git a/src/test/compile-fail/issue-2590.rs b/src/test/compile-fail/issue-2590.rs index 7a99ab8a94f16..a0b967d59593a 100644 --- a/src/test/compile-fail/issue-2590.rs +++ b/src/test/compile-fail/issue-2590.rs @@ -18,7 +18,7 @@ trait parse { impl parse for parser { fn parse(&self) -> ~[int] { - self.tokens //~ ERROR moving out of immutable field + self.tokens //~ ERROR cannot move out of field } } diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs index fcd5b1deee552..23b11bbe409e1 100644 --- a/src/test/compile-fail/issue-3044.rs +++ b/src/test/compile-fail/issue-3044.rs @@ -11,7 +11,6 @@ fn main() { let needlesArr: ~[char] = ~['a', 'f']; do vec::foldr(needlesArr) |x, y| { - //~^ ERROR Unconstrained region variable #2 } //~^ ERROR 2 parameters were supplied (including the closure passed by the `do` keyword) // diff --git a/src/test/compile-fail/issue-511.rs b/src/test/compile-fail/issue-511.rs index 90c46e5d602c9..c872f89d88450 100644 --- a/src/test/compile-fail/issue-511.rs +++ b/src/test/compile-fail/issue-511.rs @@ -17,5 +17,5 @@ fn f(o: &mut Option) { fn main() { f::(&mut option::None); - //~^ ERROR illegal borrow: creating mutable alias to static item + //~^ ERROR cannot borrow } diff --git a/src/test/compile-fail/kindck-owned-trait-contains.rs b/src/test/compile-fail/kindck-owned-trait-contains.rs index 54ee8bcc70e37..6bb90bff228d4 100644 --- a/src/test/compile-fail/kindck-owned-trait-contains.rs +++ b/src/test/compile-fail/kindck-owned-trait-contains.rs @@ -29,4 +29,7 @@ fn main() { }; assert!(3 == *(y.get())); //~ ERROR dereference of reference outside its lifetime //~^ ERROR reference is not valid outside of its lifetime + //~^^ ERROR reference is not valid outside of its lifetime + //~^^^ ERROR reference is not valid outside of its lifetime + //~^^^^ ERROR cannot infer an appropriate lifetime } diff --git a/src/test/compile-fail/lambda-mutate-nested.rs b/src/test/compile-fail/lambda-mutate-nested.rs index 8b009b91af96c..bfd1e12f3a6e0 100644 --- a/src/test/compile-fail/lambda-mutate-nested.rs +++ b/src/test/compile-fail/lambda-mutate-nested.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:assigning to captured outer immutable variable in a stack closure // Make sure that nesting a block within a @fn doesn't let us // mutate upvars from a @fn. fn f2(x: &fn()) { x(); } @@ -16,6 +15,7 @@ fn f2(x: &fn()) { x(); } fn main() { let i = 0; let ctr: @fn() -> int = || { f2(|| i = i + 1 ); i }; + //~^ ERROR cannot assign error!(ctr()); error!(ctr()); error!(ctr()); diff --git a/src/test/compile-fail/lambda-mutate.rs b/src/test/compile-fail/lambda-mutate.rs index ee5b3d8968418..a848d8698a3d6 100644 --- a/src/test/compile-fail/lambda-mutate.rs +++ b/src/test/compile-fail/lambda-mutate.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:assigning to captured outer variable in a heap closure // Make sure we can't write to upvars from @fns fn main() { let i = 0; let ctr: @fn() -> int = || { i = i + 1; i }; + //~^ ERROR cannot assign error!(ctr()); error!(ctr()); error!(ctr()); diff --git a/src/test/compile-fail/moves-based-on-type-block-bad.rs b/src/test/compile-fail/moves-based-on-type-block-bad.rs index 020dadfc96cd2..feeaadeea8263 100644 --- a/src/test/compile-fail/moves-based-on-type-block-bad.rs +++ b/src/test/compile-fail/moves-based-on-type-block-bad.rs @@ -16,7 +16,7 @@ fn main() { let s = S { x: ~Bar(~42) }; loop { do f(&s) |hellothere| { - match hellothere.x { //~ ERROR moving out of immutable field + match hellothere.x { //~ ERROR cannot move out ~Foo(_) => {} ~Bar(x) => io::println(x.to_str()), ~Baz => {} diff --git a/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs b/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs index 3c15047a29697..ecd58d485a89d 100644 --- a/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs +++ b/src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.rs @@ -13,6 +13,6 @@ fn test(_x: ~uint) {} fn main() { let i = ~3; for uint::range(0, 10) |_x| { - test(i); //~ ERROR moving out of captured outer immutable variable in a stack closure + test(i); //~ ERROR cannot move out } } diff --git a/src/test/compile-fail/mutable-class-fields-2.rs b/src/test/compile-fail/mutable-class-fields-2.rs index 56c715c9847a5..f5d24b316414e 100644 --- a/src/test/compile-fail/mutable-class-fields-2.rs +++ b/src/test/compile-fail/mutable-class-fields-2.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:assigning to immutable field struct cat { priv mut meows : uint, @@ -17,7 +16,7 @@ struct cat { pub impl cat { fn eat(&self) { - self.how_hungry -= 5; + self.how_hungry -= 5; //~ ERROR cannot assign } } diff --git a/src/test/compile-fail/mutable-class-fields.rs b/src/test/compile-fail/mutable-class-fields.rs index 6d11a98c0cb2f..8bebec7134cc3 100644 --- a/src/test/compile-fail/mutable-class-fields.rs +++ b/src/test/compile-fail/mutable-class-fields.rs @@ -8,12 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:assigning to immutable field struct cat { priv mut meows : uint, - how_hungry : int, - } fn cat(in_x : uint, in_y : int) -> cat { @@ -25,5 +22,5 @@ fn cat(in_x : uint, in_y : int) -> cat { fn main() { let nyan : cat = cat(52u, 99); - nyan.how_hungry = 0; + nyan.how_hungry = 0; //~ ERROR cannot assign } diff --git a/src/test/compile-fail/mutable-huh-ptr-assign.rs b/src/test/compile-fail/mutable-huh-ptr-assign.rs index ed356f4001dd6..6b3fd4f715384 100644 --- a/src/test/compile-fail/mutable-huh-ptr-assign.rs +++ b/src/test/compile-fail/mutable-huh-ptr-assign.rs @@ -12,7 +12,7 @@ extern mod std; fn main() { unsafe fn f(&&v: *const int) { - *v = 1 //~ ERROR assigning to dereference of const * pointer + *v = 1 //~ ERROR cannot assign } unsafe { diff --git a/src/test/compile-fail/regions-addr-of-arg.rs b/src/test/compile-fail/regions-addr-of-arg.rs index 7f2140d96e16c..4fff5a6f87c78 100644 --- a/src/test/compile-fail/regions-addr-of-arg.rs +++ b/src/test/compile-fail/regions-addr-of-arg.rs @@ -9,7 +9,7 @@ // except according to those terms. fn foo(a: int) { - let _p: &'static int = &a; //~ ERROR illegal borrow + let _p: &'static int = &a; //~ ERROR borrowed value does not live long enough } fn bar(a: int) { diff --git a/src/test/compile-fail/regions-creating-enums.rs b/src/test/compile-fail/regions-creating-enums.rs index 120428e02f4cb..2ab0c14b49b65 100644 --- a/src/test/compile-fail/regions-creating-enums.rs +++ b/src/test/compile-fail/regions-creating-enums.rs @@ -30,12 +30,12 @@ fn compute(x: &ast) -> uint { fn map_nums(x: &ast, f: &fn(uint) -> uint) -> &ast { match *x { num(x) => { - return &num(f(x)); //~ ERROR illegal borrow + return &num(f(x)); //~ ERROR borrowed value does not live long enough } add(x, y) => { let m_x = map_nums(x, f); let m_y = map_nums(y, f); - return &add(m_x, m_y); //~ ERROR illegal borrow + return &add(m_x, m_y); //~ ERROR borrowed value does not live long enough } } } diff --git a/src/test/compile-fail/regions-creating-enums4.rs b/src/test/compile-fail/regions-creating-enums4.rs index 1cb378cf406f8..8f764745697c7 100644 --- a/src/test/compile-fail/regions-creating-enums4.rs +++ b/src/test/compile-fail/regions-creating-enums4.rs @@ -14,8 +14,7 @@ enum ast<'self> { } fn mk_add_bad2<'a>(x: &'a ast<'a>, y: &'a ast<'a>, z: &ast) -> ast { - add(x, y) - //~^ ERROR cannot infer an appropriate lifetime + add(x, y) //~ ERROR cannot infer an appropriate lifetime } fn main() { diff --git a/src/test/compile-fail/regions-escape-bound-fn.rs b/src/test/compile-fail/regions-escape-bound-fn.rs index c81ef77f497db..5ac5e334be23d 100644 --- a/src/test/compile-fail/regions-escape-bound-fn.rs +++ b/src/test/compile-fail/regions-escape-bound-fn.rs @@ -14,6 +14,6 @@ fn with_int(f: &fn(x: &int)) { } fn main() { - let mut x: Option<&int> = None; //~ ERROR cannot infer + let mut x: Option<&int> = None; //~ ERROR cannot infer with_int(|y| x = Some(y)); } diff --git a/src/test/compile-fail/regions-escape-loop-via-variable.rs b/src/test/compile-fail/regions-escape-loop-via-variable.rs index ac10b5c454a85..19bd0bf9747bb 100644 --- a/src/test/compile-fail/regions-escape-loop-via-variable.rs +++ b/src/test/compile-fail/regions-escape-loop-via-variable.rs @@ -18,6 +18,6 @@ fn main() { loop { let x = 1 + *p; - p = &x; //~ ERROR illegal borrow + p = &x; //~ ERROR borrowed value does not live long enough } } diff --git a/src/test/compile-fail/regions-escape-loop-via-vec.rs b/src/test/compile-fail/regions-escape-loop-via-vec.rs index da5e3c2660ef7..92e2cd73dfbd8 100644 --- a/src/test/compile-fail/regions-escape-loop-via-vec.rs +++ b/src/test/compile-fail/regions-escape-loop-via-vec.rs @@ -14,8 +14,8 @@ fn broken() { let mut _y = ~[&mut x]; while x < 10 { let mut z = x; - _y.push(&mut z); //~ ERROR illegal borrow - x += 1; //~ ERROR assigning to mutable local variable prohibited due to outstanding loan + _y.push(&mut z); //~ ERROR borrowed value does not live long enough + x += 1; //~ ERROR cannot assign } } diff --git a/src/test/compile-fail/regions-escape-via-trait-or-not.rs b/src/test/compile-fail/regions-escape-via-trait-or-not.rs index f7165784c7975..aa431d6b81c6e 100644 --- a/src/test/compile-fail/regions-escape-via-trait-or-not.rs +++ b/src/test/compile-fail/regions-escape-via-trait-or-not.rs @@ -23,13 +23,8 @@ fn with(f: &fn(x: &int) -> R) -> int { } fn return_it() -> int { - with(|o| o) - //~^ ERROR cannot infer an appropriate lifetime due to conflicting requirements - //~^^ ERROR reference is not valid outside of its lifetime - //~^^^ ERROR reference is not valid outside of its lifetime + with(|o| o) //~ ERROR reference is not valid outside of its lifetime } fn main() { - let x = return_it(); - debug!("foo=%d", x); } diff --git a/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs b/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs index a8b7ae1b9c8e4..6e9d6c1ef0fde 100644 --- a/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs +++ b/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs @@ -18,7 +18,7 @@ fn x_coord<'r>(p: &'r point) -> &'r int { } fn foo(p: @point) -> &int { - let xc = x_coord(p); //~ ERROR illegal borrow + let xc = x_coord(p); //~ ERROR cannot root assert!(*xc == 3); return xc; } diff --git a/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs b/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs index bf8f227b5730e..d23e20130f782 100644 --- a/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs +++ b/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs @@ -17,7 +17,7 @@ fn foo(cond: &fn() -> bool, box: &fn() -> @int) { // Here we complain because the resulting region // of this borrow is the fn body as a whole. - y = borrow(x); //~ ERROR illegal borrow: cannot root managed value long enough + y = borrow(x); //~ ERROR cannot root assert!(*x == *y); if cond() { break; } diff --git a/src/test/compile-fail/regions-nested-fns-2.rs b/src/test/compile-fail/regions-nested-fns-2.rs index 2e9a4eb141037..fe995052c52e4 100644 --- a/src/test/compile-fail/regions-nested-fns-2.rs +++ b/src/test/compile-fail/regions-nested-fns-2.rs @@ -13,7 +13,7 @@ fn ignore(_f: &fn<'z>(&'z int) -> &'z int) {} fn nested() { let y = 3; ignore(|z| { - if false { &y } else { z } //~ ERROR illegal borrow + if false { &y } else { z } //~ ERROR borrowed value does not live long enough }); } diff --git a/src/test/compile-fail/regions-nested-fns.rs b/src/test/compile-fail/regions-nested-fns.rs index 3089c362a5044..74399967446ea 100644 --- a/src/test/compile-fail/regions-nested-fns.rs +++ b/src/test/compile-fail/regions-nested-fns.rs @@ -16,7 +16,7 @@ fn nested<'x>(x: &'x int) { ignore::<&fn<'z>(&'z int)>(|z| { ay = x; - ay = &y; //~ ERROR cannot infer an appropriate lifetime + ay = &y; ay = z; }); diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs index f916b0d95c2ee..f600f6f6edd92 100644 --- a/src/test/compile-fail/regions-ret-borrowed-1.rs +++ b/src/test/compile-fail/regions-ret-borrowed-1.rs @@ -19,6 +19,7 @@ fn with<'a, R>(f: &fn(x: &'a int) -> R) -> R { fn return_it<'a>() -> &'a int { with(|o| o) //~ ERROR mismatched types //~^ ERROR reference is not valid outside of its lifetime + //~^^ ERROR reference is not valid outside of its lifetime } fn main() { diff --git a/src/test/compile-fail/regions-ret-borrowed.rs b/src/test/compile-fail/regions-ret-borrowed.rs index 157b99de9e806..a3540f8f931f9 100644 --- a/src/test/compile-fail/regions-ret-borrowed.rs +++ b/src/test/compile-fail/regions-ret-borrowed.rs @@ -22,6 +22,7 @@ fn with(f: &fn(x: &int) -> R) -> R { fn return_it() -> &int { with(|o| o) //~ ERROR mismatched types //~^ ERROR reference is not valid outside of its lifetime + //~^^ ERROR reference is not valid outside of its lifetime } fn main() { diff --git a/src/test/compile-fail/regions-ret.rs b/src/test/compile-fail/regions-ret.rs index be7b28f6ef4b5..f1a7bdf228166 100644 --- a/src/test/compile-fail/regions-ret.rs +++ b/src/test/compile-fail/regions-ret.rs @@ -9,7 +9,7 @@ // except according to those terms. fn f<'a>(_x : &'a int) -> &'a int { - return &3; //~ ERROR illegal borrow + return &3; //~ ERROR borrowed value does not live long enough } fn main() { diff --git a/src/test/compile-fail/regions-var-type-out-of-scope.rs b/src/test/compile-fail/regions-var-type-out-of-scope.rs index 7d75ac7434931..addf20fd70249 100644 --- a/src/test/compile-fail/regions-var-type-out-of-scope.rs +++ b/src/test/compile-fail/regions-var-type-out-of-scope.rs @@ -14,7 +14,7 @@ fn foo(cond: bool) { let mut x; if cond { - x = &3; //~ ERROR illegal borrow: borrowed value does not live long enough + x = &3; //~ ERROR borrowed value does not live long enough assert!((*x == 3)); } } diff --git a/src/test/compile-fail/swap-no-lval.rs b/src/test/compile-fail/swap-no-lval.rs index 4fe30792e4b31..eca5fb0d315d8 100644 --- a/src/test/compile-fail/swap-no-lval.rs +++ b/src/test/compile-fail/swap-no-lval.rs @@ -10,6 +10,6 @@ fn main() { 5 <-> 3; - //~^ ERROR swapping to and from non-lvalue - //~^^ ERROR swapping to and from non-lvalue + //~^ ERROR cannot assign + //~^^ ERROR cannot assign } diff --git a/src/test/compile-fail/writing-to-immutable-vec.rs b/src/test/compile-fail/writing-to-immutable-vec.rs index 3f4c8ccef8175..faa3d6cfe47e7 100644 --- a/src/test/compile-fail/writing-to-immutable-vec.rs +++ b/src/test/compile-fail/writing-to-immutable-vec.rs @@ -8,5 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:assigning to immutable vec content -fn main() { let v: ~[int] = ~[1, 2, 3]; v[1] = 4; } +fn main() { + let v: ~[int] = ~[1, 2, 3]; + v[1] = 4; //~ ERROR cannot assign +} diff --git a/src/test/compile-fail/issue-4500.rs b/src/test/run-pass/borrowck-nested-calls.rs similarity index 51% rename from src/test/compile-fail/issue-4500.rs rename to src/test/run-pass/borrowck-nested-calls.rs index 356a64498219a..4494f5f2fa337 100644 --- a/src/test/compile-fail/issue-4500.rs +++ b/src/test/run-pass/borrowck-nested-calls.rs @@ -8,7 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn main () { - let mut _p: & int = & 4; - _p = &*~3; //~ ERROR illegal borrow +// xfail-test #5074 nested method calls + +// Test that (safe) nested calls with `&mut` receivers are permitted. + +struct Foo {a: uint, b: uint} + +pub impl Foo { + fn inc_a(&mut self, v: uint) { self.a += v; } + + fn next_b(&mut self) -> uint { + let b = self.b; + self.b += 1; + b + } +} + +fn main() { + let mut f = Foo {a: 22, b: 23}; + f.inc_a(f.next_b()); + assert_eq!(f.a, 22+23); + assert_eq!(f.b, 24); } diff --git a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs index 0e67532d7a1fc..b0d06dae10dc0 100644 --- a/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs +++ b/src/test/run-pass/coerce-reborrow-mut-vec-rcvr.rs @@ -1,10 +1,10 @@ trait Reverser { - fn reverse(&self); + fn reverse(self); } impl<'self> Reverser for &'self mut [uint] { - fn reverse(&self) { - vec::reverse(*self); + fn reverse(self) { + vec::reverse(self); } } diff --git a/src/test/run-pass/issue-2735-2.rs b/src/test/run-pass/issue-2735-2.rs index 96f76b0fd6ba6..ca584e1a6e3b8 100644 --- a/src/test/run-pass/issue-2735-2.rs +++ b/src/test/run-pass/issue-2735-2.rs @@ -9,27 +9,25 @@ // except according to those terms. // This test should behave exactly like issue-2735-3 -struct defer<'self> { - b: &'self mut bool, +struct defer { + b: @mut bool, } #[unsafe_destructor] -impl<'self> Drop for defer<'self> { +impl Drop for defer { fn finalize(&self) { - unsafe { - *(self.b) = true; - } + *self.b = true; } } -fn defer<'r>(b: &'r mut bool) -> defer<'r> { +fn defer(b: @mut bool) -> defer { defer { b: b } } pub fn main() { - let mut dtor_ran = false; - let _ = defer(&mut dtor_ran); - assert!((dtor_ran)); + let dtor_ran = @mut false; + let _ = defer(dtor_ran); + assert!(*dtor_ran); } diff --git a/src/test/run-pass/issue-2735-3.rs b/src/test/run-pass/issue-2735-3.rs index 50e3c946f50ef..44ca5d6929bd6 100644 --- a/src/test/run-pass/issue-2735-3.rs +++ b/src/test/run-pass/issue-2735-3.rs @@ -9,27 +9,25 @@ // except according to those terms. // This test should behave exactly like issue-2735-2 -struct defer<'self> { - b: &'self mut bool, +struct defer { + b: @mut bool, } #[unsafe_destructor] -impl<'self> Drop for defer<'self> { +impl Drop for defer { fn finalize(&self) { - unsafe { - *(self.b) = true; - } + *self.b = true; } } -fn defer<'r>(b: &'r mut bool) -> defer<'r> { +fn defer(b: @mut bool) -> defer { defer { b: b } } pub fn main() { - let mut dtor_ran = false; - defer(&mut dtor_ran); - assert!((dtor_ran)); + let dtor_ran = @mut false; + defer(dtor_ran); + assert!(*dtor_ran); } From 7fed4800733805156f0d157e45b01de405c4b48e Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 30 Apr 2013 13:01:12 -0400 Subject: [PATCH 051/215] char: fix unused import warning --- src/libcore/char.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcore/char.rs b/src/libcore/char.rs index ef2bd91e97313..7868b463807f6 100644 --- a/src/libcore/char.rs +++ b/src/libcore/char.rs @@ -10,6 +10,7 @@ //! Utilities for manipulating the char type +#[cfg(notest)] use cmp::Ord; use option::{None, Option, Some}; use str; From 6f18bb550e1293e77281b1cc76f1830a4da2d355 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 30 Apr 2013 13:01:20 -0400 Subject: [PATCH 052/215] iter: add a find function --- src/libcore/iter.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 7476531ef944c..6f3c6890228ac 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -41,6 +41,8 @@ much easier to implement. */ +use option::{Option, Some, None}; + pub trait Times { fn times(&self, it: &fn() -> bool); } @@ -104,6 +106,27 @@ pub fn all(predicate: &fn(T) -> bool, iter: &fn(f: &fn(T) -> bool)) -> bool { true } +/** + * Return the first element where `predicate` returns `true`, otherwise return `Npne` if no element + * is found. + * + * # Example: + * + * ~~~~ + * let xs = ~[1u, 2, 3, 4, 5, 6]; + * assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4); + * ~~~~ + */ +#[inline(always)] +pub fn find(predicate: &fn(&T) -> bool, iter: &fn(f: &fn(T) -> bool)) -> Option { + for iter |x| { + if predicate(&x) { + return Some(x); + } + } + None +} + #[cfg(test)] mod tests { use super::*; @@ -128,4 +151,10 @@ mod tests { assert!(all(|x: uint| x < 6, |f| uint::range(1, 6, f))); assert!(!all(|x: uint| x < 5, |f| uint::range(1, 6, f))); } + + #[test] + fn test_find() { + let xs = ~[1u, 2, 3, 4, 5, 6]; + assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4); + } } From 229ebf0bca23f5619940ecf2cf4541e0bb7416de Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 11:40:44 -0700 Subject: [PATCH 053/215] deleted two tests intended to test RUST_CC_ZEAL, an apparently defunct flag for the cycle collector --- src/test/run-pass/issue-1466.rs | 17 ----------------- src/test/run-pass/issue-1989.rs | 33 --------------------------------- 2 files changed, 50 deletions(-) delete mode 100644 src/test/run-pass/issue-1466.rs delete mode 100644 src/test/run-pass/issue-1989.rs diff --git a/src/test/run-pass/issue-1466.rs b/src/test/run-pass/issue-1466.rs deleted file mode 100644 index 1915f1b3a4100..0000000000000 --- a/src/test/run-pass/issue-1466.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// exec-env:RUST_CC_ZEAL=1 -// xfail-test - -pub fn main() { - error!("%?", os::getenv(~"RUST_CC_ZEAL")); - let _x = @{a: @10, b: ~true}; -} diff --git a/src/test/run-pass/issue-1989.rs b/src/test/run-pass/issue-1989.rs deleted file mode 100644 index e3327283a8162..0000000000000 --- a/src/test/run-pass/issue-1989.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// exec-env:RUST_CC_ZEAL=1 - -enum maybe_pointy { - none, - p(@mut Pointy) -} - -struct Pointy { - a : maybe_pointy, - f : @fn()->(), -} - -fn empty_pointy() -> @mut Pointy { - return @mut Pointy{ - a : none, - f : || {}, - } -} - -pub fn main() { - let v = ~[empty_pointy(), empty_pointy()]; - v[0].a = p(v[0]); -} From 5d8db6fd373f73e989439a4a95c6039ddc3fe1ed Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 12:25:44 -0700 Subject: [PATCH 054/215] remove (non-parsing) test related to impl d for d feature --- src/test/auxiliary/issue-2196-a.rs | 13 ------------- src/test/auxiliary/issue-2196-b.rs | 18 ------------------ src/test/auxiliary/issue-2196-c.rc | 16 ---------------- src/test/auxiliary/issue-2196-c.rs | 14 -------------- src/test/auxiliary/issue-2196-d.rs | 0 src/test/run-pass/issue-2196.rs | 19 ------------------- 6 files changed, 80 deletions(-) delete mode 100644 src/test/auxiliary/issue-2196-a.rs delete mode 100644 src/test/auxiliary/issue-2196-b.rs delete mode 100644 src/test/auxiliary/issue-2196-c.rc delete mode 100644 src/test/auxiliary/issue-2196-c.rs delete mode 100644 src/test/auxiliary/issue-2196-d.rs delete mode 100644 src/test/run-pass/issue-2196.rs diff --git a/src/test/auxiliary/issue-2196-a.rs b/src/test/auxiliary/issue-2196-a.rs deleted file mode 100644 index 959164d85dd2f..0000000000000 --- a/src/test/auxiliary/issue-2196-a.rs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[link(name = "issue2196a", vers = "0.1")]; -#[crate_type = "lib"]; - diff --git a/src/test/auxiliary/issue-2196-b.rs b/src/test/auxiliary/issue-2196-b.rs deleted file mode 100644 index 1ef9334b7cdf3..0000000000000 --- a/src/test/auxiliary/issue-2196-b.rs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[link(name = "issue2196b", vers = "0.1")]; -#[crate_type = "lib"]; - -use a(name = "issue2196a"); - -type d = str; -impl d for d { } - diff --git a/src/test/auxiliary/issue-2196-c.rc b/src/test/auxiliary/issue-2196-c.rc deleted file mode 100644 index 59c1e8108c08c..0000000000000 --- a/src/test/auxiliary/issue-2196-c.rc +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[link(name = "issue2196c", vers = "0.1")]; -#[crate_type = "lib"]; - -use b(name = "issue2196b"); -#[path = "issue-2196-d.rs"] -mod d; diff --git a/src/test/auxiliary/issue-2196-c.rs b/src/test/auxiliary/issue-2196-c.rs deleted file mode 100644 index 290267cbf3258..0000000000000 --- a/src/test/auxiliary/issue-2196-c.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use b::d; - -type t = uint; - diff --git a/src/test/auxiliary/issue-2196-d.rs b/src/test/auxiliary/issue-2196-d.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/test/run-pass/issue-2196.rs b/src/test/run-pass/issue-2196.rs deleted file mode 100644 index 3fce821561a90..0000000000000 --- a/src/test/run-pass/issue-2196.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-test -// aux-build:issue-2196-a.rs -// aux-build:issue-2196-b.rs -// aux-build:issue-2196-c.rc - -use c(name = "issue2196c"); -use c::t; - -pub fn main() { } From 78942a2d16a9cb57f518ee6220b252e1e96e5881 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 13:22:59 -0700 Subject: [PATCH 055/215] this issue is a dup of another one that has a correct test case this test case has rotted wrt modern syntax. fortunately, this issue was a dup of another one, and that one still ICEs. --- src/test/run-pass/issue-2869.rs | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 src/test/run-pass/issue-2869.rs diff --git a/src/test/run-pass/issue-2869.rs b/src/test/run-pass/issue-2869.rs deleted file mode 100644 index 619f4b4d7db8a..0000000000000 --- a/src/test/run-pass/issue-2869.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-test -enum pat { pat_ident(Option) } - -fn f(pat: pat) -> bool { true } - -fn num_bindings(pat: pat) -> uint { - match pat { - pat_ident(_) if f(pat) { 0 } - pat_ident(None) { 1 } - pat_ident(Some(sub)) { sub } - } -} - -pub fn main() {} From 77da0553455c5b236ea80056f743b26c7c0edbd3 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 13:44:49 -0700 Subject: [PATCH 056/215] This test case is obsolete for two reasons First, it refers to a feature (trait bounds on type parameters) that's apparently no longer in the language. Second, if I understand the issue correctly, it should never have been a "run-pass" test because it was supposed to fail. --- src/test/run-pass/issue-3480.rs | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 src/test/run-pass/issue-3480.rs diff --git a/src/test/run-pass/issue-3480.rs b/src/test/run-pass/issue-3480.rs deleted file mode 100644 index aaff822398d6f..0000000000000 --- a/src/test/run-pass/issue-3480.rs +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-test -type IMap = ~[(K, V)]; - -trait ImmutableMap -{ - fn contains_key(key: K) -> bool; -} - -impl IMap : ImmutableMap -{ - fn contains_key(key: K) -> bool { - vec::find(self, |e| {e.first() == key}).is_some() - } -} - -pub fn main() {} From 9455eaf77bef8f225e146e61107d26010f137b51 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 13:58:15 -0700 Subject: [PATCH 057/215] changed to impl trait for type stx --- src/test/run-pass/issue-3979-generics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/run-pass/issue-3979-generics.rs b/src/test/run-pass/issue-3979-generics.rs index d26e9f1ba7b43..57962911538de 100644 --- a/src/test/run-pass/issue-3979-generics.rs +++ b/src/test/run-pass/issue-3979-generics.rs @@ -32,7 +32,7 @@ impl Positioned for Point { } } -impl Point: Movable; +impl Movable for Point; pub fn main() { let p = Point{ x: 1, y: 2}; From aa48a170d55e3003b70626b16ccd698b5aca8269 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 30 Apr 2013 14:07:26 -0400 Subject: [PATCH 058/215] dataflow: fix flow of information through pattern variants --- src/librustc/middle/dataflow.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index cfdd7f95030aa..9d032a1839e23 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -846,10 +846,9 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { // alternatives, so we must treat this like an N-way select // statement. let initial_state = reslice(in_out).to_vec(); - self.reset(in_out); for pats.each |&pat| { let mut temp = copy initial_state; - self.walk_pat(pat, in_out, loop_scopes); + self.walk_pat(pat, temp, loop_scopes); join_bits(&self.dfcx.oper, temp, in_out); } } From 7a0c1ea560126a6ccefbe7981fd1e18d80d3ed20 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 30 Apr 2013 14:07:52 -0400 Subject: [PATCH 059/215] correct used_mut annotations for args, inherited case --- src/librustc/middle/borrowck/check_loans.rs | 33 +++++++++------- .../middle/borrowck/gather_loans/lifetime.rs | 4 +- .../middle/borrowck/gather_loans/mod.rs | 39 ------------------- .../borrowck/gather_loans/restrictions.rs | 4 +- src/librustc/middle/borrowck/mod.rs | 5 +-- 5 files changed, 24 insertions(+), 61 deletions(-) diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 56eb57009ca08..9330395c061a7 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -260,11 +260,21 @@ pub impl<'self> CheckLoanCtxt<'self> { // and report an error otherwise. match cmt.mutbl { mc::McDeclared => { - // OK + // OK, but we have to mark arguments as requiring mut + // if they are assigned (other cases are handled by liveness, + // since we need to distinguish local variables assigned + // once vs those assigned multiple times) + match cmt.cat { + mc::cat_self(*) | + mc::cat_arg(*) => { + mark_variable_as_used_mut(self, cmt); + } + _ => {} + } } mc::McInherited => { // OK, but we may have to add an entry to `used_mut_nodes` - mark_writes_through_upvars_as_used_mut(self, cmt); + mark_variable_as_used_mut(self, cmt); } mc::McReadOnly | mc::McImmutable => { // Subtle: liveness guarantees that immutable local @@ -289,33 +299,28 @@ pub impl<'self> CheckLoanCtxt<'self> { self, expr, cmt); } - fn mark_writes_through_upvars_as_used_mut(self: &CheckLoanCtxt, - cmt: mc::cmt) { + fn mark_variable_as_used_mut(self: &CheckLoanCtxt, + cmt: mc::cmt) { //! If the mutability of the `cmt` being written is inherited - //! from a local variable in another closure, liveness may + //! from a local variable, liveness will //! not have been able to detect that this variable's mutability //! is important, so we must add the variable to the - //! `used_mut_nodes` table here. This is because liveness - //! does not consider closures. + //! `used_mut_nodes` table here. - let mut passed_upvar = false; let mut cmt = cmt; loop { debug!("mark_writes_through_upvars_as_used_mut(cmt=%s)", cmt.repr(self.tcx())); match cmt.cat { mc::cat_local(id) | - mc::cat_arg(id, _) | + mc::cat_arg(id) | mc::cat_self(id) => { - if passed_upvar { - self.tcx().used_mut_nodes.insert(id); - } + self.tcx().used_mut_nodes.insert(id); return; } mc::cat_stack_upvar(b) => { cmt = b; - passed_upvar = true; } mc::cat_rvalue | @@ -552,7 +557,7 @@ pub impl<'self> CheckLoanCtxt<'self> { match cmt.cat { // Rvalues, locals, and arguments can be moved: mc::cat_rvalue | mc::cat_local(_) | - mc::cat_arg(_, ast::by_copy) | mc::cat_self(_) => {} + mc::cat_arg(_) | mc::cat_self(_) => {} // It seems strange to allow a move out of a static item, // but what happens in practice is that you have a diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 21d7e7041d959..4d267b7dc471c 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -255,7 +255,7 @@ impl GuaranteeLifetimeContext { match cmt.guarantor().cat { mc::cat_local(id) | mc::cat_self(id) | - mc::cat_arg(id, _) => { + mc::cat_arg(id) => { self.bccx.moved_variables_set.contains(&id) } mc::cat_rvalue | @@ -292,7 +292,7 @@ impl GuaranteeLifetimeContext { ty::re_static } mc::cat_local(local_id) | - mc::cat_arg(local_id, _) | + mc::cat_arg(local_id) | mc::cat_self(local_id) => { self.bccx.tcx.region_maps.encl_region(local_id) } diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 82638ceb4d4f1..1bc3b70ac3842 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -27,7 +27,6 @@ use util::common::indenter; use util::ppaux::{Repr}; use core::hashmap::HashSet; -use core::vec; use syntax::ast::{m_const, m_imm, m_mutbl}; use syntax::ast; use syntax::ast_util::id_range; @@ -169,20 +168,6 @@ fn gather_loans_in_expr(ex: @ast::expr, visit::visit_expr(ex, self, vt); } - ast::expr_call(f, ref args, _) => { - let arg_tys = ty::ty_fn_args(ty::expr_ty(self.tcx(), f)); - self.guarantee_arguments(ex, *args, arg_tys); - visit::visit_expr(ex, self, vt); - } - - ast::expr_method_call(_, _, _, ref args, _) => { - let arg_tys = ty::ty_fn_args(ty::node_id_to_type(self.tcx(), - ex.callee_id)); - self.guarantee_arguments(ex, *args, arg_tys); - - visit::visit_expr(ex, self, vt); - } - ast::expr_match(ex_v, ref arms) => { let cmt = self.bccx.cat_expr(ex_v); for arms.each |arm| { @@ -271,30 +256,6 @@ pub impl GatherLoanCtxt { assert!(id == popped); } - fn guarantee_arguments(&mut self, - call_expr: @ast::expr, - args: &[@ast::expr], - arg_tys: &[ty::arg]) { - for vec::each2(args, arg_tys) |arg, arg_ty| { - match ty::resolved_mode(self.tcx(), arg_ty.mode) { - ast::by_ref => { - self.guarantee_by_ref_argument(call_expr, *arg); - } - ast::by_copy => {} - } - } - } - - fn guarantee_by_ref_argument(&mut self, - call_expr: @ast::expr, - arg_expr: @ast::expr) { - // FIXME(#5074) nested method calls - let scope_r = ty::re_scope(call_expr.id); - let arg_cmt = self.bccx.cat_expr(arg_expr); - self.guarantee_valid(arg_expr.id, arg_expr.span, - arg_cmt, m_imm, scope_r); - } - fn guarantee_adjustments(&mut self, expr: @ast::expr, adjustment: &ty::AutoAdjustment) { diff --git a/src/librustc/middle/borrowck/gather_loans/restrictions.rs b/src/librustc/middle/borrowck/gather_loans/restrictions.rs index 950dbc58ec364..0be4c67a9bc91 100644 --- a/src/librustc/middle/borrowck/gather_loans/restrictions.rs +++ b/src/librustc/middle/borrowck/gather_loans/restrictions.rs @@ -15,7 +15,6 @@ use middle::borrowck::*; use mc = middle::mem_categorization; use middle::ty; use syntax::ast::{m_const, m_imm, m_mutbl}; -use syntax::ast; use syntax::codemap::span; pub enum RestrictionResult { @@ -74,7 +73,7 @@ impl RestrictionsContext { } mc::cat_local(local_id) | - mc::cat_arg(local_id, ast::by_copy) | + mc::cat_arg(local_id) | mc::cat_self(local_id) => { let lp = @LpVar(local_id); SafeIf(lp, ~[Restriction {loan_path: lp, @@ -114,7 +113,6 @@ impl RestrictionsContext { mc::cat_copied_upvar(*) | // FIXME(#2152) allow mutation of upvars mc::cat_static_item(*) | mc::cat_implicit_self(*) | - mc::cat_arg(_, ast::by_ref) | mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) | mc::cat_deref(_, _, mc::gc_ptr(m_imm)) => { Safe diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index c108b020378eb..3f10223723727 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -242,13 +242,12 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> { mc::cat_rvalue | mc::cat_static_item | mc::cat_copied_upvar(_) | - mc::cat_implicit_self | - mc::cat_arg(_, ast::by_ref) => { + mc::cat_implicit_self => { None } mc::cat_local(id) | - mc::cat_arg(id, ast::by_copy) | + mc::cat_arg(id) | mc::cat_self(id) => { Some(@LpVar(id)) } From 545d51c1608198aed4e3bdca0dac23bcc6af19b9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 30 Apr 2013 14:08:18 -0400 Subject: [PATCH 060/215] rustc: remove modes --- src/librustc/middle/mem_categorization.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index f525230664a21..5921e4b0e4ca0 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -64,7 +64,7 @@ pub enum categorization { cat_copied_upvar(CopiedUpvar), // upvar copied into @fn or ~fn env cat_stack_upvar(cmt), // by ref upvar from &fn cat_local(ast::node_id), // local variable - cat_arg(ast::node_id, ast::rmode), // formal argument + cat_arg(ast::node_id), // formal argument cat_deref(cmt, uint, ptr_kind), // deref of a ptr cat_interior(cmt, interior_kind), // something interior cat_discr(cmt, ast::node_id), // match discriminant (see preserve()) @@ -465,11 +465,10 @@ pub impl mem_categorization_ctxt { // m: mutability of the argument let m = if mutbl {McDeclared} else {McImmutable}; - let mode = ty::resolved_mode(self.tcx, mode); @cmt_ { id: id, span: span, - cat: cat_arg(vid, mode), + cat: cat_arg(vid), mutbl: m, ty:expr_ty } @@ -1059,7 +1058,7 @@ pub impl cmt_ { cat_copied_upvar(CopiedUpvar {onceness: ast::Once, _}) | cat_rvalue(*) | cat_local(*) | - cat_arg(_, ast::by_copy) | + cat_arg(_) | cat_self(*) | cat_deref(_, _, unsafe_ptr(*)) | // of course it is aliasable, but... cat_deref(_, _, region_ptr(m_mutbl, _)) => { @@ -1068,8 +1067,7 @@ pub impl cmt_ { cat_copied_upvar(CopiedUpvar {onceness: ast::Many, _}) | cat_static_item(*) | - cat_implicit_self(*) | - cat_arg(_, ast::by_ref) => { + cat_implicit_self(*) => { Some(AliasableOther) } From 70b9ad1748748d93ccef95b59435a7357b350d11 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 30 Apr 2013 14:09:14 -0400 Subject: [PATCH 061/215] rustc: work around issue with default-method-simple, fix some rebase errors --- src/librustc/middle/ty.rs | 7 +++++++ src/librustc/middle/typeck/check/method.rs | 16 ++++++++++++++++ src/librustc/middle/typeck/check/mod.rs | 3 ++- src/librustc/middle/typeck/check/regionck.rs | 10 ++++------ 4 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 28705ac49320a..b17dac82048bf 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1553,6 +1553,13 @@ pub fn type_is_ty_var(ty: t) -> bool { pub fn type_is_bool(ty: t) -> bool { get(ty).sty == ty_bool } +pub fn type_is_self(ty: t) -> bool { + match get(ty).sty { + ty_self(*) => true, + _ => false + } +} + pub fn type_is_structural(ty: t) -> bool { match get(ty).sty { ty_struct(*) | ty_tup(_) | ty_enum(*) | ty_closure(_) | ty_trait(*) | diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 0cc2ddd32b46a..de6530fb464c5 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -658,6 +658,12 @@ pub impl<'self> LookupContext<'self> { let tcx = self.tcx(); return match ty::get(self_ty).sty { + ty::ty_rptr(_, self_mt) if default_method_hack(self_mt) => { + (self_ty, + ty::AutoDerefRef(ty::AutoDerefRef { + autoderefs: autoderefs, + autoref: None})) + } ty::ty_rptr(_, self_mt) => { let region = self.infcx().next_region_var_nb(self.expr.span); (ty::mk_rptr(tcx, region, self_mt), @@ -679,6 +685,16 @@ pub impl<'self> LookupContext<'self> { autoref: None})) } }; + + fn default_method_hack(self_mt: ty::mt) -> bool { + // FIXME(#6129). Default methods can't deal with autoref. + // + // I am a horrible monster and I pray for death. Currently + // the default method code fails when you try to reborrow + // because it is not handling types correctly. In lieu of + // fixing that, I am introducing this horrible hack. - ndm + self_mt.mutbl == m_imm && ty::type_is_self(self_mt.ty) + } } fn search_for_autosliced_method( diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 84fc40f6954a8..fb58df3d55c68 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -2966,7 +2966,8 @@ pub fn check_block(fcx0: @mut FnCtxt, blk: &ast::blk) { pub fn check_block_with_expected(fcx: @mut FnCtxt, blk: &ast::blk, expected: Option) { - let prev = replace(&mut fcx.ps, fcx.ps.recurse(blk)); + let purity_state = fcx.ps.recurse(blk); + let prev = replace(&mut fcx.ps, purity_state); do fcx.with_region_lb(blk.node.id) { let mut warned = false; diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 1c35c911b14cd..be513cbb0f307 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -457,20 +457,18 @@ fn constrain_call(rcx: @mut Rcx, let callee_scope = call_expr.id; let callee_region = ty::re_scope(callee_scope); - for fn_sig.inputs.eachi |i, input| { + for arg_exprs.each |&arg_expr| { // ensure that any regions appearing in the argument type are // valid for at least the lifetime of the function: constrain_regions_in_type_of_node( - rcx, arg_exprs[i].id, callee_region, arg_exprs[i].span); + rcx, arg_expr.id, callee_region, arg_expr.span); // unfortunately, there are two means of taking implicit // references, and we need to propagate constraints as a // result. modes are going away and the "DerefArgs" code // should be ported to use adjustments - ty::set_default_mode(tcx, input.mode, ast::by_copy); - let is_by_ref = ty::resolved_mode(tcx, input.mode) == ast::by_ref; - if implicitly_ref_args || is_by_ref { - guarantor::for_by_ref(rcx, arg_exprs[i], callee_scope); + if implicitly_ref_args { + guarantor::for_by_ref(rcx, arg_expr, callee_scope); } } From 418f99111852d13e9446c70cd616e6e6780bb632 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 30 Apr 2013 14:10:21 -0400 Subject: [PATCH 062/215] allover: numerous unused muts etc --- src/compiletest/header.rs | 3 +-- src/compiletest/runtest.rs | 2 +- src/libcore/cell.rs | 4 ++-- src/libcore/comm.rs | 4 ++-- src/libcore/flate.rs | 13 ++++++------- src/libcore/libc.rs | 3 +-- src/libcore/os.rs | 17 ++++++++--------- src/libcore/rt/sched/mod.rs | 2 -- src/libcore/unstable/extfmt.rs | 6 +++--- src/libcore/vec.rs | 9 +++------ src/librustc/middle/lang_items.rs | 11 +++++------ src/librustc/middle/moves.rs | 2 +- src/librustc/util/ppaux.rs | 3 ++- src/libstd/ebml.rs | 2 +- src/libstd/future.rs | 2 +- src/libstd/sort.rs | 1 - src/libstd/workcache.rs | 2 +- src/libsyntax/parse/mod.rs | 2 +- src/libsyntax/parse/parser.rs | 3 +-- src/test/compile-fail/die-not-static.rs | 3 +-- 20 files changed, 41 insertions(+), 53 deletions(-) diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index b0d04c6739b4a..28bbbda966340 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -82,14 +82,13 @@ pub fn load_props(testfile: &Path) -> TestProps { } pub fn is_test_ignored(config: config, testfile: &Path) -> bool { - let mut found = false; for iter_header(testfile) |ln| { if parse_name_directive(ln, ~"xfail-test") { return true; } if parse_name_directive(ln, xfail_target()) { return true; } if config.mode == common::mode_pretty && parse_name_directive(ln, ~"xfail-pretty") { return true; } }; - return found; + return false; fn xfail_target() -> ~str { ~"xfail-" + str::from_slice(os::SYSNAME) diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index fef4cabf7fd6d..5805c1730296c 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -106,7 +106,7 @@ fn run_rpass_test(config: config, props: TestProps, testfile: &Path) { fatal_ProcRes(~"test run failed!", ProcRes); } } else { - let mut ProcRes = jit_test(config, props, testfile); + let ProcRes = jit_test(config, props, testfile); if ProcRes.status != 0 { fatal_ProcRes(~"jit failed!", ProcRes); } } diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 27e03d2bf3103..959defeec0413 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -42,7 +42,7 @@ pub fn empty_cell() -> Cell { pub impl Cell { /// Yields the value, failing if the cell is empty. fn take(&self) -> T { - let mut self = unsafe { transmute_mut(self) }; + let self = unsafe { transmute_mut(self) }; if self.is_empty() { fail!(~"attempt to take an empty cell"); } @@ -54,7 +54,7 @@ pub impl Cell { /// Returns the value, failing if the cell is full. fn put_back(&self, value: T) { - let mut self = unsafe { transmute_mut(self) }; + let self = unsafe { transmute_mut(self) }; if !self.is_empty() { fail!(~"attempt to put a value back into a full cell"); } diff --git a/src/libcore/comm.rs b/src/libcore/comm.rs index 50a3bba049bbb..d075ff08bb7eb 100644 --- a/src/libcore/comm.rs +++ b/src/libcore/comm.rs @@ -205,8 +205,8 @@ impl Selectable for Port { fn header(&self) -> *PacketHeader { unsafe { match self.endp { - Some(ref endp) => endp.header(), - None => fail!(~"peeking empty stream") + Some(ref endp) => endp.header(), + None => fail!(~"peeking empty stream") } } } diff --git a/src/libcore/flate.rs b/src/libcore/flate.rs index c3518cc8b6ee2..ba10f97e626c4 100644 --- a/src/libcore/flate.rs +++ b/src/libcore/flate.rs @@ -16,7 +16,6 @@ Simple compression use libc; use libc::{c_void, size_t, c_int}; -use ptr; use vec; #[cfg(test)] use rand; @@ -29,13 +28,13 @@ pub mod rustrt { pub extern { unsafe fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void, src_buf_len: size_t, - pout_len: *size_t, + pout_len: *mut size_t, flags: c_int) -> *c_void; unsafe fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void, src_buf_len: size_t, - pout_len: *size_t, + pout_len: *mut size_t, flags: c_int) -> *c_void; } @@ -53,11 +52,11 @@ pub fn deflate_bytes(bytes: &const [u8]) -> ~[u8] { let res = rustrt::tdefl_compress_mem_to_heap(b as *c_void, len as size_t, - &outsz, + &mut outsz, lz_norm); assert!(res as int != 0); let out = vec::raw::from_buf_raw(res as *u8, - outsz as uint); + outsz as uint); libc::free(res); out } @@ -67,11 +66,11 @@ pub fn deflate_bytes(bytes: &const [u8]) -> ~[u8] { pub fn inflate_bytes(bytes: &const [u8]) -> ~[u8] { do vec::as_const_buf(bytes) |b, len| { unsafe { - let outsz : size_t = 0; + let mut outsz : size_t = 0; let res = rustrt::tinfl_decompress_mem_to_heap(b as *c_void, len as size_t, - &outsz, + &mut outsz, 0); assert!(res as int != 0); let out = vec::raw::from_buf_raw(res as *u8, diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs index 44864630f9873..d7a9ab4d63b5f 100644 --- a/src/libcore/libc.rs +++ b/src/libcore/libc.rs @@ -253,8 +253,7 @@ pub mod types { pub type ssize_t = i32; } pub mod posix01 { - use libc::types::os::arch::c95::{c_int, c_short, c_long, - time_t}; + use libc::types::os::arch::c95::{c_short, c_long, time_t}; use libc::types::os::arch::posix88::{dev_t, gid_t, ino_t}; use libc::types::os::arch::posix88::{mode_t, off_t}; use libc::types::os::arch::posix88::{uid_t}; diff --git a/src/libcore/os.rs b/src/libcore/os.rs index f1962eeaa23d0..d5271ec228ba5 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -351,13 +351,13 @@ pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int { } } -pub struct Pipe { mut in: c_int, mut out: c_int } +pub struct Pipe { in: c_int, out: c_int } #[cfg(unix)] pub fn pipe() -> Pipe { unsafe { let mut fds = Pipe {in: 0 as c_int, - out: 0 as c_int }; + out: 0 as c_int }; assert!((libc::pipe(&mut fds.in) == (0 as c_int))); return Pipe {in: fds.in, out: fds.out}; } @@ -373,8 +373,7 @@ pub fn pipe() -> Pipe { // fully understand. Here we explicitly make the pipe non-inheritable, // which means to pass it to a subprocess they need to be duplicated // first, as in rust_run_program. - let mut fds = Pipe {in: 0 as c_int, - out: 0 as c_int }; + let mut fds = Pipe {in: 0 as c_int, out: 0 as c_int}; let res = libc::pipe(&mut fds.in, 1024 as ::libc::c_uint, (libc::O_BINARY | libc::O_NOINHERIT) as c_int); assert!((res == 0 as c_int)); @@ -959,10 +958,10 @@ pub fn last_os_error() -> ~str { #[cfg(target_os = "macos")] #[cfg(target_os = "android")] #[cfg(target_os = "freebsd")] - fn strerror_r(errnum: c_int, buf: *c_char, buflen: size_t) -> c_int { + fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int { #[nolink] extern { - unsafe fn strerror_r(errnum: c_int, buf: *c_char, + unsafe fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; } unsafe { @@ -974,10 +973,10 @@ pub fn last_os_error() -> ~str { // and requires macros to instead use the POSIX compliant variant. // So we just use __xpg_strerror_r which is always POSIX compliant #[cfg(target_os = "linux")] - fn strerror_r(errnum: c_int, buf: *c_char, buflen: size_t) -> c_int { + fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int { #[nolink] extern { - unsafe fn __xpg_strerror_r(errnum: c_int, buf: *c_char, + unsafe fn __xpg_strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int; } unsafe { @@ -987,7 +986,7 @@ pub fn last_os_error() -> ~str { let mut buf = [0 as c_char, ..TMPBUF_SZ]; unsafe { - let err = strerror_r(errno() as c_int, &buf[0], + let err = strerror_r(errno() as c_int, &mut buf[0], TMPBUF_SZ as size_t); if err < 0 { fail!(~"strerror_r failure"); diff --git a/src/libcore/rt/sched/mod.rs b/src/libcore/rt/sched/mod.rs index a2132676c1a03..333146394ee1f 100644 --- a/src/libcore/rt/sched/mod.rs +++ b/src/libcore/rt/sched/mod.rs @@ -136,7 +136,6 @@ pub impl Scheduler { /// Called by a running task to end execution, after which it will /// be recycled by the scheduler for reuse in a new task. fn terminate_current_task(~self) { - let mut self = self; assert!(self.in_task_context()); rtdebug!("ending running task"); @@ -152,7 +151,6 @@ pub impl Scheduler { } fn schedule_new_task(~self, task: ~Task) { - let mut self = self; assert!(self.in_task_context()); do self.switch_running_tasks_and_then(task) |last_task| { diff --git a/src/libcore/unstable/extfmt.rs b/src/libcore/unstable/extfmt.rs index b812be5575a4a..e5d32c4bb3259 100644 --- a/src/libcore/unstable/extfmt.rs +++ b/src/libcore/unstable/extfmt.rs @@ -501,7 +501,7 @@ pub mod rt { pub fn conv_int(cv: Conv, i: int, buf: &mut ~str) { let radix = 10; let prec = get_int_precision(cv); - let mut s : ~str = uint_to_str_prec(int::abs(i) as uint, radix, prec); + let s : ~str = uint_to_str_prec(int::abs(i) as uint, radix, prec); let head = if i >= 0 { if have_flag(cv.flags, flag_sign_always) { @@ -516,7 +516,7 @@ pub mod rt { } pub fn conv_uint(cv: Conv, u: uint, buf: &mut ~str) { let prec = get_int_precision(cv); - let mut rs = + let rs = match cv.ty { TyDefault => uint_to_str_prec(u, 10, prec), TyHexLower => uint_to_str_prec(u, 16, prec), @@ -559,7 +559,7 @@ pub mod rt { CountIs(c) => (float::to_str_exact, c as uint), CountImplied => (float::to_str_digits, 6u) }; - let mut s = to_str(f, digits); + let s = to_str(f, digits); let head = if 0.0 <= f { if have_flag(cv.flags, flag_sign_always) { Some('+') diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 2f9488d1bc7a7..4c817da081982 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -1826,12 +1826,9 @@ impl<'self,T:Copy> CopyableVector for &'self [T] { #[inline] fn to_owned(&self) -> ~[T] { let mut result = ~[]; - // FIXME: #4568 - unsafe { - reserve(&mut result, self.len()); - for self.each |e| { - result.push(copy *e); - } + reserve(&mut result, self.len()); + for self.each |e| { + result.push(copy *e); } result diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 784db49a0fd62..e7261d53952a2 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -28,7 +28,6 @@ use syntax::ast_util::local_def; use syntax::visit::{default_simple_visitor, mk_simple_visitor, SimpleVisitor}; use syntax::visit::visit_crate; -use core::cast::transmute; use core::hashmap::HashMap; pub enum LangItem { @@ -370,7 +369,7 @@ pub impl LanguageItemCollector { } fn collect_local_language_items(&mut self) { - let this = ptr::addr_of(&self); + let this: *mut LanguageItemCollector = &mut *self; visit_crate(self.crate, (), mk_simple_visitor(@SimpleVisitor { visit_item: |item| { for item.attrs.each |attribute| { @@ -380,10 +379,10 @@ pub impl LanguageItemCollector { attribute.node.value ); } - }, - .. *default_simple_visitor() - })); - } + } + }, + .. *default_simple_visitor() + })); } fn collect_external_language_items(&mut self) { diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index d8a0e6bacf489..0daad80af5db7 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -299,7 +299,7 @@ pub fn compute_moves(tcx: ty::ctxt, pub fn moved_variable_node_id_from_def(def: def) -> Option { match def { def_binding(nid, _) | - def_arg(nid, _, _) | + def_arg(nid, _) | def_local(nid, _) | def_self(nid, _) => Some(nid), diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index d99d87231bece..751fe19f2a236 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -13,7 +13,8 @@ use middle::ty::{ReSkolemized, ReVar}; use middle::ty::{bound_region, br_anon, br_named, br_self, br_cap_avoid}; use middle::ty::{br_fresh, ctxt, field, method}; use middle::ty::{mt, t, param_bound, param_ty}; -use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region}; +use middle::ty::{re_bound, re_free, re_scope, re_infer, re_static, Region, + re_empty}; use middle::ty::{ty_bool, ty_bot, ty_box, ty_struct, ty_enum}; use middle::ty::{ty_err, ty_estr, ty_evec, ty_float, ty_bare_fn, ty_closure}; use middle::ty::{ty_nil, ty_opaque_box, ty_opaque_closure_ptr, ty_param}; diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index 9b89036eee51b..65ce9d8989f05 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -617,7 +617,7 @@ pub mod writer { priv impl Encoder { // used internally to emit things like the vector length and so on fn _emit_tagged_uint(&self, t: EbmlEncoderTag, v: uint) { - assert!(v <= 0xFFFF_FFFF_u); + assert!(v <= 0xFFFF_FFFF_u); // FIXME(#6130) assert warns on 32-bit self.wr_tagged_u32(t as uint, v as u32); } diff --git a/src/libstd/future.rs b/src/libstd/future.rs index c3fc16bdf70ba..5e3e64b2f1cfa 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -23,7 +23,7 @@ use core::cast; use core::cell::Cell; -use core::comm::{ChanOne, PortOne, oneshot, send_one}; +use core::comm::{PortOne, oneshot, send_one}; use core::pipes::recv; use core::task; diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index c153d7f22c034..f3d30ecd5cdf1 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -11,7 +11,6 @@ //! Sorting methods use core::cmp::{Eq, Ord}; -use core::util; use core::vec::len; use core::vec; diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs index bb4a9e97ea1f4..c01d1f5a2d7b0 100644 --- a/src/libstd/workcache.rs +++ b/src/libstd/workcache.rs @@ -17,7 +17,7 @@ use sort; use core::cell::Cell; use core::cmp; -use core::comm::{ChanOne, PortOne, oneshot, send_one}; +use core::comm::{PortOne, oneshot, send_one}; use core::either::{Either, Left, Right}; use core::hashmap::HashMap; use core::io; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 7e7931bbb606b..5d51a54d770b1 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -24,7 +24,7 @@ use parse::token::{ident_interner, mk_ident_interner}; use core::io; use core::option::{None, Option, Some}; use core::path::Path; -use core::result::{Err, Ok, Result}; +use core::result::{Err, Ok}; pub mod lexer; pub mod parser; diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 50bdfb2f55726..1129e7b708ea2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -938,7 +938,7 @@ pub impl Parser { match *self.token { token::MOD_SEP => { match self.look_ahead(1u) { - token::IDENT(id,_) => { + token::IDENT(*) => { self.bump(); ids.push(self.parse_ident()); } @@ -3728,7 +3728,6 @@ pub impl Parser { items: _, foreign_items: foreign_items } = self.parse_foreign_items(first_item_attrs, true); - let mut initial_attrs = attrs_remaining; assert!(*self.token == token::RBRACE); ast::foreign_mod { sort: sort, diff --git a/src/test/compile-fail/die-not-static.rs b/src/test/compile-fail/die-not-static.rs index b30e3942e6330..d33c591d8c87f 100644 --- a/src/test/compile-fail/die-not-static.rs +++ b/src/test/compile-fail/die-not-static.rs @@ -1,7 +1,6 @@ -// error-pattern:illegal borrow: borrowed value does not live long enough - fn main() { let v = ~"test"; let sslice = str::slice(v, 0, v.len()); + //~^ ERROR borrowed value does not live long enough fail!(sslice); } From a6eaa3bbb490b01c21864adc41e12eafb98a3c32 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 30 Apr 2013 13:28:20 -0400 Subject: [PATCH 063/215] iter: add max and min functions --- src/libcore/iter.rs | 68 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 6f3c6890228ac..8fc2db6d6f19a 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -41,6 +41,7 @@ much easier to implement. */ +use cmp::Ord; use option::{Option, Some, None}; pub trait Times { @@ -107,8 +108,7 @@ pub fn all(predicate: &fn(T) -> bool, iter: &fn(f: &fn(T) -> bool)) -> bool { } /** - * Return the first element where `predicate` returns `true`, otherwise return `Npne` if no element - * is found. + * Return the first element where `predicate` returns `true`. Return `None` if no element is found. * * # Example: * @@ -127,6 +127,58 @@ pub fn find(predicate: &fn(&T) -> bool, iter: &fn(f: &fn(T) -> bool)) -> Opti None } +/** + * Return the largest item yielded by an iterator. Return `None` if the iterator is empty. + * + * # Example: + * + * ~~~~ + * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; + * assert_eq!(max(|f| xs.each(f)).unwrap(), &15); + * ~~~~ + */ +#[inline] +pub fn max(iter: &fn(f: &fn(T) -> bool)) -> Option { + let mut result = None; + for iter |x| { + match result { + Some(ref mut y) => { + if x > *y { + *y = x; + } + } + None => result = Some(x) + } + } + result +} + +/** + * Return the smallest item yielded by an iterator. Return `None` if the iterator is empty. + * + * # Example: + * + * ~~~~ + * let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; + * assert_eq!(max(|f| xs.each(f)).unwrap(), &-5); + * ~~~~ + */ +#[inline] +pub fn min(iter: &fn(f: &fn(T) -> bool)) -> Option { + let mut result = None; + for iter |x| { + match result { + Some(ref mut y) => { + if x < *y { + *y = x; + } + } + None => result = Some(x) + } + } + result +} + #[cfg(test)] mod tests { use super::*; @@ -157,4 +209,16 @@ mod tests { let xs = ~[1u, 2, 3, 4, 5, 6]; assert_eq!(*find(|& &x: & &uint| x > 3, |f| xs.each(f)).unwrap(), 4); } + + #[test] + fn test_max() { + let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; + assert_eq!(max(|f| xs.each(f)).unwrap(), &15); + } + + #[test] + fn test_min() { + let xs = ~[8, 2, 3, 1, -5, 9, 11, 15]; + assert_eq!(min(|f| xs.each(f)).unwrap(), &-5); + } } From 97109aa51b46215b47a12b9e596ca61b9ed801c9 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Wed, 1 May 2013 03:27:14 +0900 Subject: [PATCH 064/215] Remove mach_sty --- src/librustc/middle/ty.rs | 10 ---------- src/librustc/middle/typeck/infer/combine.rs | 12 ++---------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c7fb1e94adf4c..df507f012d626 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1253,16 +1253,6 @@ pub fn mk_opaque_closure_ptr(cx: ctxt, sigil: ast::Sigil) -> t { pub fn mk_opaque_box(cx: ctxt) -> t { mk_t(cx, ty_opaque_box) } -// Converts s to its machine type equivalent -pub fn mach_sty(cfg: @session::config, t: t) -> sty { - match get(t).sty { - ty_int(ast::ty_i) => ty_int(cfg.int_type), - ty_uint(ast::ty_u) => ty_uint(cfg.uint_type), - ty_float(ast::ty_f) => ty_float(cfg.float_type), - ref s => (/*bad*/copy *s) - } -} - pub fn walk_ty(ty: t, f: &fn(t)) { maybe_walk_ty(ty, |t| { f(t); true }); } diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index e4db423c2e35c..de3ffcd63ab7c 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -480,6 +480,8 @@ pub fn super_tys( unify_float_variable(self, !self.a_is_expected(), v_id, v) } + (ty::ty_nil, _) | + (ty::ty_bool, _) | (ty::ty_int(_), _) | (ty::ty_uint(_), _) | (ty::ty_float(_), _) => { @@ -490,16 +492,6 @@ pub fn super_tys( } } - (ty::ty_nil, _) | - (ty::ty_bool, _) => { - let cfg = tcx.sess.targ_cfg; - if ty::mach_sty(cfg, a) == ty::mach_sty(cfg, b) { - Ok(a) - } else { - Err(ty::terr_sorts(expected_found(self, a, b))) - } - } - (ty::ty_param(ref a_p), ty::ty_param(ref b_p)) if a_p.idx == b_p.idx => { Ok(a) } From 8408012ca4ed6e8e0aa2aa85e24eb53b4b17308d Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Tue, 30 Apr 2013 11:36:22 -0700 Subject: [PATCH 065/215] The null case of a nullable-poiner enum might not be nullary. Cases like `Either<@int,()>` have a null case with at most one value but a nonzero number of fields; if we misreport this, then bad things can happen inside of, for example, pattern matching. Closes #6117. --- src/librustc/middle/trans/adt.rs | 4 ++-- src/test/run-pass/issue-6117.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/issue-6117.rs diff --git a/src/librustc/middle/trans/adt.rs b/src/librustc/middle/trans/adt.rs index b3e24fcc93951..0ee2a2c4cb149 100644 --- a/src/librustc/middle/trans/adt.rs +++ b/src/librustc/middle/trans/adt.rs @@ -409,8 +409,8 @@ pub fn num_args(r: &Repr, discr: int) -> uint { st.fields.len() - (if dtor { 1 } else { 0 }) } General(ref cases) => cases[discr as uint].fields.len() - 1, - NullablePointer{ nonnull: ref nonnull, nndiscr, _ } => { - if discr == nndiscr { nonnull.fields.len() } else { 0 } + NullablePointer{ nonnull: ref nonnull, nndiscr, nullfields: ref nullfields, _ } => { + if discr == nndiscr { nonnull.fields.len() } else { nullfields.len() } } } } diff --git a/src/test/run-pass/issue-6117.rs b/src/test/run-pass/issue-6117.rs new file mode 100644 index 0000000000000..73e9391f01683 --- /dev/null +++ b/src/test/run-pass/issue-6117.rs @@ -0,0 +1,16 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + match Left(@17) { + Right(()) => {} + _ => {} + } +} From 41d06dbd28a9c26ecf114c020c6d855252fe323c Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Tue, 30 Apr 2013 12:05:06 -0700 Subject: [PATCH 066/215] Reverse accidental src/llvm reversion in 876483dcf, and add test. The test is reduced from a doc test, but making it separate ensures that (1) unrelated changes to the docs won't leave this case uncovered, and (2) the nature of any future failures will be more obvious to whoever sees the tree on fire as a result. --- src/llvm | 2 +- .../enum-nullable-simplifycfg-misopt.rs | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/test/run-pass/enum-nullable-simplifycfg-misopt.rs diff --git a/src/llvm b/src/llvm index 56dd407f4f97a..2e9f0d21fe321 160000 --- a/src/llvm +++ b/src/llvm @@ -1 +1 @@ -Subproject commit 56dd407f4f97a01b8df6554c569170d2fc276fcb +Subproject commit 2e9f0d21fe321849a4759a01fc28eae82ef196d6 diff --git a/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs b/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs new file mode 100644 index 0000000000000..b5cf15f3b3863 --- /dev/null +++ b/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs @@ -0,0 +1,24 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/*! + * This is a regression test for a bug in LLVM, fixed in upstream r179587, + * where the switch instructions generated for destructuring enums + * represented with nullable pointers could be misoptimized in some cases. + */ + +enum List { Nil, Cons(X, @List) } +pub fn main() { + match Cons(10, @Nil) { + Cons(10, _) => {} + Nil => {} + _ => fail!() + } +} From 4701716b56a22e209223110ce7d4aa9be45839da Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Tue, 30 Apr 2013 12:07:10 -0700 Subject: [PATCH 067/215] Revert "doc: XFAIL mysterious failure on bots" This reverts commit 2c6dae081b72d33a2c51b5f46436e6350bb3682f. --- doc/rust.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/rust.md b/doc/rust.md index 136c7ee9da3f2..9f81b38009fe8 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -2393,7 +2393,7 @@ variables in the arm's block, and control enters the block. An example of an `match` expression: -~~~~ {.xfail-test} +~~~~ # fn process_pair(a: int, b: int) { } # fn process_ten() { } From dc21daeeb88c20b6431e70fe4ef5cc416af8410d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 30 Apr 2013 16:34:22 -0400 Subject: [PATCH 068/215] borrowck: fix critical bug prevent us from ever using write guards :) --- src/librustc/middle/borrowck/check_loans.rs | 3 +++ .../middle/borrowck/gather_loans/lifetime.rs | 1 + .../middle/borrowck/gather_loans/mod.rs | 4 ++-- src/test/run-pass/too-much-recursion.rs | 22 ------------------- 4 files changed, 6 insertions(+), 24 deletions(-) delete mode 100644 src/test/run-pass/too-much-recursion.rs diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 9330395c061a7..70da9c9380559 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -357,6 +357,8 @@ pub impl<'self> CheckLoanCtxt<'self> { //! Safety checks related to writes to aliasable, mutable locations let guarantor = cmt.guarantor(); + debug!("check_for_aliasable_mutable_writes(cmt=%s, guarantor=%s)", + cmt.repr(self.tcx()), guarantor.repr(self.tcx())); match guarantor.cat { mc::cat_deref(b, _, mc::region_ptr(m_mutbl, _)) => { // Statically prohibit writes to `&mut` when aliasable @@ -379,6 +381,7 @@ pub impl<'self> CheckLoanCtxt<'self> { id: base.id, derefs: deref_count }; + debug!("Inserting write guard at %?", key); self.bccx.write_guard_map.insert(key); } diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 4d267b7dc471c..fdfb26c0d0835 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -90,6 +90,7 @@ impl GuaranteeLifetimeContext { // See rule Freeze-Imm-Managed-Ptr-2 in doc.rs let omit_root = ( + ptr_mutbl == m_imm && self.bccx.is_subregion_of(self.loan_region, base_scope) && base.mutbl.is_immutable() && !self.is_moved(base) diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 1bc3b70ac3842..8a986a22d4c48 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -148,7 +148,7 @@ fn gather_loans_in_expr(ex: @ast::expr, // If this expression is borrowed, have to ensure it remains valid: { - let mut this = &mut *self; // FIXME(#5074) + let this = &mut *self; // FIXME(#5074) if !this.ignore_adjustments.contains(&ex.id) { for tcx.adjustments.find(&ex.id).each |&adjustments| { this.guarantee_adjustments(ex, *adjustments); @@ -283,7 +283,7 @@ pub impl GatherLoanCtxt { let mcx = &mc::mem_categorization_ctxt { tcx: self.tcx(), method_map: self.bccx.method_map}; - let mut cmt = mcx.cat_expr_autoderefd(expr, autoderefs); + let cmt = mcx.cat_expr_autoderefd(expr, autoderefs); debug!("after autoderef, cmt=%s", cmt.repr(self.tcx())); match *autoref { diff --git a/src/test/run-pass/too-much-recursion.rs b/src/test/run-pass/too-much-recursion.rs deleted file mode 100644 index adccc786926dc..0000000000000 --- a/src/test/run-pass/too-much-recursion.rs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-win32 -// error-pattern:ran out of stack - -// Test that the task fails after hitting the recursion limit, but -// that it doesn't bring down the whole proc - -pub fn main() { - do task::spawn_unlinked { - fn f() { f() }; - f(); - }; -} From f236b850c0dc4c1b925e33d1173f359605801307 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 30 Apr 2013 16:35:01 -0400 Subject: [PATCH 069/215] remove some unused mut decls --- src/libcore/num/num.rs | 2 +- src/librustc/middle/resolve.rs | 4 ++-- src/librustc/middle/trans/base.rs | 2 +- src/librustc/middle/trans/callee.rs | 2 +- src/librustc/middle/trans/expr.rs | 2 -- src/librustc/middle/typeck/check/method.rs | 4 ++-- src/librustc/middle/typeck/check/mod.rs | 4 ++-- src/librustc/middle/typeck/check/regionck.rs | 2 +- src/test/run-fail/borrowck-wg-fail-2.rs | 3 ++- src/test/run-fail/borrowck-wg-fail-3.rs | 3 ++- src/test/run-fail/borrowck-wg-fail.rs | 6 ++---- 11 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index de7597fa821d6..96fed51309ee3 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -385,7 +385,7 @@ pub fn pow_with_uint+Mul>( } #[cfg(test)] -fn test_num(ten: T, two: T) { +pub fn test_num(ten: T, two: T) { assert_eq!(ten.add(&two), cast(12)); assert_eq!(ten.sub(&two), cast(8)); assert_eq!(ten.mul(&two), cast(20)); diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index ffc9d1488cf13..ff46abaf7128c 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -5267,7 +5267,7 @@ pub impl Resolver { debug!("Import resolutions:"); for module_.import_resolutions.each |name, import_resolution| { - let mut value_repr; + let value_repr; match import_resolution.target_for_namespace(ValueNS) { None => { value_repr = ~""; } Some(_) => { @@ -5276,7 +5276,7 @@ pub impl Resolver { } } - let mut type_repr; + let type_repr; match import_resolution.target_for_namespace(TypeNS) { None => { type_repr = ~""; } Some(_) => { diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 7be6bdb654e1f..1785feda7790c 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2366,7 +2366,7 @@ pub fn create_entry_wrapper(ccx: @CrateContext, // Call main. let lloutputarg = C_null(T_ptr(T_i8())); let llenvarg = unsafe { llvm::LLVMGetParam(llfdecl, 1 as c_uint) }; - let mut args = ~[lloutputarg, llenvarg]; + let args = ~[lloutputarg, llenvarg]; let llresult = Call(bcx, main_llfn, args); Store(bcx, llresult, fcx.llretptr.get()); diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index af00257fe1603..c4c6133b405c0 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -722,7 +722,7 @@ pub fn trans_arg_expr(bcx: block, } } }; - let mut arg_datum = arg_datumblock.datum; + let arg_datum = arg_datumblock.datum; let bcx = arg_datumblock.bcx; debug!(" arg datum: %s", arg_datum.to_str(bcx.ccx())); diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index ac6fa7a5a1c4f..fa6f7802e7d50 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -563,7 +563,6 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block { fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, dest: Dest) -> block { - let mut bcx = bcx; let _icx = bcx.insn_ctxt("trans_rvalue_dps_unadjusted"); let tcx = bcx.tcx(); @@ -1408,7 +1407,6 @@ fn trans_eager_binop(bcx: block, lhs_datum: &Datum, rhs_datum: &Datum) -> DatumBlock { - let mut bcx = bcx; let _icx = bcx.insn_ctxt("trans_eager_binop"); let lhs = lhs_datum.to_appropriate_llval(bcx); diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index de6530fb464c5..9f9132fa94665 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -120,7 +120,7 @@ pub fn lookup( expr: @ast::expr, // The expression `a.b(...)`. self_expr: @ast::expr, // The expression `a`. callee_id: node_id, /* Where to store `a.b`'s type, - * also the scope of the call */ + * also the scope of the call */ m_name: ast::ident, // The ident `b`. self_ty: ty::t, // The type of `a`. supplied_tps: &[ty::t], // The list of types X, Y, ... . @@ -128,7 +128,7 @@ pub fn lookup( check_traits: CheckTraitsFlag, // Whether we check traits only. autoderef_receiver: AutoderefReceiverFlag) -> Option { - let mut impl_dups = @mut HashSet::new(); + let impl_dups = @mut HashSet::new(); let lcx = LookupContext { fcx: fcx, expr: expr, diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index fb58df3d55c68..70282fdc57cfe 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1684,7 +1684,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, }; // construct the function type - let mut fn_ty = astconv::ty_of_closure(fcx, + let fn_ty = astconv::ty_of_closure(fcx, fcx, sigil, purity, @@ -1695,7 +1695,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, &opt_vec::Empty, expr.span); - let mut fty_sig; + let fty_sig; let fty = if error_happened { fty_sig = FnSig { bound_lifetime_names: opt_vec::Empty, diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index be513cbb0f307..fd19738b32110 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -871,7 +871,7 @@ pub mod guarantor { let tcx = rcx.tcx(); debug!("guarantor::for_by_ref(expr=%s, callee_scope=%?)", expr.repr(tcx), callee_scope); - let mut expr_cat = categorize(rcx, expr); + let expr_cat = categorize(rcx, expr); debug!("guarantor::for_by_ref(expr=%?, callee_scope=%?) category=%?", expr.id, callee_scope, expr_cat); let minimum_lifetime = ty::re_scope(callee_scope); diff --git a/src/test/run-fail/borrowck-wg-fail-2.rs b/src/test/run-fail/borrowck-wg-fail-2.rs index 126135772ade0..121ec9c79216f 100644 --- a/src/test/run-fail/borrowck-wg-fail-2.rs +++ b/src/test/run-fail/borrowck-wg-fail-2.rs @@ -7,5 +7,6 @@ struct S { fn main() { let x = @mut S { x: 3 }; let y: &S = x; - x.x = 5; + let z = x; + z.x = 5; } diff --git a/src/test/run-fail/borrowck-wg-fail-3.rs b/src/test/run-fail/borrowck-wg-fail-3.rs index ad4c794212121..2b95cf3fe5fa9 100644 --- a/src/test/run-fail/borrowck-wg-fail-3.rs +++ b/src/test/run-fail/borrowck-wg-fail-3.rs @@ -3,6 +3,7 @@ fn main() { let x = @mut 3; let y: &mut int = x; - *x = 5; + let z = x; + *z = 5; } diff --git a/src/test/run-fail/borrowck-wg-fail.rs b/src/test/run-fail/borrowck-wg-fail.rs index d393832c6e862..fd2d36b895ada 100644 --- a/src/test/run-fail/borrowck-wg-fail.rs +++ b/src/test/run-fail/borrowck-wg-fail.rs @@ -1,9 +1,7 @@ // error-pattern:borrowed -fn f(x: &int, y: @mut int) { - unsafe { - *y = 2; - } +fn f(_x: &int, y: @mut int) { + *y = 2; } fn main() { From 0b377e53a1f1475e3b13427a1af8432924a0a586 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 30 Apr 2013 17:09:11 -0400 Subject: [PATCH 070/215] clear *everything* from the tmp directory The .tmp files were missed before. I don't think there's a need to use *.ext instead of just *. --- mk/clean.mk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mk/clean.mk b/mk/clean.mk index 30897eea45793..660793b1c347e 100644 --- a/mk/clean.mk +++ b/mk/clean.mk @@ -48,7 +48,7 @@ clean-misc: $(Q)rm -f $(RUSTLLVM_LIB_OBJS) $(RUSTLLVM_OBJS_OBJS) $(RUSTLLVM_DEF) $(Q)rm -Rf $(DOCS) $(Q)rm -Rf $(GENERATED) - $(Q)rm -f tmp/*.log tmp/*.rc tmp/*.rs tmp/*.ok + $(Q)rm -f tmp/* $(Q)rm -Rf rust-stage0-*.tar.bz2 $(PKG_NAME)-*.tar.gz dist $(Q)rm -Rf $(foreach ext, \ html aux cp fn ky log pdf pg toc tp vr cps, \ From 4493cf49cdaeb7aea974b9155a678fb8c9e3e390 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Tue, 30 Apr 2013 16:17:19 -0700 Subject: [PATCH 071/215] Fix error messages harder --- src/test/compile-fail/alt-vec-mismatch-2.rs | 2 +- src/test/compile-fail/alt-vec-mismatch.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/compile-fail/alt-vec-mismatch-2.rs b/src/test/compile-fail/alt-vec-mismatch-2.rs index bef18cc666ae6..6ea0300cf1e7d 100644 --- a/src/test/compile-fail/alt-vec-mismatch-2.rs +++ b/src/test/compile-fail/alt-vec-mismatch-2.rs @@ -1,5 +1,5 @@ fn main() { match () { - [()] => { } //~ ERROR mismatched type: expected `()` but found a vector pattern + [()] => { } //~ ERROR mismatched types: expected `()` but found a vector pattern } } diff --git a/src/test/compile-fail/alt-vec-mismatch.rs b/src/test/compile-fail/alt-vec-mismatch.rs index 1f6822cfd2ce5..85ed8761ee935 100644 --- a/src/test/compile-fail/alt-vec-mismatch.rs +++ b/src/test/compile-fail/alt-vec-mismatch.rs @@ -1,6 +1,6 @@ fn main() { match ~"foo" { - ['f', 'o', .._] => { } //~ ERROR mismatched type: expected `~str` but found a vector pattern + ['f', 'o', .._] => { } //~ ERROR mismatched types: expected `~str` but found a vector pattern _ => { } } } From dd310d6c3b635628f584f3266b3ab31888fd0e95 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 14:48:59 -0700 Subject: [PATCH 072/215] Got test cases to pass, after some major surgery --- src/test/auxiliary/issue2378a.rs | 11 +++++++---- src/test/auxiliary/issue2378b.rs | 14 ++++++++------ src/test/run-pass/issue2378c.rs | 12 ++++++------ 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/test/auxiliary/issue2378a.rs b/src/test/auxiliary/issue2378a.rs index ead338c4bc803..1873aca5909ca 100644 --- a/src/test/auxiliary/issue2378a.rs +++ b/src/test/auxiliary/issue2378a.rs @@ -8,13 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#[link (name = "issue2378a")]; +#[crate_type = "lib"]; + enum maybe { just(T), nothing } -impl copy> for maybe for methods T { +impl Index for maybe { + fn index(&self, idx: &uint) -> T { match self { - just(t) { t } - nothing { fail!(); } + &just(ref t) => copy *t, + ¬hing => { fail!(); } } } } diff --git a/src/test/auxiliary/issue2378b.rs b/src/test/auxiliary/issue2378b.rs index 9037417ef6224..20f07a5cb546b 100644 --- a/src/test/auxiliary/issue2378b.rs +++ b/src/test/auxiliary/issue2378b.rs @@ -8,15 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use issue2378a; +#[link (name = "issue2378b")]; +#[crate_type = "lib"]; + +extern mod issue2378a; use issue2378a::maybe; -use issue2378a::methods; -type two_maybes = {a: maybe, b: maybe}; +struct two_maybes {a: maybe, b: maybe} -impl copy> for two_maybes for methods (T, T) { - (self.a[idx], self.b[idx]) +impl Index for two_maybes { + fn index(&self, idx: &uint) -> (T, T) { + (self.a[*idx], self.b[*idx]) } } diff --git a/src/test/run-pass/issue2378c.rs b/src/test/run-pass/issue2378c.rs index ea8c47a3eb91a..98e60c56476d8 100644 --- a/src/test/run-pass/issue2378c.rs +++ b/src/test/run-pass/issue2378c.rs @@ -8,17 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test -- #2378 unfixed // aux-build:issue2378a.rs // aux-build:issue2378b.rs +// xfail-fast - check-fast doesn't understand aux-build -use issue2378a; -use issue2378b; +extern mod issue2378a; +extern mod issue2378b; -use issue2378a::{just, methods}; -use issue2378b::{methods}; +use issue2378a::{just}; +use issue2378b::{two_maybes}; pub fn main() { - let x = {a: just(3), b: just(5)}; + let x = two_maybes{a: just(3), b: just(5)}; assert!(x[0u] == (3, 5)); } From 325263fe221647b7d6ef6c3cc1efd0d1e7cf3a21 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 15:05:39 -0700 Subject: [PATCH 073/215] this test still doesn't pass, but at least it parses... --- src/test/run-pass/mlist-cycle.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/test/run-pass/mlist-cycle.rs b/src/test/run-pass/mlist-cycle.rs index e886c941a4b6a..a67f1574f64af 100644 --- a/src/test/run-pass/mlist-cycle.rs +++ b/src/test/run-pass/mlist-cycle.rs @@ -10,16 +10,18 @@ // xfail-test // -*- rust -*- -extern mod std; +extern mod core; +use core::gc; +use core::gc::rustrt; -type cell = {c: @list}; +struct cell {c: @list} enum list { link(@mut cell), nil, } pub fn main() { - let first: @cell = @mut {c: @nil()}; - let second: @cell = @mut {c: @link(first)}; + let first: @cell = @mut cell{c: @nil()}; + let second: @cell = @mut cell{c: @link(first)}; first._0 = @link(second); - sys.rustrt.gc(); - let third: @cell = @mut {c: @nil()}; + rustrt::gc(); + let third: @cell = @mut cell{c: @nil()}; } From 7e89a514a5ce9aa427ca350a4ba62e63f3c89f95 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 15:13:24 -0700 Subject: [PATCH 074/215] This test case now parses I've done a slapdash job of fixing up the syntax; it didn't pass before, and it doesn't pass now, but at least it parses... --- src/test/run-pass/preempt.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/test/run-pass/preempt.rs b/src/test/run-pass/preempt.rs index e0434c14048a0..3d3e178f064ae 100644 --- a/src/test/run-pass/preempt.rs +++ b/src/test/run-pass/preempt.rs @@ -13,7 +13,7 @@ fn starve_main(alive: chan) { debug!("signalling main"); - alive <| 1; + alive.recv(1); debug!("starving main"); let i: int = 0; loop { i += 1; } @@ -22,10 +22,12 @@ fn starve_main(alive: chan) { pub fn main() { let alive: port = port(); debug!("main started"); - let s: task = spawn starve_main(chan(alive)); + let s: task = do task::spawn { + starve_main(chan(alive)); + }; let i: int; debug!("main waiting for alive signal"); - alive |> i; + alive.send(i); debug!("main got alive signal"); while i < 50 { debug!("main iterated"); i += 1; } debug!("main completed"); From add60bb081b9c23c8606a22b078f0885d5ab169c Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 15:20:36 -0700 Subject: [PATCH 075/215] Test now passes --- src/test/run-pass/regions-fn-subtyping-2.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/test/run-pass/regions-fn-subtyping-2.rs b/src/test/run-pass/regions-fn-subtyping-2.rs index a995b3d969352..a660b9c9ee2d5 100644 --- a/src/test/run-pass/regions-fn-subtyping-2.rs +++ b/src/test/run-pass/regions-fn-subtyping-2.rs @@ -8,20 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - // Issue #2263. // Here, `f` is a function that takes a pointer `x` and a function // `g`, where `g` requires its argument `y` to be in the same region // that `x` is in. -fn has_same_region(f: &fn(x: &a.int, g: &fn(y: &a.int))) { +fn has_same_region(f: &fn<'a>(x: &'a int, g: &fn(y: &'a int))) { // `f` should be the type that `wants_same_region` wants, but // right now the compiler complains that it isn't. wants_same_region(f); } -fn wants_same_region(_f: &fn(x: &b.int, g: &fn(y: &b.int))) { +fn wants_same_region(_f: &fn<'b>(x: &'b int, g: &fn(y: &'b int))) { } pub fn main() { From cc4e0186ac005768ebede5b6b858b223c33e4de3 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 15:49:28 -0700 Subject: [PATCH 076/215] added test case for issue 5927 --- src/test/run-fail/issue-5927.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/test/run-fail/issue-5927.rs diff --git a/src/test/run-fail/issue-5927.rs b/src/test/run-fail/issue-5927.rs new file mode 100644 index 0000000000000..f302d706c15d7 --- /dev/null +++ b/src/test/run-fail/issue-5927.rs @@ -0,0 +1,20 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + + +// error-pattern:cant-use-x-as-pattern-mumble + +fn main() { + let z = match 3 { + x() => x + }; + assert_eq!(z,3); +} From d6bb587c12da816b2872db1c1f9154a58fc91006 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 16:44:36 -0700 Subject: [PATCH 077/215] with syntax fixes, this test case now appears to pass --- src/test/run-pass/tag-align-dyn-u64.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/test/run-pass/tag-align-dyn-u64.rs b/src/test/run-pass/tag-align-dyn-u64.rs index a9c59de49eeaa..0fdf4e019a775 100644 --- a/src/test/run-pass/tag-align-dyn-u64.rs +++ b/src/test/run-pass/tag-align-dyn-u64.rs @@ -8,27 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - -tag a_tag { - a_tag(A); +enum a_tag { + a_tag(A) } -type t_rec = { +struct t_rec { c8: u8, t: a_tag -}; +} fn mk_rec() -> t_rec { - return { c8:0u8, t:a_tag(0u64) }; + return t_rec { c8:0u8, t:a_tag(0u64) }; } -fn is_8_byte_aligned(&&u: a_tag) -> bool { +fn is_8_byte_aligned(u: &a_tag) -> bool { let p = ptr::to_unsafe_ptr(u) as uint; return (p & 7u) == 0u; } pub fn main() { let x = mk_rec(); - assert!(is_8_byte_aligned(x.t)); + assert!(is_8_byte_aligned(&x.t)); } From 178305ffecf4e183a425028ba53b39a4f4dd1121 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 16:48:33 -0700 Subject: [PATCH 078/215] fixed up issue-2185, but now it has a trait failure --- src/test/run-pass/issue-2185.rs | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/test/run-pass/issue-2185.rs b/src/test/run-pass/issue-2185.rs index ac680d3d12e41..350dea4415dd0 100644 --- a/src/test/run-pass/issue-2185.rs +++ b/src/test/run-pass/issue-2185.rs @@ -8,22 +8,45 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test FIXME #2263 +// does the second one subsume the first? +// xfail-test // xfail-fast + +// notes on this test case: +// On Thu, Apr 18, 2013 at 6:30 PM, John Clements wrote: +// the "issue-2185.rs" test was xfailed with a ref to #2263. Issue #2263 is now fixed, so I tried it again, and after adding some &self parameters, I got this error: +// +// Running /usr/local/bin/rustc: +// issue-2185.rs:24:0: 26:1 error: conflicting implementations for a trait +// issue-2185.rs:24 impl iterable for @fn(&fn(uint)) { +// issue-2185.rs:25 fn iter(&self, blk: &fn(v: uint)) { self( |i| blk(i) ) } +// issue-2185.rs:26 } +// issue-2185.rs:20:0: 22:1 note: note conflicting implementation here +// issue-2185.rs:20 impl iterable for @fn(&fn(A)) { +// issue-2185.rs:21 fn iter(&self, blk: &fn(A)) { self(blk); } +// issue-2185.rs:22 } +// +// … so it looks like it's just not possible to implement both the generic iterable and iterable for the type iterable. Is it okay if I just remove this test? +// +// but Niko responded: +// think it's fine to remove this test, just because it's old and cruft and not hard to reproduce. *However* it should eventually be possible to implement the same interface for the same type multiple times with different type parameters, it's just that our current trait implementation has accidental limitations. + +// so I'm leaving it in. + // This test had to do with an outdated version of the iterable trait. // However, the condition it was testing seemed complex enough to // warrant still having a test, so I inlined the old definitions. trait iterable { - fn iter(blk: &fn(A)); + fn iter(&self, blk: &fn(A)); } impl iterable for @fn(&fn(A)) { - fn iter(blk: &fn(A)) { self(blk); } + fn iter(&self, blk: &fn(A)) { self(blk); } } impl iterable for @fn(&fn(uint)) { - fn iter(blk: &fn(&&v: uint)) { self( |i| blk(i) ) } + fn iter(&self, blk: &fn(v: uint)) { self( |i| blk(i) ) } } fn filter>(self: IA, prd: @fn(A) -> bool, blk: &fn(A)) { From 3a5361aec990ff2b07cabf9d9fbfac67f056d97f Mon Sep 17 00:00:00 2001 From: John Clements Date: Tue, 30 Apr 2013 10:39:20 -0700 Subject: [PATCH 079/215] more commits on issue 2185 --- src/test/run-pass/issue-2185.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/run-pass/issue-2185.rs b/src/test/run-pass/issue-2185.rs index 350dea4415dd0..8a553784c5e2e 100644 --- a/src/test/run-pass/issue-2185.rs +++ b/src/test/run-pass/issue-2185.rs @@ -32,6 +32,7 @@ // think it's fine to remove this test, just because it's old and cruft and not hard to reproduce. *However* it should eventually be possible to implement the same interface for the same type multiple times with different type parameters, it's just that our current trait implementation has accidental limitations. // so I'm leaving it in. +// actually, it looks like this is related to bug #3429. I'll rename this bug. // This test had to do with an outdated version of the iterable trait. // However, the condition it was testing seemed complex enough to From 527f7716b76cf77f57915c663d88f72037e11af4 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 16:55:48 -0700 Subject: [PATCH 080/215] after syntax fixes, these tests appear to pass --- src/test/run-pass/tag-align-dyn-variants.rs | 64 ++++++++++----------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/src/test/run-pass/tag-align-dyn-variants.rs b/src/test/run-pass/tag-align-dyn-variants.rs index 4fc6410f8f3d0..96921f2a065c2 100644 --- a/src/test/run-pass/tag-align-dyn-variants.rs +++ b/src/test/run-pass/tag-align-dyn-variants.rs @@ -8,64 +8,62 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test - -tag a_tag { - varA(A); - varB(B); +enum a_tag { + varA(A), + varB(B) } -type t_rec = { +struct t_rec { chA: u8, tA: a_tag, chB: u8, tB: a_tag -}; +} -fn mk_rec(a: A, b: B) -> t_rec { - return { chA:0u8, tA:varA(a), chB:1u8, tB:varB(b) }; +fn mk_rec(a: A, b: B) -> t_rec { + return t_rec{ chA:0u8, tA:varA(a), chB:1u8, tB:varB(b) }; } -fn is_aligned(amnt: uint, &&u: A) -> bool { +fn is_aligned(amnt: uint, u: &A) -> bool { let p = ptr::to_unsafe_ptr(u) as uint; return (p & (amnt-1u)) == 0u; } -fn variant_data_is_aligned(amnt: uint, &&u: a_tag) -> bool { +fn variant_data_is_aligned(amnt: uint, u: &a_tag) -> bool { match u { - varA(a) { is_aligned(amnt, a) } - varB(b) { is_aligned(amnt, b) } + &varA(ref a) => is_aligned(amnt, a), + &varB(ref b) => is_aligned(amnt, b) } } pub fn main() { let x = mk_rec(22u64, 23u64); - assert!(is_aligned(8u, x.tA)); - assert!(variant_data_is_aligned(8u, x.tA)); - assert!(is_aligned(8u, x.tB)); - assert!(variant_data_is_aligned(8u, x.tB)); + assert!(is_aligned(8u, &x.tA)); + assert!(variant_data_is_aligned(8u, &x.tA)); + assert!(is_aligned(8u, &x.tB)); + assert!(variant_data_is_aligned(8u, &x.tB)); let x = mk_rec(22u64, 23u32); - assert!(is_aligned(8u, x.tA)); - assert!(variant_data_is_aligned(8u, x.tA)); - assert!(is_aligned(8u, x.tB)); - assert!(variant_data_is_aligned(4u, x.tB)); + assert!(is_aligned(8u, &x.tA)); + assert!(variant_data_is_aligned(8u, &x.tA)); + assert!(is_aligned(8u, &x.tB)); + assert!(variant_data_is_aligned(4u, &x.tB)); let x = mk_rec(22u32, 23u64); - assert!(is_aligned(8u, x.tA)); - assert!(variant_data_is_aligned(4u, x.tA)); - assert!(is_aligned(8u, x.tB)); - assert!(variant_data_is_aligned(8u, x.tB)); + assert!(is_aligned(8u, &x.tA)); + assert!(variant_data_is_aligned(4u, &x.tA)); + assert!(is_aligned(8u, &x.tB)); + assert!(variant_data_is_aligned(8u, &x.tB)); let x = mk_rec(22u32, 23u32); - assert!(is_aligned(4u, x.tA)); - assert!(variant_data_is_aligned(4u, x.tA)); - assert!(is_aligned(4u, x.tB)); - assert!(variant_data_is_aligned(4u, x.tB)); + assert!(is_aligned(4u, &x.tA)); + assert!(variant_data_is_aligned(4u, &x.tA)); + assert!(is_aligned(4u, &x.tB)); + assert!(variant_data_is_aligned(4u, &x.tB)); let x = mk_rec(22f64, 23f64); - assert!(is_aligned(8u, x.tA)); - assert!(variant_data_is_aligned(8u, x.tA)); - assert!(is_aligned(8u, x.tB)); - assert!(variant_data_is_aligned(8u, x.tB)); + assert!(is_aligned(8u, &x.tA)); + assert!(variant_data_is_aligned(8u, &x.tA)); + assert!(is_aligned(8u, &x.tB)); + assert!(variant_data_is_aligned(8u, &x.tB)); } From 3931ce448e0329672583d3210df714cca5176f02 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 17:08:23 -0700 Subject: [PATCH 081/215] fixed the test case, hope it's still testing something --- src/test/run-pass/tag-align-shape.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/test/run-pass/tag-align-shape.rs b/src/test/run-pass/tag-align-shape.rs index 052bacad7ce19..43a793a34c89d 100644 --- a/src/test/run-pass/tag-align-shape.rs +++ b/src/test/run-pass/tag-align-shape.rs @@ -8,22 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test -// -// See issue #1535 - -tag a_tag { - a_tag(u64); +enum a_tag { + a_tag(u64) } -type t_rec = { +struct t_rec { c8: u8, t: a_tag -}; +} pub fn main() { - let x = {c8: 22u8, t: a_tag(44u64)}; + let x = t_rec {c8: 22u8, t: a_tag(44u64)}; let y = fmt!("%?", x); debug!("y = %s", y); - assert!(y == "(22, a_tag(44))"); + assert_eq!(y, ~"{c8: 22, t: a_tag(44)}"); } From d1921fb3caa131c83673020a377e1d0cd245b1ea Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 17:10:26 -0700 Subject: [PATCH 082/215] fixed this test case too --- src/test/run-pass/tag-align-u64.rs | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/test/run-pass/tag-align-u64.rs b/src/test/run-pass/tag-align-u64.rs index fd96d7d0242c3..56d384e5fdb76 100644 --- a/src/test/run-pass/tag-align-u64.rs +++ b/src/test/run-pass/tag-align-u64.rs @@ -8,27 +8,26 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test -tag a_tag { - a_tag(u64); +enum a_tag { + a_tag(u64) } -type t_rec = { +struct t_rec { c8: u8, t: a_tag -}; +} fn mk_rec() -> t_rec { - return { c8:0u8, t:a_tag(0u64) }; + return t_rec { c8:0u8, t:a_tag(0u64) }; } -fn is_8_byte_aligned(&&u: a_tag) -> bool { +fn is_8_byte_aligned(u: &a_tag) -> bool { let p = ptr::to_unsafe_ptr(u) as u64; return (p & 7u64) == 0u64; } pub fn main() { let x = mk_rec(); - assert!(is_8_byte_aligned(x.t)); + assert!(is_8_byte_aligned(&x.t)); } From 89bb02adf9f3ec55340b775a3b1f75c25478ce73 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 17:20:28 -0700 Subject: [PATCH 083/215] typestate is not planned for upcoming versions of rust.... --- src/test/run-pass/tstate-loop-break.rs | 27 -------------------------- 1 file changed, 27 deletions(-) delete mode 100644 src/test/run-pass/tstate-loop-break.rs diff --git a/src/test/run-pass/tstate-loop-break.rs b/src/test/run-pass/tstate-loop-break.rs deleted file mode 100644 index 4228f72b7caa4..0000000000000 --- a/src/test/run-pass/tstate-loop-break.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// xfail-test - -fn is_even(i: int) -> bool { (i%2) == 0 } -fn even(i: int) : is_even(i) -> int { i } - -fn test() { - let v = 4; - loop { - check is_even(v); - break; - } - even(v); -} - -pub fn main() { - test(); -} From c75b7630bcc45bf9f2c7f6831e46c84b0c8f024f Mon Sep 17 00:00:00 2001 From: John Clements Date: Tue, 30 Apr 2013 10:40:08 -0700 Subject: [PATCH 084/215] renamed issue-2185 to issue-3429 --- src/test/run-pass/{issue-1895.rs => issue-3429.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/run-pass/{issue-1895.rs => issue-3429.rs} (100%) diff --git a/src/test/run-pass/issue-1895.rs b/src/test/run-pass/issue-3429.rs similarity index 100% rename from src/test/run-pass/issue-1895.rs rename to src/test/run-pass/issue-3429.rs From fc661079a479f0aff6add4478c3afb8c2226b333 Mon Sep 17 00:00:00 2001 From: John Clements Date: Thu, 18 Apr 2013 17:28:22 -0700 Subject: [PATCH 085/215] fixed up syntax --- src/test/run-pass/type-sizes.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/test/run-pass/type-sizes.rs b/src/test/run-pass/type-sizes.rs index bc2ca20d642d9..134f1e4098f07 100644 --- a/src/test/run-pass/type-sizes.rs +++ b/src/test/run-pass/type-sizes.rs @@ -8,9 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test -use sys::rustrt::size_of; -extern mod std; +extern mod core; +use core::sys::size_of; + +struct t {a: u8, b: i8} +struct u {a: u8, b: i8, c: u8} +struct v {a: u8, b: i8, c: v2, d: u32} +struct v2 {u: char, v: u8} +struct w {a: int, b: ()} +struct x {a: int, b: (), c: ()} +struct y {x: int} pub fn main() { assert!((size_of::() == 1 as uint)); @@ -18,14 +25,14 @@ pub fn main() { assert!((size_of::() == 4 as uint)); assert!((size_of::() == 1 as uint)); assert!((size_of::() == 4 as uint)); - assert!((size_of::<{a: u8, b: i8}>() == 2 as uint)); - assert!((size_of::<{a: u8, b: i8, c: u8}>() == 3 as uint)); + assert!((size_of::() == 2 as uint)); + assert!((size_of::() == 3 as uint)); // Alignment causes padding before the char and the u32. - assert!(size_of::<{a: u8, b: i8, c: {u: char, v: u8}, d: u32}>() == + assert!(size_of::() == 16 as uint); assert!((size_of::() == size_of::())); - assert!((size_of::<{a: int, b: ()}>() == size_of::())); - assert!((size_of::<{a: int, b: (), c: ()}>() == size_of::())); - assert!((size_of::() == size_of::<{x: int}>())); + assert!((size_of::() == size_of::())); + assert!((size_of::() == size_of::())); + assert!((size_of::() == size_of::())); } From ab1d8ead91ac23e07f4ba9a186e0ae7ddbcd2515 Mon Sep 17 00:00:00 2001 From: John Clements Date: Tue, 30 Apr 2013 11:58:55 -0700 Subject: [PATCH 086/215] fixed pattern, moved test to compile-fail --- src/test/{run-fail => compile-fail}/issue-5927.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/test/{run-fail => compile-fail}/issue-5927.rs (92%) diff --git a/src/test/run-fail/issue-5927.rs b/src/test/compile-fail/issue-5927.rs similarity index 92% rename from src/test/run-fail/issue-5927.rs rename to src/test/compile-fail/issue-5927.rs index f302d706c15d7..a1b4ee7aa3445 100644 --- a/src/test/run-fail/issue-5927.rs +++ b/src/test/compile-fail/issue-5927.rs @@ -10,7 +10,7 @@ -// error-pattern:cant-use-x-as-pattern-mumble +// error-pattern:unresolved enum variant fn main() { let z = match 3 { From 9847428acf91e313c9c742fc38c69546bcfc8b26 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 30 Apr 2013 17:45:08 -0700 Subject: [PATCH 087/215] mk: Fix pdf build --- mk/docs.mk | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mk/docs.mk b/mk/docs.mk index 252f62cf87116..f49c75d6acb01 100644 --- a/mk/docs.mk +++ b/mk/docs.mk @@ -53,7 +53,7 @@ doc/rust.html: rust.md doc/version_info.html doc/rust.css doc/manual.css --include-before-body=doc/version_info.html \ --output=$@ -DOCS += doc/rust.pdf +DOCS += doc/rust.tex doc/rust.tex: rust.md doc/version.md @$(call E, pandoc: $@) $(Q)$(CFG_NODE) $(S)doc/prep.js $< | \ @@ -139,6 +139,7 @@ doc/tutorial-tasks.html: tutorial-tasks.md doc/version_info.html doc/rust.css $(info cfg: lacking luatex, disabling pdflatex) else +DOCS += doc/rust.pdf doc/rust.pdf: doc/rust.tex @$(call E, pdflatex: $@) $(Q)$(CFG_PDFLATEX) \ From 782e06e0e379768d03e35acae16e7ee1e1841633 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Tue, 30 Apr 2013 17:58:24 -0700 Subject: [PATCH 088/215] core/std: Fix race condition in os::mkdir_recursive tests Added a change_dir_locked function to os, and use it in the mkdir_recursive tests so that the tests don't clobber each other's directory changes. --- src/libcore/os.rs | 30 +++++++++++++++++++++++++ src/libstd/tempfile.rs | 50 ++++++++++++++++++++++++------------------ 2 files changed, 59 insertions(+), 21 deletions(-) diff --git a/src/libcore/os.rs b/src/libcore/os.rs index f1962eeaa23d0..0455dabb7f013 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -818,6 +818,36 @@ pub fn change_dir(p: &Path) -> bool { } } +/// Changes the current working directory to the specified +/// path while acquiring a global lock, then calls `action`. +/// If the change is successful, releases the lock and restores the +/// CWD to what it was before, returning true. +/// Returns false if the directory doesn't exist or if the directory change +/// is otherwise unsuccessful. +pub fn change_dir_locked(p: &Path, action: &fn()) -> bool { + use unstable::global::global_data_clone_create; + use unstable::{Exclusive, exclusive}; + + fn key(_: Exclusive<()>) { } + + let result = unsafe { + global_data_clone_create(key, || { + ~exclusive(()) + }) + }; + + do result.with_imm() |_| { + let old_dir = os::getcwd(); + if change_dir(p) { + action(); + change_dir(&old_dir) + } + else { + false + } + } +} + /// Copies a file from one location to another pub fn copy_file(from: &Path, to: &Path) -> bool { return do_copy_file(from, to); diff --git a/src/libstd/tempfile.rs b/src/libstd/tempfile.rs index eec91b6845444..6da74834b1a49 100644 --- a/src/libstd/tempfile.rs +++ b/src/libstd/tempfile.rs @@ -42,13 +42,18 @@ mod tests { use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use core::os; - let root = mkdtemp(&os::tmpdir(), "temp").expect("recursive_mkdir_rel"); - os::change_dir(&root); - let path = Path("frob"); - assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - assert!(os::path_is_dir(&path)); - assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - assert!(os::path_is_dir(&path)); + let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel"). + expect("recursive_mkdir_rel"); + assert!(do os::change_dir_locked(&root) { + let path = Path("frob"); + debug!("recursive_mkdir_rel: Making: %s in cwd %s [%?]", path.to_str(), + os::getcwd().to_str(), + os::path_exists(&path)); + assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); + assert!(os::path_is_dir(&path)); + assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); + assert!(os::path_is_dir(&path)); + }); } #[test] @@ -67,18 +72,21 @@ mod tests { use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; use core::os; - let root = mkdtemp(&os::tmpdir(), "temp").expect("recursive_mkdir_rel_2"); - os::change_dir(&root); - let path = Path("./frob/baz"); - debug!("...Making: %s in cwd %s", path.to_str(), os::getcwd().to_str()); - assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - assert!(os::path_is_dir(&path)); - assert!(os::path_is_dir(&path.pop())); - let path2 = Path("quux/blat"); - debug!("Making: %s in cwd %s", path2.to_str(), os::getcwd().to_str()); - assert!(os::mkdir_recursive(&path2, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); - assert!(os::path_is_dir(&path2)); - assert!(os::path_is_dir(&path2.pop())); + let root = mkdtemp(&os::tmpdir(), "recursive_mkdir_rel_2"). + expect("recursive_mkdir_rel_2"); + assert!(do os::change_dir_locked(&root) { + let path = Path("./frob/baz"); + debug!("recursive_mkdir_rel_2: Making: %s in cwd %s [%?]", path.to_str(), + os::getcwd().to_str(), os::path_exists(&path)); + assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); + assert!(os::path_is_dir(&path)); + assert!(os::path_is_dir(&path.pop())); + let path2 = Path("quux/blat"); + debug!("recursive_mkdir_rel_2: Making: %s in cwd %s", path2.to_str(), + os::getcwd().to_str()); + assert!(os::mkdir_recursive(&path2, (S_IRUSR | S_IWUSR | S_IXUSR) as i32)); + assert!(os::path_is_dir(&path2)); + assert!(os::path_is_dir(&path2.pop())); + }); } - -} \ No newline at end of file +} From ee26c7c433dbb8d41a2b65dbc89eb84acfc2d311 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Wed, 1 May 2013 15:40:05 +1000 Subject: [PATCH 089/215] Revert rename of Div to Quot --- doc/rust.md | 6 +- src/libcore/core.rc | 2 +- src/libcore/num/f32.rs | 9 +- src/libcore/num/f64.rs | 9 +- src/libcore/num/float.rs | 10 +-- src/libcore/num/int-template.rs | 123 +++++++++++++--------------- src/libcore/num/num.rs | 29 ++++--- src/libcore/num/strconv.rs | 16 ++-- src/libcore/num/uint-template.rs | 29 +++---- src/libcore/ops.rs | 6 -- src/libcore/prelude.rs | 2 +- src/librustc/middle/const_eval.rs | 10 +-- src/librustc/middle/lang_items.rs | 10 +-- src/librustc/middle/resolve.rs | 6 +- src/librustc/middle/trans/base.rs | 6 +- src/librustc/middle/trans/consts.rs | 2 +- src/librustc/middle/trans/expr.rs | 2 +- src/librustc/middle/ty.rs | 2 +- src/libstd/num/bigint.rs | 123 ++++++++++++++-------------- src/libstd/num/complex.rs | 6 +- src/libstd/num/rational.rs | 8 +- src/libsyntax/ast.rs | 2 +- src/libsyntax/ast_util.rs | 6 +- src/libsyntax/parse/parser.rs | 4 +- src/libsyntax/parse/token.rs | 2 +- src/test/compile-fail/eval-enum.rs | 2 +- src/test/run-fail/divide-by-zero.rs | 2 +- 27 files changed, 199 insertions(+), 235 deletions(-) diff --git a/doc/rust.md b/doc/rust.md index 9f81b38009fe8..e23613e149ce7 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -1467,8 +1467,8 @@ A complete list of the built-in language items follows: : Elements can be subtracted. `mul` : Elements can be multiplied. -`quot` - : Elements have a quotient operation. +`div` + : Elements have a division operation. `rem` : Elements have a remainder operation. `neg` @@ -1857,7 +1857,7 @@ The default meaning of the operators on standard types is given here. Calls the `mul` method on the `core::ops::Mul` trait. `/` : Quotient. - Calls the `quot` method on the `core::ops::Quot` trait. + Calls the `div` method on the `core::ops::Div` trait. `%` : Remainder. Calls the `rem` method on the `core::ops::Rem` trait. diff --git a/src/libcore/core.rc b/src/libcore/core.rc index f9a56f613d542..26398f3fe5236 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -78,7 +78,7 @@ pub use ops::{Drop}; #[cfg(stage0)] pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not}; #[cfg(not(stage0))] -pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not}; +pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Shl, Shr, Index}; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index e687f482fa98c..04ddd63a177e7 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -123,7 +123,7 @@ pub fn sub(x: f32, y: f32) -> f32 { return x - y; } pub fn mul(x: f32, y: f32) -> f32 { return x * y; } #[inline(always)] -pub fn quot(x: f32, y: f32) -> f32 { return x / y; } +pub fn div(x: f32, y: f32) -> f32 { return x / y; } #[inline(always)] pub fn rem(x: f32, y: f32) -> f32 { return x % y; } @@ -279,16 +279,11 @@ impl Mul for f32 { fn mul(&self, other: &f32) -> f32 { *self * *other } } -#[cfg(stage0,notest)] +#[cfg(notest)] impl Div for f32 { #[inline(always)] fn div(&self, other: &f32) -> f32 { *self / *other } } -#[cfg(not(stage0),notest)] -impl Quot for f32 { - #[inline(always)] - fn quot(&self, other: &f32) -> f32 { *self / *other } -} #[cfg(stage0,notest)] impl Modulo for f32 { diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index d00e6ae2c0d79..9f1944e3fad7f 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -149,7 +149,7 @@ pub fn sub(x: f64, y: f64) -> f64 { return x - y; } pub fn mul(x: f64, y: f64) -> f64 { return x * y; } #[inline(always)] -pub fn quot(x: f64, y: f64) -> f64 { return x / y; } +pub fn div(x: f64, y: f64) -> f64 { return x / y; } #[inline(always)] pub fn rem(x: f64, y: f64) -> f64 { return x % y; } @@ -296,15 +296,10 @@ impl Sub for f64 { impl Mul for f64 { fn mul(&self, other: &f64) -> f64 { *self * *other } } -#[cfg(stage0,notest)] +#[cfg(notest)] impl Div for f64 { fn div(&self, other: &f64) -> f64 { *self / *other } } -#[cfg(not(stage0),notest)] -impl Quot for f64 { - #[inline(always)] - fn quot(&self, other: &f64) -> f64 { *self / *other } -} #[cfg(stage0,notest)] impl Modulo for f64 { fn modulo(&self, other: &f64) -> f64 { *self % *other } diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 3aa8848cdbed2..f163d67a69ccb 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -25,7 +25,7 @@ use libc::c_int; use num::{Zero, One, strconv}; use prelude::*; -pub use f64::{add, sub, mul, quot, rem, lt, le, eq, ne, ge, gt}; +pub use f64::{add, sub, mul, div, rem, lt, le, eq, ne, ge, gt}; pub use f64::logarithm; pub use f64::{acos, asin, atan2, cbrt, ceil, copysign, cosh, floor}; pub use f64::{erf, erfc, exp, expm1, exp2, abs_sub}; @@ -692,16 +692,12 @@ impl Mul for float { fn mul(&self, other: &float) -> float { *self * *other } } -#[cfg(stage0,notest)] +#[cfg(notest)] impl Div for float { #[inline(always)] fn div(&self, other: &float) -> float { *self / *other } } -#[cfg(not(stage0),notest)] -impl Quot for float { - #[inline(always)] - fn quot(&self, other: &float) -> float { *self / *other } -} + #[cfg(stage0,notest)] impl Modulo for float { #[inline(always)] diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index ec38a32c039d6..fadba84a0fe93 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -30,7 +30,7 @@ pub fn sub(x: T, y: T) -> T { x - y } #[inline(always)] pub fn mul(x: T, y: T) -> T { x * y } #[inline(always)] -pub fn quot(x: T, y: T) -> T { x / y } +pub fn div(x: T, y: T) -> T { x / y } /// /// Returns the remainder of y / x. @@ -201,16 +201,11 @@ impl Mul for T { fn mul(&self, other: &T) -> T { *self * *other } } -#[cfg(stage0,notest)] +#[cfg(notest)] impl Div for T { - #[inline(always)] - fn div(&self, other: &T) -> T { *self / *other } -} -#[cfg(not(stage0),notest)] -impl Quot for T { /// - /// Returns the integer quotient, truncated towards 0. As this behaviour reflects - /// the underlying machine implementation it is more efficient than `Natural::div`. + /// Integer division, truncated towards 0. As this behaviour reflects the underlying + /// machine implementation it is more efficient than `Integer::div_floor`. /// /// # Examples /// @@ -227,7 +222,7 @@ impl Quot for T { /// ~~~ /// #[inline(always)] - fn quot(&self, other: &T) -> T { *self / *other } + fn div(&self, other: &T) -> T { *self / *other } } #[cfg(stage0,notest)] @@ -307,25 +302,25 @@ impl Integer for T { /// # Examples /// /// ~~~ - /// assert!(( 8).div( 3) == 2); - /// assert!(( 8).div(-3) == -3); - /// assert!((-8).div( 3) == -3); - /// assert!((-8).div(-3) == 2); + /// assert!(( 8).div_floor( 3) == 2); + /// assert!(( 8).div_floor(-3) == -3); + /// assert!((-8).div_floor( 3) == -3); + /// assert!((-8).div_floor(-3) == 2); /// - /// assert!(( 1).div( 2) == 0); - /// assert!(( 1).div(-2) == -1); - /// assert!((-1).div( 2) == -1); - /// assert!((-1).div(-2) == 0); + /// assert!(( 1).div_floor( 2) == 0); + /// assert!(( 1).div_floor(-2) == -1); + /// assert!((-1).div_floor( 2) == -1); + /// assert!((-1).div_floor(-2) == 0); /// ~~~ /// #[inline(always)] - fn div(&self, other: &T) -> T { + fn div_floor(&self, other: &T) -> T { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match self.quot_rem(other) { - (q, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => q - 1, - (q, _) => q, + match self.div_rem(other) { + (d, r) if (r > 0 && *other < 0) + || (r < 0 && *other > 0) => d - 1, + (d, _) => d, } } @@ -333,25 +328,25 @@ impl Integer for T { /// Integer modulo, satisfying: /// /// ~~~ - /// assert!(n.div(d) * d + n.modulo(d) == n) + /// assert!(n.div_floor(d) * d + n.mod_floor(d) == n) /// ~~~ /// /// # Examples /// /// ~~~ - /// assert!(( 8).modulo( 3) == 2); - /// assert!(( 8).modulo(-3) == -1); - /// assert!((-8).modulo( 3) == 1); - /// assert!((-8).modulo(-3) == -2); + /// assert!(( 8).mod_floor( 3) == 2); + /// assert!(( 8).mod_floor(-3) == -1); + /// assert!((-8).mod_floor( 3) == 1); + /// assert!((-8).mod_floor(-3) == -2); /// - /// assert!(( 1).modulo( 2) == 1); - /// assert!(( 1).modulo(-2) == -1); - /// assert!((-1).modulo( 2) == 1); - /// assert!((-1).modulo(-2) == -1); + /// assert!(( 1).mod_floor( 2) == 1); + /// assert!(( 1).mod_floor(-2) == -1); + /// assert!((-1).mod_floor( 2) == 1); + /// assert!((-1).mod_floor(-2) == -1); /// ~~~ /// #[inline(always)] - fn modulo(&self, other: &T) -> T { + fn mod_floor(&self, other: &T) -> T { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) match *self % *other { @@ -361,21 +356,21 @@ impl Integer for T { } } - /// Calculates `div` and `modulo` simultaneously + /// Calculates `div_floor` and `mod_floor` simultaneously #[inline(always)] - fn div_mod(&self, other: &T) -> (T,T) { + fn div_mod_floor(&self, other: &T) -> (T,T) { // Algorithm from [Daan Leijen. _Division and Modulus for Computer Scientists_, // December 2001](http://research.microsoft.com/pubs/151917/divmodnote-letter.pdf) - match self.quot_rem(other) { - (q, r) if (r > 0 && *other < 0) - || (r < 0 && *other > 0) => (q - 1, r + *other), - (q, r) => (q, r), + match self.div_rem(other) { + (d, r) if (r > 0 && *other < 0) + || (r < 0 && *other > 0) => (d - 1, r + *other), + (d, r) => (d, r), } } - /// Calculates `quot` (`\`) and `rem` (`%`) simultaneously + /// Calculates `div` (`\`) and `rem` (`%`) simultaneously #[inline(always)] - fn quot_rem(&self, other: &T) -> (T,T) { + fn div_rem(&self, other: &T) -> (T,T) { (*self / *other, *self % *other) } @@ -599,42 +594,42 @@ mod tests { } #[test] - fn test_quot_rem() { - fn test_nd_qr(nd: (T,T), qr: (T,T)) { + fn test_div_rem() { + fn test_nd_dr(nd: (T,T), qr: (T,T)) { let (n,d) = nd; - let separate_quot_rem = (n / d, n % d); - let combined_quot_rem = n.quot_rem(&d); + let separate_div_rem = (n / d, n % d); + let combined_div_rem = n.div_rem(&d); - assert_eq!(separate_quot_rem, qr); - assert_eq!(combined_quot_rem, qr); + assert_eq!(separate_div_rem, qr); + assert_eq!(combined_div_rem, qr); - test_division_rule(nd, separate_quot_rem); - test_division_rule(nd, combined_quot_rem); + test_division_rule(nd, separate_div_rem); + test_division_rule(nd, combined_div_rem); } - test_nd_qr(( 8, 3), ( 2, 2)); - test_nd_qr(( 8, -3), (-2, 2)); - test_nd_qr((-8, 3), (-2, -2)); - test_nd_qr((-8, -3), ( 2, -2)); + test_nd_dr(( 8, 3), ( 2, 2)); + test_nd_dr(( 8, -3), (-2, 2)); + test_nd_dr((-8, 3), (-2, -2)); + test_nd_dr((-8, -3), ( 2, -2)); - test_nd_qr(( 1, 2), ( 0, 1)); - test_nd_qr(( 1, -2), ( 0, 1)); - test_nd_qr((-1, 2), ( 0, -1)); - test_nd_qr((-1, -2), ( 0, -1)); + test_nd_dr(( 1, 2), ( 0, 1)); + test_nd_dr(( 1, -2), ( 0, 1)); + test_nd_dr((-1, 2), ( 0, -1)); + test_nd_dr((-1, -2), ( 0, -1)); } #[test] - fn test_div_mod() { + fn test_div_mod_floor() { fn test_nd_dm(nd: (T,T), dm: (T,T)) { let (n,d) = nd; - let separate_div_mod = (n.div(&d), n.modulo(&d)); - let combined_div_mod = n.div_mod(&d); + let separate_div_mod_floor = (n.div_floor(&d), n.mod_floor(&d)); + let combined_div_mod_floor = n.div_mod_floor(&d); - assert_eq!(separate_div_mod, dm); - assert_eq!(combined_div_mod, dm); + assert_eq!(separate_div_mod_floor, dm); + assert_eq!(combined_div_mod_floor, dm); - test_division_rule(nd, separate_div_mod); - test_division_rule(nd, combined_div_mod); + test_division_rule(nd, separate_div_mod_floor); + test_division_rule(nd, combined_div_mod_floor); } test_nd_dm(( 8, 3), ( 2, 2)); diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 3e43ebfef1222..b8f47db7d128e 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -11,13 +11,11 @@ //! An interface for numeric types use cmp::{Eq, Ord}; #[cfg(stage0)] -use ops::{Add, Sub, Mul, Neg}; -#[cfg(stage0)] -use Quot = ops::Div; +use ops::{Add, Sub, Mul, Div, Neg}; #[cfg(stage0)] use Rem = ops::Modulo; #[cfg(not(stage0))] -use ops::{Add, Sub, Mul, Quot, Rem, Neg}; +use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use option::Option; use kinds::Copy; @@ -32,7 +30,7 @@ pub trait Num: Eq + Zero + One + Add + Sub + Mul - + Quot + + Div + Rem {} pub trait IntConvertible { @@ -76,12 +74,13 @@ pub fn abs>(v: T) -> T { pub trait Integer: Num + Orderable - + Quot + + Div + Rem { - fn div(&self, other: &Self) -> Self; - fn modulo(&self, other: &Self) -> Self; - fn div_mod(&self, other: &Self) -> (Self,Self); - fn quot_rem(&self, other: &Self) -> (Self,Self); + fn div_rem(&self, other: &Self) -> (Self,Self); + + fn div_floor(&self, other: &Self) -> Self; + fn mod_floor(&self, other: &Self) -> Self; + fn div_mod_floor(&self, other: &Self) -> (Self,Self); fn gcd(&self, other: &Self) -> Self; fn lcm(&self, other: &Self) -> Self; @@ -102,7 +101,7 @@ pub trait Round { pub trait Fractional: Num + Orderable + Round - + Quot { + + Div { fn recip(&self) -> Self; } @@ -226,7 +225,7 @@ pub trait Primitive: Num + Add + Sub + Mul - + Quot + + Div + Rem { // FIXME (#5527): These should be associated constants fn bits() -> uint; @@ -371,7 +370,7 @@ pub trait FromStrRadix { /// - If code written to use this function doesn't care about it, it's /// probably assuming that `x^0` always equals `1`. /// -pub fn pow_with_uint+Mul>( +pub fn pow_with_uint+Mul>( radix: uint, pow: uint) -> T { let _0: T = Zero::zero(); let _1: T = One::one(); @@ -413,13 +412,13 @@ pub fn test_num(ten: T, two: T) { assert_eq!(ten.add(&two), cast(12)); assert_eq!(ten.sub(&two), cast(8)); assert_eq!(ten.mul(&two), cast(20)); - assert_eq!(ten.quot(&two), cast(5)); + assert_eq!(ten.div(&two), cast(5)); assert_eq!(ten.rem(&two), cast(0)); assert_eq!(ten.add(&two), ten + two); assert_eq!(ten.sub(&two), ten - two); assert_eq!(ten.mul(&two), ten * two); - assert_eq!(ten.quot(&two), ten / two); + assert_eq!(ten.div(&two), ten / two); assert_eq!(ten.rem(&two), ten % two); } diff --git a/src/libcore/num/strconv.rs b/src/libcore/num/strconv.rs index 2f3cd92dac09e..68e3b407a8bc2 100644 --- a/src/libcore/num/strconv.rs +++ b/src/libcore/num/strconv.rs @@ -10,15 +10,13 @@ use core::cmp::{Ord, Eq}; #[cfg(stage0)] -use ops::{Add, Sub, Mul, Neg}; -#[cfg(stage0)] -use Quot = ops::Div; +use ops::{Add, Sub, Mul, Div, Neg}; #[cfg(stage0)] use Rem = ops::Modulo; #[cfg(stage1)] #[cfg(stage2)] #[cfg(stage3)] -use ops::{Add, Sub, Mul, Quot, Rem, Neg}; +use ops::{Add, Sub, Mul, Div, Rem, Neg}; use option::{None, Option, Some}; use char; use str; @@ -67,7 +65,7 @@ fn is_neg_inf(num: &T) -> bool { } #[inline(always)] -fn is_neg_zero>(num: &T) -> bool { +fn is_neg_zero>(num: &T) -> bool { let _0: T = Zero::zero(); let _1: T = One::one(); @@ -180,7 +178,7 @@ static nan_buf: [u8, ..3] = ['N' as u8, 'a' as u8, 'N' as u8]; * - Fails if `radix` < 2 or `radix` > 36. */ pub fn to_str_bytes_common+Neg+Rem+Mul>( + Div+Neg+Rem+Mul>( num: &T, radix: uint, negative_zero: bool, sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) { if (radix as int) < 2 { @@ -388,7 +386,7 @@ pub fn to_str_bytes_common+Neg+Rem+Mul>( + Div+Neg+Rem+Mul>( num: &T, radix: uint, negative_zero: bool, sign: SignFormat, digits: SignificantDigits) -> (~str, bool) { let (bytes, special) = to_str_bytes_common(num, radix, @@ -441,7 +439,7 @@ priv static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u; * - Fails if `radix` > 18 and `special == true` due to conflict * between digit and lowest first character in `inf` and `NaN`, the `'i'`. */ -pub fn from_str_bytes_common+ +pub fn from_str_bytes_common+ Mul+Sub+Neg+Add+ NumStrConv>( buf: &[u8], radix: uint, negative: bool, fractional: bool, @@ -638,7 +636,7 @@ pub fn from_str_bytes_common+ * `from_str_bytes_common()`, for details see there. */ #[inline(always)] -pub fn from_str_common+Mul+ +pub fn from_str_common+Mul+ Sub+Neg+Add+NumStrConv>( buf: &str, radix: uint, negative: bool, fractional: bool, special: bool, exponent: ExponentFormat, empty_zero: bool, diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index 3dfdd22c42dc1..f6b98989545d0 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -31,7 +31,7 @@ pub fn sub(x: T, y: T) -> T { x - y } #[inline(always)] pub fn mul(x: T, y: T) -> T { x * y } #[inline(always)] -pub fn quot(x: T, y: T) -> T { x / y } +pub fn div(x: T, y: T) -> T { x / y } #[inline(always)] pub fn rem(x: T, y: T) -> T { x % y } @@ -166,16 +166,11 @@ impl Mul for T { fn mul(&self, other: &T) -> T { *self * *other } } -#[cfg(stage0,notest)] +#[cfg(notest)] impl Div for T { #[inline(always)] fn div(&self, other: &T) -> T { *self / *other } } -#[cfg(not(stage0),notest)] -impl Quot for T { - #[inline(always)] - fn quot(&self, other: &T) -> T { *self / *other } -} #[cfg(stage0,notest)] impl Modulo for T { @@ -197,23 +192,23 @@ impl Neg for T { impl Unsigned for T {} impl Integer for T { - /// Unsigned integer division. Returns the same result as `quot` (`/`). + /// Calculates `div` (`\`) and `rem` (`%`) simultaneously #[inline(always)] - fn div(&self, other: &T) -> T { *self / *other } + fn div_rem(&self, other: &T) -> (T,T) { + (*self / *other, *self % *other) + } - /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). + /// Unsigned integer division. Returns the same result as `div` (`/`). #[inline(always)] - fn modulo(&self, other: &T) -> T { *self / *other } + fn div_floor(&self, other: &T) -> T { *self / *other } - /// Calculates `div` and `modulo` simultaneously + /// Unsigned integer modulo operation. Returns the same result as `rem` (`%`). #[inline(always)] - fn div_mod(&self, other: &T) -> (T,T) { - (*self / *other, *self % *other) - } + fn mod_floor(&self, other: &T) -> T { *self / *other } - /// Calculates `quot` (`\`) and `rem` (`%`) simultaneously + /// Calculates `div_floor` and `modulo_floor` simultaneously #[inline(always)] - fn quot_rem(&self, other: &T) -> (T,T) { + fn div_mod_floor(&self, other: &T) -> (T,T) { (*self / *other, *self % *other) } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 1aa7aada05c88..5ba860c89c9b9 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -31,15 +31,9 @@ pub trait Mul { } #[lang="div"] -#[cfg(stage0)] pub trait Div { fn div(&self, rhs: &RHS) -> Result; } -#[lang="quot"] -#[cfg(not(stage0))] -pub trait Quot { - fn quot(&self, rhs: &RHS) -> Result; -} #[lang="modulo"] #[cfg(stage0)] diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 9a2e480ce6e54..4527fcf2923da 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -17,7 +17,7 @@ pub use kinds::{Const, Copy, Owned, Durable}; #[cfg(stage0)] pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not}; #[cfg(not(stage0))] -pub use ops::{Add, Sub, Mul, Quot, Rem, Neg, Not}; +pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Drop}; pub use ops::{Shl, Shr, Index}; diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index bba4d35b56046..86b7379bb698d 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -279,7 +279,7 @@ pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: @expr) add => Ok(const_float(a + b)), subtract => Ok(const_float(a - b)), mul => Ok(const_float(a * b)), - quot => Ok(const_float(a / b)), + div => Ok(const_float(a / b)), rem => Ok(const_float(a % b)), eq => fromb(a == b), lt => fromb(a < b), @@ -295,8 +295,8 @@ pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: @expr) add => Ok(const_int(a + b)), subtract => Ok(const_int(a - b)), mul => Ok(const_int(a * b)), - quot if b == 0 => Err(~"attempted quotient with a divisor of zero"), - quot => Ok(const_int(a / b)), + div if b == 0 => Err(~"attempted to divide by zero"), + div => Ok(const_int(a / b)), rem if b == 0 => Err(~"attempted remainder with a divisor of zero"), rem => Ok(const_int(a % b)), and | bitand => Ok(const_int(a & b)), @@ -317,8 +317,8 @@ pub fn eval_const_expr_partial(tcx: middle::ty::ctxt, e: @expr) add => Ok(const_uint(a + b)), subtract => Ok(const_uint(a - b)), mul => Ok(const_uint(a * b)), - quot if b == 0 => Err(~"attempted quotient with a divisor of zero"), - quot => Ok(const_uint(a / b)), + div if b == 0 => Err(~"attempted to divide by zero"), + div => Ok(const_uint(a / b)), rem if b == 0 => Err(~"attempted remainder with a divisor of zero"), rem => Ok(const_uint(a % b)), and | bitand => Ok(const_uint(a & b)), diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 2de12b9eb9746..7298064e1c00d 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -42,7 +42,7 @@ pub enum LangItem { AddTraitLangItem, // 5 SubTraitLangItem, // 6 MulTraitLangItem, // 7 - QuotTraitLangItem, // 8 + DivTraitLangItem, // 8 RemTraitLangItem, // 9 NegTraitLangItem, // 10 NotTraitLangItem, // 11 @@ -105,7 +105,7 @@ pub impl LanguageItems { 5 => "add", 6 => "sub", 7 => "mul", - 8 => "quot", + 8 => "div", 9 => "rem", 10 => "neg", 11 => "not", @@ -167,8 +167,8 @@ pub impl LanguageItems { pub fn mul_trait(&const self) -> def_id { self.items[MulTraitLangItem as uint].get() } - pub fn quot_trait(&const self) -> def_id { - self.items[QuotTraitLangItem as uint].get() + pub fn div_trait(&const self) -> def_id { + self.items[DivTraitLangItem as uint].get() } pub fn rem_trait(&const self) -> def_id { self.items[RemTraitLangItem as uint].get() @@ -268,7 +268,7 @@ fn LanguageItemCollector<'r>(crate: @crate, item_refs.insert(@~"add", AddTraitLangItem as uint); item_refs.insert(@~"sub", SubTraitLangItem as uint); item_refs.insert(@~"mul", MulTraitLangItem as uint); - item_refs.insert(@~"quot", QuotTraitLangItem as uint); + item_refs.insert(@~"div", DivTraitLangItem as uint); item_refs.insert(@~"rem", RemTraitLangItem as uint); item_refs.insert(@~"neg", NegTraitLangItem as uint); item_refs.insert(@~"not", NotTraitLangItem as uint); diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 294a21fac2c23..d8ad53212e2b7 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -33,7 +33,7 @@ use syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op}; use syntax::ast::{expr_binary, expr_break, expr_field}; use syntax::ast::{expr_fn_block, expr_index, expr_method_call, expr_path}; use syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param}; -use syntax::ast::{def_upvar, def_use, def_variant, quot, eq}; +use syntax::ast::{def_upvar, def_use, def_variant, div, eq}; use syntax::ast::{expr, expr_again, expr_assign_op}; use syntax::ast::{expr_index, expr_loop}; use syntax::ast::{expr_path, expr_struct, expr_unary, fn_decl}; @@ -4901,9 +4901,9 @@ pub impl Resolver { self.add_fixed_trait_for_expr(expr.id, self.lang_items.mul_trait()); } - expr_binary(quot, _, _) | expr_assign_op(quot, _, _) => { + expr_binary(div, _, _) | expr_assign_op(div, _, _) => { self.add_fixed_trait_for_expr(expr.id, - self.lang_items.quot_trait()); + self.lang_items.div_trait()); } expr_binary(rem, _, _) | expr_assign_op(rem, _, _) => { self.add_fixed_trait_for_expr(expr.id, diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index efa10dfc2aa34..262196ffffd5c 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -777,10 +777,10 @@ pub fn cast_shift_rhs(op: ast::binop, } } -pub fn fail_if_zero(cx: block, span: span, quotrem: ast::binop, +pub fn fail_if_zero(cx: block, span: span, divrem: ast::binop, rhs: ValueRef, rhs_t: ty::t) -> block { - let text = if quotrem == ast::quot { - @~"attempted quotient with a divisor of zero" + let text = if divrem == ast::div { + @~"attempted to divide by zero" } else { @~"attempted remainder with a divisor of zero" }; diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 25f34b8eaa9d1..c6c5561854c0d 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -270,7 +270,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { if is_float { llvm::LLVMConstFMul(te1, te2) } else { llvm::LLVMConstMul(te1, te2) } } - ast::quot => { + ast::div => { if is_float { llvm::LLVMConstFDiv(te1, te2) } else if signed { llvm::LLVMConstSDiv(te1, te2) } else { llvm::LLVMConstUDiv(te1, te2) } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index f83562add3169..ae510ae6d114f 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1435,7 +1435,7 @@ fn trans_eager_binop(bcx: block, if is_float { FMul(bcx, lhs, rhs) } else { Mul(bcx, lhs, rhs) } } - ast::quot => { + ast::div => { if is_float { FDiv(bcx, lhs, rhs) } else { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c7fb1e94adf4c..4280cd4000d81 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4134,7 +4134,7 @@ pub fn is_binopable(_cx: ctxt, ty: t, op: ast::binop) -> bool { ast::add => opcat_add, ast::subtract => opcat_sub, ast::mul => opcat_mult, - ast::quot => opcat_mult, + ast::div => opcat_mult, ast::rem => opcat_mult, ast::and => opcat_logic, ast::or => opcat_logic, diff --git a/src/libstd/num/bigint.rs b/src/libstd/num/bigint.rs index e010340b94d8e..fa9d6318cc947 100644 --- a/src/libstd/num/bigint.rs +++ b/src/libstd/num/bigint.rs @@ -293,10 +293,10 @@ impl Mul for BigUint { } } -impl Quot for BigUint { +impl Div for BigUint { #[inline(always)] - fn quot(&self, other: &BigUint) -> BigUint { - let (q, _) = self.quot_rem(other); + fn div(&self, other: &BigUint) -> BigUint { + let (q, _) = self.div_rem(other); return q; } } @@ -304,7 +304,7 @@ impl Quot for BigUint { impl Rem for BigUint { #[inline(always)] fn rem(&self, other: &BigUint) -> BigUint { - let (_, r) = self.quot_rem(other); + let (_, r) = self.div_rem(other); return r; } } @@ -316,19 +316,24 @@ impl Neg for BigUint { impl Integer for BigUint { #[inline(always)] - fn div(&self, other: &BigUint) -> BigUint { - let (d, _) = self.div_mod(other); + fn div_rem(&self, other: &BigUint) -> (BigUint, BigUint) { + self.div_mod_floor(other) + } + + #[inline(always)] + fn div_floor(&self, other: &BigUint) -> BigUint { + let (d, _) = self.div_mod_floor(other); return d; } #[inline(always)] - fn modulo(&self, other: &BigUint) -> BigUint { - let (_, m) = self.div_mod(other); + fn mod_floor(&self, other: &BigUint) -> BigUint { + let (_, m) = self.div_mod_floor(other); return m; } #[inline(always)] - fn div_mod(&self, other: &BigUint) -> (BigUint, BigUint) { + fn div_mod_floor(&self, other: &BigUint) -> (BigUint, BigUint) { if other.is_zero() { fail!() } if self.is_zero() { return (Zero::zero(), Zero::zero()); } if *other == One::one() { return (copy *self, Zero::zero()); } @@ -346,11 +351,11 @@ impl Integer for BigUint { shift += 1; } assert!(shift < BigDigit::bits); - let (d, m) = div_mod_inner(self << shift, other << shift); + let (d, m) = div_mod_floor_inner(self << shift, other << shift); return (d, m >> shift); #[inline(always)] - fn div_mod_inner(a: BigUint, b: BigUint) -> (BigUint, BigUint) { + fn div_mod_floor_inner(a: BigUint, b: BigUint) -> (BigUint, BigUint) { let mut m = a; let mut d = Zero::zero::(); let mut n = 1; @@ -409,11 +414,6 @@ impl Integer for BigUint { } } - #[inline(always)] - fn quot_rem(&self, other: &BigUint) -> (BigUint, BigUint) { - self.div_mod(other) - } - /** * Calculates the Greatest Common Divisor (GCD) of the number and `other` * @@ -485,7 +485,7 @@ impl ToStrRadix for BigUint { let mut result = ~[]; let mut m = n; while m > divider { - let (d, m0) = m.div_mod(÷r); + let (d, m0) = m.div_mod_floor(÷r); result += [m0.to_uint() as BigDigit]; m = d; } @@ -894,10 +894,10 @@ impl Mul for BigInt { } } -impl Quot for BigInt { +impl Div for BigInt { #[inline(always)] - fn quot(&self, other: &BigInt) -> BigInt { - let (q, _) = self.quot_rem(other); + fn div(&self, other: &BigInt) -> BigInt { + let (q, _) = self.div_rem(other); return q; } } @@ -905,7 +905,7 @@ impl Quot for BigInt { impl Rem for BigInt { #[inline(always)] fn rem(&self, other: &BigInt) -> BigInt { - let (_, r) = self.quot_rem(other); + let (_, r) = self.div_rem(other); return r; } } @@ -919,21 +919,36 @@ impl Neg for BigInt { impl Integer for BigInt { #[inline(always)] - fn div(&self, other: &BigInt) -> BigInt { - let (d, _) = self.div_mod(other); + fn div_rem(&self, other: &BigInt) -> (BigInt, BigInt) { + // r.sign == self.sign + let (d_ui, r_ui) = self.data.div_mod_floor(&other.data); + let d = BigInt::from_biguint(Plus, d_ui); + let r = BigInt::from_biguint(Plus, r_ui); + match (self.sign, other.sign) { + (_, Zero) => fail!(), + (Plus, Plus) | (Zero, Plus) => ( d, r), + (Plus, Minus) | (Zero, Minus) => (-d, r), + (Minus, Plus) => (-d, -r), + (Minus, Minus) => ( d, -r) + } + } + + #[inline(always)] + fn div_floor(&self, other: &BigInt) -> BigInt { + let (d, _) = self.div_mod_floor(other); return d; } #[inline(always)] - fn modulo(&self, other: &BigInt) -> BigInt { - let (_, m) = self.div_mod(other); + fn mod_floor(&self, other: &BigInt) -> BigInt { + let (_, m) = self.div_mod_floor(other); return m; } #[inline(always)] - fn div_mod(&self, other: &BigInt) -> (BigInt, BigInt) { + fn div_mod_floor(&self, other: &BigInt) -> (BigInt, BigInt) { // m.sign == other.sign - let (d_ui, m_ui) = self.data.quot_rem(&other.data); + let (d_ui, m_ui) = self.data.div_rem(&other.data); let d = BigInt::from_biguint(Plus, d_ui), m = BigInt::from_biguint(Plus, m_ui); match (self.sign, other.sign) { @@ -953,21 +968,6 @@ impl Integer for BigInt { } } - #[inline(always)] - fn quot_rem(&self, other: &BigInt) -> (BigInt, BigInt) { - // r.sign == self.sign - let (q_ui, r_ui) = self.data.div_mod(&other.data); - let q = BigInt::from_biguint(Plus, q_ui); - let r = BigInt::from_biguint(Plus, r_ui); - match (self.sign, other.sign) { - (_, Zero) => fail!(), - (Plus, Plus) | (Zero, Plus) => ( q, r), - (Plus, Minus) | (Zero, Minus) => (-q, r), - (Minus, Plus) => (-q, -r), - (Minus, Minus) => ( q, -r) - } - } - /** * Calculates the Greatest Common Divisor (GCD) of the number and `other` * @@ -1100,8 +1100,6 @@ pub impl BigInt { #[cfg(test)] mod biguint_tests { - - use core::*; use core::num::{IntConvertible, Zero, One, FromStrRadix}; use core::cmp::{Less, Equal, Greater}; use super::{BigUint, BigDigit}; @@ -1347,7 +1345,7 @@ mod biguint_tests { (&[ 0, 0, 1], &[ 0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]) ]; - static quot_rem_quadruples: &'static [(&'static [BigDigit], + static div_rem_quadruples: &'static [(&'static [BigDigit], &'static [BigDigit], &'static [BigDigit], &'static [BigDigit])] @@ -1371,7 +1369,7 @@ mod biguint_tests { assert!(b * a == c); } - for quot_rem_quadruples.each |elm| { + for div_rem_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); @@ -1384,7 +1382,7 @@ mod biguint_tests { } #[test] - fn test_quot_rem() { + fn test_div_rem() { for mul_triples.each |elm| { let (aVec, bVec, cVec) = *elm; let a = BigUint::from_slice(aVec); @@ -1392,21 +1390,21 @@ mod biguint_tests { let c = BigUint::from_slice(cVec); if !a.is_zero() { - assert!(c.quot_rem(&a) == (copy b, Zero::zero())); + assert!(c.div_rem(&a) == (copy b, Zero::zero())); } if !b.is_zero() { - assert!(c.quot_rem(&b) == (copy a, Zero::zero())); + assert!(c.div_rem(&b) == (copy a, Zero::zero())); } } - for quot_rem_quadruples.each |elm| { + for div_rem_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigUint::from_slice(aVec); let b = BigUint::from_slice(bVec); let c = BigUint::from_slice(cVec); let d = BigUint::from_slice(dVec); - if !b.is_zero() { assert!(a.quot_rem(&b) == (c, d)); } + if !b.is_zero() { assert!(a.div_rem(&b) == (c, d)); } } } @@ -1558,7 +1556,6 @@ mod biguint_tests { #[cfg(test)] mod bigint_tests { use super::{BigInt, BigUint, BigDigit, Sign, Minus, Zero, Plus}; - use core::*; use core::cmp::{Less, Equal, Greater}; use core::num::{IntConvertible, Zero, One, FromStrRadix}; @@ -1750,10 +1747,10 @@ mod bigint_tests { (&[ 0, 0, 1], &[ 0, 0, 0, 1], &[0, 0, 0, 0, 0, 1]) ]; - static quot_rem_quadruples: &'static [(&'static [BigDigit], - &'static [BigDigit], - &'static [BigDigit], - &'static [BigDigit])] + static div_rem_quadruples: &'static [(&'static [BigDigit], + &'static [BigDigit], + &'static [BigDigit], + &'static [BigDigit])] = &[ (&[ 1], &[ 2], &[], &[1]), (&[ 1, 1], &[ 2], &[-1/2+1], &[1]), @@ -1777,7 +1774,7 @@ mod bigint_tests { assert!((-b) * a == -c); } - for quot_rem_quadruples.each |elm| { + for div_rem_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); @@ -1790,9 +1787,9 @@ mod bigint_tests { } #[test] - fn test_div_mod() { + fn test_div_mod_floor() { fn check_sub(a: &BigInt, b: &BigInt, ans_d: &BigInt, ans_m: &BigInt) { - let (d, m) = a.div_mod(b); + let (d, m) = a.div_mod_floor(b); if !m.is_zero() { assert!(m.sign == b.sign); } @@ -1826,7 +1823,7 @@ mod bigint_tests { if !b.is_zero() { check(&c, &b, &a, &Zero::zero()); } } - for quot_rem_quadruples.each |elm| { + for div_rem_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); @@ -1841,9 +1838,9 @@ mod bigint_tests { #[test] - fn test_quot_rem() { + fn test_div_rem() { fn check_sub(a: &BigInt, b: &BigInt, ans_q: &BigInt, ans_r: &BigInt) { - let (q, r) = a.quot_rem(b); + let (q, r) = a.div_rem(b); if !r.is_zero() { assert!(r.sign == a.sign); } @@ -1869,7 +1866,7 @@ mod bigint_tests { if !b.is_zero() { check(&c, &b, &a, &Zero::zero()); } } - for quot_rem_quadruples.each |elm| { + for div_rem_quadruples.each |elm| { let (aVec, bVec, cVec, dVec) = *elm; let a = BigInt::from_slice(Plus, aVec); let b = BigInt::from_slice(Plus, bVec); diff --git a/src/libstd/num/complex.rs b/src/libstd/num/complex.rs index 02393b15cca0f..41d2b4a101cd5 100644 --- a/src/libstd/num/complex.rs +++ b/src/libstd/num/complex.rs @@ -102,9 +102,9 @@ impl Mul, Cmplx> for Cmplx { // (a + i b) / (c + i d) == [(a + i b) * (c - i d)] / (c*c + d*d) // == [(a*c + b*d) / (c*c + d*d)] + i [(b*c - a*d) / (c*c + d*d)] -impl Quot, Cmplx> for Cmplx { +impl Div, Cmplx> for Cmplx { #[inline] - fn quot(&self, other: &Cmplx) -> Cmplx { + fn div(&self, other: &Cmplx) -> Cmplx { let norm_sqr = other.norm_sqr(); Cmplx::new((self.re*other.re + self.im*other.im) / norm_sqr, (self.im*other.re - self.re*other.im) / norm_sqr) @@ -275,7 +275,7 @@ mod test { } } #[test] - fn test_quot() { + fn test_div() { assert_eq!(_neg1_1i / _0_1i, _1_1i); for all_consts.each |&c| { if c != Zero::zero() { diff --git a/src/libstd/num/rational.rs b/src/libstd/num/rational.rs index a7c170c1cd6da..9b92b7241b990 100644 --- a/src/libstd/num/rational.rs +++ b/src/libstd/num/rational.rs @@ -143,9 +143,9 @@ impl // (a/b) / (c/d) = (a*d)/(b*c) impl - Quot,Ratio> for Ratio { + Div,Ratio> for Ratio { #[inline] - fn quot(&self, rhs: &Ratio) -> Ratio { + fn div(&self, rhs: &Ratio) -> Ratio { Ratio::new(self.numer * rhs.denom, self.denom * rhs.numer) } } @@ -395,7 +395,7 @@ mod test { } #[test] - fn test_quot() { + fn test_div() { assert_eq!(_1 / _1_2, _2); assert_eq!(_3_2 / _1_2, _1 + _2); assert_eq!(_1 / _neg1_2, _neg1_2 + _neg1_2 + _neg1_2 + _neg1_2); @@ -424,7 +424,7 @@ mod test { } #[test] #[should_fail] - fn test_quot_0() { + fn test_div_0() { let _a = _1 / _0; } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index ba6fe1cda4f31..5690502c811fe 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -389,7 +389,7 @@ pub enum binop { add, subtract, mul, - quot, + div, rem, and, or, diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 148b713a4f58f..0ffeb684dc051 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -73,7 +73,7 @@ pub fn binop_to_str(op: binop) -> ~str { add => return ~"+", subtract => return ~"-", mul => return ~"*", - quot => return ~"/", + div => return ~"/", rem => return ~"%", and => return ~"&&", or => return ~"||", @@ -96,7 +96,7 @@ pub fn binop_to_method_name(op: binop) -> Option<~str> { add => return Some(~"add"), subtract => return Some(~"sub"), mul => return Some(~"mul"), - quot => return Some(~"quot"), + div => return Some(~"div"), rem => return Some(~"rem"), bitxor => return Some(~"bitxor"), bitand => return Some(~"bitand"), @@ -341,7 +341,7 @@ pub fn is_self(d: ast::def) -> bool { /// Maps a binary operator to its precedence pub fn operator_prec(op: ast::binop) -> uint { match op { - mul | quot | rem => 12u, + mul | div | rem => 12u, // 'as' sits between here with 11 add | subtract => 10u, shl | shr => 9u, diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 50bdfb2f55726..42c6fad646364 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -19,7 +19,7 @@ use ast::{_mod, add, arg, arm, attribute, bind_by_ref, bind_infer}; use ast::{bind_by_copy, bitand, bitor, bitxor, blk}; use ast::{blk_check_mode, box}; use ast::{crate, crate_cfg, decl, decl_item}; -use ast::{decl_local, default_blk, deref, quot, enum_def}; +use ast::{decl_local, default_blk, deref, div, enum_def}; use ast::{expr, expr_, expr_addr_of, expr_match, expr_again}; use ast::{expr_assign, expr_assign_op, expr_binary, expr_block}; use ast::{expr_break, expr_call, expr_cast, expr_copy, expr_do_body}; @@ -1836,7 +1836,7 @@ pub impl Parser { token::PLUS => aop = add, token::MINUS => aop = subtract, token::STAR => aop = mul, - token::SLASH => aop = quot, + token::SLASH => aop = div, token::PERCENT => aop = rem, token::CARET => aop = bitxor, token::AND => aop = bitand, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 0327a3b80da87..9426e9abab3b4 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -371,7 +371,7 @@ impl<'self> to_bytes::IterBytes for StringRef<'self> { pub fn token_to_binop(tok: Token) -> Option { match tok { BINOP(STAR) => Some(ast::mul), - BINOP(SLASH) => Some(ast::quot), + BINOP(SLASH) => Some(ast::div), BINOP(PERCENT) => Some(ast::rem), BINOP(PLUS) => Some(ast::add), BINOP(MINUS) => Some(ast::subtract), diff --git a/src/test/compile-fail/eval-enum.rs b/src/test/compile-fail/eval-enum.rs index 0123341957903..f92dad961d134 100644 --- a/src/test/compile-fail/eval-enum.rs +++ b/src/test/compile-fail/eval-enum.rs @@ -1,5 +1,5 @@ enum test { - quot_zero = 1/0, //~ERROR expected constant: attempted quotient with a divisor of zero + div_zero = 1/0, //~ERROR expected constant: attempted to divide by zero rem_zero = 1%0 //~ERROR expected constant: attempted remainder with a divisor of zero } diff --git a/src/test/run-fail/divide-by-zero.rs b/src/test/run-fail/divide-by-zero.rs index d4f3828ea7174..9c996807ad866 100644 --- a/src/test/run-fail/divide-by-zero.rs +++ b/src/test/run-fail/divide-by-zero.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// error-pattern:attempted quotient with a divisor of zero +// error-pattern:attempted to divide by zero fn main() { let y = 0; let z = 1 / y; From dca88701a311c7dffec1ee5e990df9570647ba03 Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Wed, 1 May 2013 18:49:19 +0900 Subject: [PATCH 090/215] mk: install-runtime-target added to install.mk (pushing shared library to android target) --- mk/install.mk | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/mk/install.mk b/mk/install.mk index a84f527a165b4..693589980ce03 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -154,3 +154,66 @@ uninstall: done $(Q)rm -Rf $(PHL)/rustc $(Q)rm -f $(PREFIX_ROOT)/share/man/man1/rustc.1 + +# target platform specific variables +# for arm-linux-androidabi +define DEF_ADB_STATUS +CFG_ADB_DEVICE=$(1) +endef + +$(foreach target,$(CFG_TARGET_TRIPLES), \ + $(if $(findstring $(target),"arm-linux-androideabi"), \ + $(if $(findstring adb,$(shell which adb)), \ + $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[A-Za-z0-9]+[[:blank:]]+device')), \ + $(info install: install-runtime-target for arm-linux-androideabi enabled \ + $(info install: android device attached) \ + $(eval $(call DEF_ADB_STATUS, true))), \ + $(info install: install-runtime-target for arm-linux-androideabi disabled \ + $(info install: android device not attached) \ + $(eval $(call DEF_ADB_STATUS, false))) \ + ), \ + $(info install: install-runtime-target for arm-linux-androideabi disabled \ + $(info install: adb not found) \ + $(eval $(call DEF_ADB_STATUS, false))) \ + ), \ + ) \ +) + +ifeq ($(CFG_ADB_DEVICE),true) + +ifdef VERBOSE + ADB = adb $(1) + ADB_PUSH = adb push $(1) $(2) + ADB_SHELL = adb shell $(1) $(2) +else + ADB = $(Q)$(call E, adb $(1)) && adb $(1) 1>/dev/null 2>/dev/null + ADB_PUSH = $(Q)$(call E, adb push $(1)) && adb push $(1) $(2) 1>/dev/null 2>/dev/null + ADB_SHELL = $(Q)$(call E, adb shell $(1) $(2)) && adb shell $(1) $(2) 1>/dev/null 2>/dev/null +endif + +define INSTALL_RUNTIME_TARGET_N +install-runtime-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ$$(ISTAGE)_T_$(1)_H_$(2)) + $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(CFG_RUNTIME_$(1)),/system/lib) + $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(CORELIB_GLOB_$(1)),/system/lib) + $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(STDLIB_GLOB_$(1)),/system/lib) +endef + +define INSTALL_RUNTIME_TARGET_CLEANUP_N +install-runtime-target-$(1)-cleanup: + $(Q)$(call ADB,remount) + $(Q)$(call ADB_SHELL,rm,/system/lib/$(CFG_RUNTIME_$(1))) + $(Q)$(call ADB_SHELL,rm,/system/lib/$(CORELIB_GLOB_$(1))) + $(Q)$(call ADB_SHELL,rm,/system/lib/$(STDLIB_GLOB_$(1))) +endef + +$(eval $(call INSTALL_RUNTIME_TARGET_N,arm-linux-androideabi,$(CFG_BUILD_TRIPLE))) +$(eval $(call INSTALL_RUNTIME_TARGET_CLEANUP_N,arm-linux-androideabi)) + +install-runtime-target: \ + install-runtime-target-arm-linux-androideabi-cleanup \ + install-runtime-target-arm-linux-androideabi-host-$(CFG_BUILD_TRIPLE) + +else +install-runtime-target: + @echo +endif From 57c126e9bbcb4d02c40787afc46f5865874220d7 Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Wed, 1 May 2013 18:50:23 +0900 Subject: [PATCH 091/215] mk: test.mk expanded to ARM test automation --- mk/tests.mk | 113 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 108 insertions(+), 5 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index f96b7325f60d4..9b01c4af80fdd 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -92,6 +92,48 @@ endef $(foreach target,$(CFG_TARGET_TRIPLES), \ $(eval $(call DEF_TARGET_COMMANDS,$(target)))) +# Target specific variables +# for arm-linux-androidabi +define DEF_RUNNABLE_STATUS +CFG_RUNNABLE_$(1)=$(2) +endef + +$(foreach target,$(CFG_TARGET_TRIPLES), \ + $(if $(findstring $(target),$(CFG_BUILD_TRIPLE)), \ + $(info check: $(target) test set is runnable \ + $(eval $(call DEF_RUNNABLE_STATUS,$(target),true))), \ + $(if $(findstring $(target),"arm-linux-androideabi"), \ + $(if $(findstring adb,$(shell which adb)), \ + $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[A-Za-z0-9]+[[:blank:]]+device')), \ + $(info check: $(target) test set is runnable \ + $(info check: adb device attached) \ + $(eval $(call DEF_RUNNABLE_STATUS,$(target),true))), \ + $(info check: $(target) test set is not runnable \ + $(info check: adb device not attached) \ + $(eval $(call DEF_RUNNABLE_STATUS,$(target),false))) \ + ), \ + $(info check: $(target) test set is not runnable \ + $(info check: adb not found) \ + $(eval $(call DEF_RUNNABLE_STATUS,$(target),false))) \ + ), \ + $(info check: $(target) test set is not runnable \ + $(eval $(call DEF_RUNNABLE_STATUS,$(target),false)) \ + ) \ + ) \ + ) \ +) + +ifeq ($(CFG_RUNNABLE_arm-linux-androideabi),true) +CFG_ADB_DEVICE=true +CFG_ADB_PATH := $(shell which adb) +CFG_ADB_TEST_DIR=/system/tmp + +$(info check: device $(CFG_ADB_TEST_DIR) \ + $(shell $(CFG_ADB_PATH) shell mkdir $(CFG_ADB_TEST_DIR) 1>/dev/null) \ + $(shell $(CFG_ADB_PATH) shell rm $(CFG_ADB_TEST_DIR)/*-arm-linux-androideabi 1>/dev/null) \ + $(shell $(CFG_ADB_PATH) shell rm $(CFG_ADB_TEST_DIR)/*.so 1>/dev/null) \ + ) +endif ###################################################################### # Main test targets @@ -319,11 +361,52 @@ $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ && touch $$@ endef +define DEF_TEST_CRATE_RULES_arm-linux-androideabi +check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)) + +$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ + $(3)/test/$(4)test.stage$(1)-$(2)$$(X_$(2)) + @$$(call E, run: $$< via adb) + @$(CFG_ADB_PATH) push $$< $(CFG_ADB_TEST_DIR) + @$(CFG_ADB_PATH) shell $(CFG_ADB_TEST_DIR)/`echo $$< | sed 's/.*\///'` \ + --logfile $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log > \ + tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp + @cat tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp + @touch tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log + @$(CFG_ADB_PATH) pull $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log tmp/ + @$(CFG_ADB_PATH) shell rm $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log + @if grep -q "result: ok" tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \ + then \ + rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \ + touch $$@; \ + else \ + rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \ + exit 101; \ + fi +endef + +define DEF_TEST_CRATE_RULES_null +check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)) + +$$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ + $(3)/test/$(4)test.stage$(1)-$(2)$$(X_$(2)) + @$$(call E, run: skipped $$< ) + @touch $$@ +endef + $(foreach host,$(CFG_HOST_TRIPLES), \ $(foreach target,$(CFG_TARGET_TRIPLES), \ $(foreach stage,$(STAGES), \ $(foreach crate, $(TEST_CRATES), \ - $(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))))))) + $(if $(findstring $(target),$(CFG_BUILD_TRIPLE)), \ + $(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))), \ + $(if $(findstring $(target),"arm-linux-androideabi"), \ + $(if $(findstring $(CFG_RUNNABLE_arm-linux-androideabi),"true"), \ + $(eval $(call DEF_TEST_CRATE_RULES_arm-linux-androideabi,$(stage),$(target),$(host),$(crate))), \ + $(eval $(call DEF_TEST_CRATE_RULES_null,$(stage),$(target),$(host),$(crate))) \ + ), \ + $(eval $(call DEF_TEST_CRATE_RULES_null,$(stage),$(target),$(host),$(crate))) \ + )))))) ###################################################################### @@ -414,15 +497,35 @@ TEST_SREQ$(1)_T_$(2)_H_$(3) = \ # Rules for the cfail/rfail/rpass/bench/perf test runner +ifeq ($(CFG_ADB_DEVICE),true) + CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --compile-lib-path $$(HLIB$(1)_H_$(3)) \ --run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \ --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ --aux-base $$(S)src/test/auxiliary/ \ --stage-id stage$(1)-$(2) \ + --host $(3) \ + --target $(2) \ + --adb-path=$(CFG_ADB_PATH) \ --rustcflags "$(RUSTC_FLAGS_$(2)) $$(CFG_RUSTC_FLAGS) --target=$(2)" \ $$(CTEST_TESTARGS) +else + +CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ + --compile-lib-path $$(HLIB$(1)_H_$(3)) \ + --run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \ + --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ + --aux-base $$(S)src/test/auxiliary/ \ + --stage-id stage$(1)-$(2) \ + --host $(3) \ + --target $(2) \ + --rustcflags "$(RUSTC_FLAGS_$(2)) $$(CFG_RUSTC_FLAGS) --target=$(2)" \ + $$(CTEST_TESTARGS) + +endif + CTEST_DEPS_rpass_$(1)-T-$(2)-H-$(3) = $$(RPASS_TESTS) CTEST_DEPS_rpass_full_$(1)-T-$(2)-H-$(3) = $$(RPASS_FULL_TESTS) $$(TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3)) CTEST_DEPS_rfail_$(1)-T-$(2)-H-$(3) = $$(RFAIL_TESTS) @@ -454,7 +557,7 @@ ifeq ($$(CTEST_DISABLE_$(4)),) $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ $$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3)) - @$$(call E, run $(4): $$<) + @$$(call E, run $(4) [$(2)]: $$<) $$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \ $$(CTEST_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \ --logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \ @@ -465,7 +568,7 @@ else $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ $$(CTEST_DEPS_$(4)_$(1)-T-$(2)-H-$(3)) - @$$(call E, run $(4): $$<) + @$$(call E, run $(4) [$(2)]: $$<) @$$(call E, warning: tests disabled: $$(CTEST_DISABLE_$(4))) touch $$@ @@ -506,7 +609,7 @@ check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4 $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ $$(PRETTY_DEPS_$(4)) - @$$(call E, run pretty-rpass: $$<) + @$$(call E, run pretty-rpass [$(2)]: $$<) $$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \ $$(PRETTY_ARGS$(1)-T-$(2)-H-$(3)-$(4)) \ --logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),$(4)) \ @@ -533,7 +636,7 @@ check-stage$(1)-T-$(2)-H-$(3)-doc-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3) $$(call TEST_OK_FILE,$(1),$(2),$(3),doc-$(4)): \ $$(TEST_SREQ$(1)_T_$(2)_H_$(3)) \ doc-$(4)-extract$(3) - @$$(call E, run doc-$(4): $$<) + @$$(call E, run doc-$(4) [$(2)]: $$<) $$(Q)$$(call CFG_RUN_CTEST_$(2),$(1),$$<,$(3)) \ $$(DOC_TEST_ARGS$(1)-T-$(2)-H-$(3)-doc-$(4)) \ --logfile $$(call TEST_LOG_FILE,$(1),$(2),$(3),doc-$(4)) \ From f7ef71d491fe432eab3c3c9d2ee80a6678ebb952 Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Wed, 1 May 2013 18:52:08 +0900 Subject: [PATCH 092/215] compiletest: expanded to ARM test automation --- src/compiletest/common.rs | 12 ++++ src/compiletest/compiletest.rc | 26 ++++++- src/compiletest/runtest.rs | 127 +++++++++++++++++++++++++++++++-- 3 files changed, 158 insertions(+), 7 deletions(-) diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs index e515ef302f658..73322fe1bdeac 100644 --- a/src/compiletest/common.rs +++ b/src/compiletest/common.rs @@ -64,6 +64,18 @@ pub struct config { // Run tests using the new runtime newrt: bool, + // Host System to be built + host: ~str, + + // Target System to be executed + target: ~str, + + // Extra parameter to run arm-linux-androideabi + adb_path: ~str, + + // check if can be run or not + flag_runnable: bool, + // Explain what's going on verbose: bool diff --git a/src/compiletest/compiletest.rc b/src/compiletest/compiletest.rc index 4392ce7ba2891..70e09fc7bab7e 100644 --- a/src/compiletest/compiletest.rc +++ b/src/compiletest/compiletest.rc @@ -60,7 +60,11 @@ pub fn parse_config(args: ~[~str]) -> config { getopts::optflag(~"verbose"), getopts::optopt(~"logfile"), getopts::optflag(~"jit"), - getopts::optflag(~"newrt")]; + getopts::optflag(~"newrt"), + getopts::optopt(~"host"), + getopts::optopt(~"target"), + getopts::optopt(~"adb-path") + ]; assert!(!args.is_empty()); let args_ = vec::tail(args); @@ -93,6 +97,22 @@ pub fn parse_config(args: ~[~str]) -> config { rustcflags: getopts::opt_maybe_str(matches, ~"rustcflags"), jit: getopts::opt_present(matches, ~"jit"), newrt: getopts::opt_present(matches, ~"newrt"), + host: opt_str(getopts::opt_maybe_str(matches, ~"host")), + target: opt_str(getopts::opt_maybe_str(matches, ~"target")), + adb_path: opt_str(getopts::opt_maybe_str(matches, ~"adb-path")), + flag_runnable: + if (getopts::opt_maybe_str(matches, ~"host") == + getopts::opt_maybe_str(matches, ~"target")) { true } + else { + match getopts::opt_maybe_str(matches, ~"target") { + Some(~"arm-linux-androideabi") => { + if (getopts::opt_maybe_str(matches, ~"adb-path") != + option::None) { true } + else { false } + } + _ => { false } + } + }, verbose: getopts::opt_present(matches, ~"verbose") } } @@ -113,6 +133,10 @@ pub fn log_config(config: config) { logv(c, fmt!("rustcflags: %s", opt_str(config.rustcflags))); logv(c, fmt!("jit: %b", config.jit)); logv(c, fmt!("newrt: %b", config.newrt)); + logv(c, fmt!("host: %s", config.host)); + logv(c, fmt!("target: %s", config.target)); + logv(c, fmt!("adb_path: %s", config.adb_path)); + logv(c, fmt!("flag_runnable: %b", config.flag_runnable)); logv(c, fmt!("verbose: %b", config.verbose)); logv(c, fmt!("\n")); } diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index fef4cabf7fd6d..4b07835163c00 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -77,8 +77,10 @@ fn run_rfail_test(config: config, props: TestProps, testfile: &Path) { fatal_ProcRes(~"run-fail test isn't valgrind-clean!", ProcRes); } - check_correct_failure_status(ProcRes); - check_error_patterns(props, testfile, ProcRes); + if (config.flag_runnable) { + check_correct_failure_status(ProcRes); + check_error_patterns(props, testfile, ProcRes); + } } fn check_correct_failure_status(ProcRes: ProcRes) { @@ -483,10 +485,96 @@ fn exec_compiled_test(config: config, props: TestProps, props.exec_env }; - compose_and_run(config, testfile, - make_run_args(config, props, testfile), - env, - config.run_lib_path, None) + if (config.host == config.target) { + compose_and_run(config, testfile, + make_run_args(config, props, testfile), + env, + config.run_lib_path, None) + } + else { + let args = make_run_args(config, props, testfile); + let cmdline = make_cmdline(~"", args.prog, args.args); + + let defaultRes = match config.mode { + mode_run_fail => ProcRes {status: 101, stdout: ~"", stderr: ~"", cmdline: cmdline}, + _ => ProcRes {status: 0, stdout: ~"", stderr: ~"", cmdline: cmdline} + }; + + match (config.target, config.flag_runnable) { + + (~"arm-linux-androideabi", true) => { + + // get bare program string + let mut tvec = ~[]; + let tstr = args.prog; + for str::each_split_char(tstr, '/') |ts| { tvec.push(ts.to_owned()) } + let prog_short = tvec.pop(); + + // copy to target + let copy_result = procsrv::run(~"", config.adb_path, + ~[~"push", args.prog, ~"/system/tmp"], + ~[(~"",~"")], Some(~"")); + + if config.verbose { + io::stdout().write_str(fmt!("push (%s) %s %s %s", + config.target, args.prog, + copy_result.out, copy_result.err)); + } + + // execute program + logv(config, fmt!("executing (%s) %s", config.target, cmdline)); + + // NOTE : adb shell dose not forward to each stdout and stderr of internal result + // but forward to stdout only + let mut newargs_out = ~[]; + let mut newargs_err = ~[]; + let subargs = args.args; + newargs_out.push(~"shell"); + newargs_err.push(~"shell"); + + let mut newcmd_out = ~""; + let mut newcmd_err = ~""; + newcmd_out.push_str(~"LD_LIBRARY_PATH=/system/tmp; "); + newcmd_err.push_str(~"LD_LIBRARY_PATH=/system/tmp; "); + newcmd_out.push_str(~"export LD_LIBRARY_PATH; "); + newcmd_err.push_str(~"export LD_LIBRARY_PATH; "); + newcmd_out.push_str(~"cd /system/tmp; "); + newcmd_err.push_str(~"cd /system/tmp; "); + newcmd_out.push_str("./"); + newcmd_err.push_str("./"); + newcmd_out.push_str(prog_short); + newcmd_err.push_str(prog_short); + + for vec::each(subargs) |tv| { + newcmd_out.push_str(" "); + newcmd_err.push_str(" "); + newcmd_out.push_str(tv.to_owned()); + newcmd_err.push_str(tv.to_owned()); + } + + newcmd_out.push_str(" 2>/dev/null"); + newcmd_err.push_str(" 1>/dev/null"); + + newargs_out.push(newcmd_out); + newargs_err.push(newcmd_err); + + let exe_result_out = procsrv::run(~"", config.adb_path, + newargs_out, ~[(~"",~"")], Some(~"")); + let exe_result_err = procsrv::run(~"", config.adb_path, + newargs_err, ~[(~"",~"")], Some(~"")); + + dump_output(config, testfile, exe_result_out.out, exe_result_err.out); + + match exe_result_err.out { + ~"" => ProcRes {status: exe_result_out.status, stdout: exe_result_out.out, + stderr: exe_result_err.out, cmdline: cmdline }, + _ => ProcRes {status: 101, stdout: exe_result_out.out, + stderr: exe_result_err.out, cmdline: cmdline } + } + } + _=> defaultRes + } + } } fn compose_and_run_compiler( @@ -516,6 +604,33 @@ fn compose_and_run_compiler( abs_ab.to_str()), auxres); } + if (config.host != config.target) + { + match (config.target, config.flag_runnable) { + + (~"arm-linux-androideabi", true) => { + + let tstr = aux_output_dir_name(config, testfile).to_str(); + + for os::list_dir_path(&Path(tstr)).each |file| { + + if (file.filetype() == Some(~".so")) { + + let copy_result = procsrv::run(~"", config.adb_path, + ~[~"push", file.to_str(), ~"/system/tmp"], + ~[(~"",~"")], Some(~"")); + + if config.verbose { + io::stdout().write_str(fmt!("push (%s) %s %s %s", + config.target, file.to_str(), + copy_result.out, copy_result.err)); + } + } + } + } + _=> () + } + } } compose_and_run(config, testfile, args, ~[], From 9d6544667e09259e0a4ccab72e0bd1687102f2c8 Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Wed, 1 May 2013 19:18:57 +0900 Subject: [PATCH 093/215] compiletest: fix to remove trailing whitespace --- src/compiletest/runtest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 4b07835163c00..ad128f4529c66 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -524,7 +524,7 @@ fn exec_compiled_test(config: config, props: TestProps, // execute program logv(config, fmt!("executing (%s) %s", config.target, cmdline)); - // NOTE : adb shell dose not forward to each stdout and stderr of internal result + // NOTE : adb shell dose not forward to each stdout and stderr of internal result // but forward to stdout only let mut newargs_out = ~[]; let mut newargs_err = ~[]; From 5ab33a297521c2d5885422bc1744f6d9dab8f3f7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2013 08:49:48 -0400 Subject: [PATCH 094/215] correct incorrect handling of overloaded operators, exposing various other bits of rot --- src/libcore/ptr.rs | 16 +-- .../middle/borrowck/gather_loans/mod.rs | 63 +++--------- src/librustc/middle/typeck/check/regionck.rs | 9 +- src/libstd/arc.rs | 8 +- src/libstd/rope.rs | 28 +++--- src/libstd/sort.rs | 97 ++++++++++--------- src/libstd/std.rc | 7 ++ .../borrowck-loan-in-overloaded-op.rs | 10 +- src/test/run-pass/auto-ref-slice-plus-ref.rs | 8 +- 9 files changed, 117 insertions(+), 129 deletions(-) diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 86b36834bbd6e..85e46a0feff6b 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -296,34 +296,34 @@ impl Ord for *const T { // Equality for region pointers #[cfg(notest)] -impl<'self,T:Eq> Eq for &'self const T { +impl<'self,T:Eq> Eq for &'self T { #[inline(always)] - fn eq(&self, other: & &'self const T) -> bool { + fn eq(&self, other: & &'self T) -> bool { return *(*self) == *(*other); } #[inline(always)] - fn ne(&self, other: & &'self const T) -> bool { + fn ne(&self, other: & &'self T) -> bool { return *(*self) != *(*other); } } // Comparison for region pointers #[cfg(notest)] -impl<'self,T:Ord> Ord for &'self const T { +impl<'self,T:Ord> Ord for &'self T { #[inline(always)] - fn lt(&self, other: & &'self const T) -> bool { + fn lt(&self, other: & &'self T) -> bool { *(*self) < *(*other) } #[inline(always)] - fn le(&self, other: & &'self const T) -> bool { + fn le(&self, other: & &'self T) -> bool { *(*self) <= *(*other) } #[inline(always)] - fn ge(&self, other: & &'self const T) -> bool { + fn ge(&self, other: & &'self T) -> bool { *(*self) >= *(*other) } #[inline(always)] - fn gt(&self, other: & &'self const T) -> bool { + fn gt(&self, other: & &'self T) -> bool { *(*self) > *(*other) } } diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 8a986a22d4c48..ecdf260bffffa 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -68,8 +68,7 @@ struct GatherLoanCtxt { id_range: id_range, all_loans: @mut ~[Loan], item_ub: ast::node_id, - repeating_ids: ~[ast::node_id], - ignore_adjustments: HashSet + repeating_ids: ~[ast::node_id] } pub fn gather_loans(bccx: @BorrowckCtxt, @@ -79,8 +78,7 @@ pub fn gather_loans(bccx: @BorrowckCtxt, id_range: id_range::max(), all_loans: @mut ~[], item_ub: body.node.id, - repeating_ids: ~[body.node.id], - ignore_adjustments: HashSet::new() + repeating_ids: ~[body.node.id] }; let v = visit::mk_vt(@visit::Visitor {visit_expr: gather_loans_in_expr, visit_block: gather_loans_in_block, @@ -147,13 +145,8 @@ fn gather_loans_in_expr(ex: @ast::expr, self.id_range.add(ex.callee_id); // If this expression is borrowed, have to ensure it remains valid: - { - let this = &mut *self; // FIXME(#5074) - if !this.ignore_adjustments.contains(&ex.id) { - for tcx.adjustments.find(&ex.id).each |&adjustments| { - this.guarantee_adjustments(ex, *adjustments); - } - } + for tcx.adjustments.find(&ex.id).each |&adjustments| { + self.guarantee_adjustments(ex, *adjustments); } // Special checks for various kinds of expressions: @@ -178,46 +171,20 @@ fn gather_loans_in_expr(ex: @ast::expr, visit::visit_expr(ex, self, vt); } - ast::expr_index(rcvr, _) | - ast::expr_binary(_, rcvr, _) | - ast::expr_unary(_, rcvr) | - ast::expr_assign_op(_, rcvr, _) + ast::expr_index(_, arg) | + ast::expr_binary(_, _, arg) if self.bccx.method_map.contains_key(&ex.id) => { - // Receivers in method calls are always passed by ref. - // - // Here, in an overloaded operator, the call is this expression, - // and hence the scope of the borrow is this call. - // - // FIX? / NOT REALLY---technically we should check the other - // argument and consider the argument mode. But how annoying. - // And this problem when goes away when argument modes are - // phased out. So I elect to leave this undone. - let scope_r = ty::re_scope(ex.id); - let rcvr_cmt = self.bccx.cat_expr(rcvr); - self.guarantee_valid(rcvr.id, rcvr.span, rcvr_cmt, m_imm, scope_r); - - // FIXME (#3387): Total hack: Ignore adjustments for the left-hand - // side. Their regions will be inferred to be too large. - self.ignore_adjustments.insert(rcvr.id); - - visit::visit_expr(ex, self, vt); + // Arguments in method calls are always passed by ref. + // + // Currently these do not use adjustments, so we have to + // hardcode this check here (note that the receiver DOES use + // adjustments). + let scope_r = ty::re_scope(ex.id); + let arg_cmt = self.bccx.cat_expr(arg); + self.guarantee_valid(arg.id, arg.span, arg_cmt, m_imm, scope_r); + visit::visit_expr(ex, self, vt); } - // FIXME--#3387 - // ast::expr_binary(_, lhs, rhs) => { - // // Universal comparison operators like ==, >=, etc - // // take their arguments by reference. - // let lhs_ty = ty::expr_ty(self.tcx(), lhs); - // if !ty::type_is_scalar(lhs_ty) { - // let scope_r = ty::re_scope(ex.id); - // let lhs_cmt = self.bccx.cat_expr(lhs); - // self.guarantee_valid(lhs_cmt, m_imm, scope_r); - // let rhs_cmt = self.bccx.cat_expr(rhs); - // self.guarantee_valid(rhs_cmt, m_imm, scope_r); - // } - // visit::visit_expr(ex, self, vt); - // } - // see explanation attached to the `root_ub` field: ast::expr_while(cond, ref body) => { // during the condition, can only root for the condition diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index fd19738b32110..1b0a22752a592 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -236,9 +236,16 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { // overloaded. See #3511. let tcx = rcx.fcx.tcx(); match expr.node { + // You'd think that x += y where `+=` is overloaded would be a + // cleanup scope. You'd be... kind of right. In fact the + // handling of `+=` and friends in trans for overloaded + // operators is a hopeless mess and I can't figure out how to + // represent it. - ndm + // + // ast::expr_assign_op(*) | + ast::expr_index(*) | ast::expr_binary(*) | - ast::expr_assign_op(*) | ast::expr_unary(*) if has_method_map => { tcx.region_maps.record_cleanup_scope(expr.id); } diff --git a/src/libstd/arc.rs b/src/libstd/arc.rs index 027bf93b4814f..98d7a01b928b0 100644 --- a/src/libstd/arc.rs +++ b/src/libstd/arc.rs @@ -598,8 +598,8 @@ mod tests { let arc = ~RWARC(1); let arc2 = (*arc).clone(); do task::try || { - do arc2.write_downgrade |write_mode| { - do (&write_mode).write |one| { + do arc2.write_downgrade |mut write_mode| { + do write_mode.write |one| { assert!(*one == 2); } } @@ -733,8 +733,8 @@ mod tests { } // Downgrader (us) - do arc.write_downgrade |write_mode| { - do (&write_mode).write_cond |state, cond| { + do arc.write_downgrade |mut write_mode| { + do write_mode.write_cond |state, cond| { wc1.send(()); // send to another writer who will wake us up while *state == 0 { cond.wait(); diff --git a/src/libstd/rope.rs b/src/libstd/rope.rs index 1292d2a858559..93364f8a319ee 100644 --- a/src/libstd/rope.rs +++ b/src/libstd/rope.rs @@ -1256,22 +1256,24 @@ mod tests { match (r) { node::Empty => return ~"", node::Content(x) => { - let str = @mut ~""; - fn aux(str: @mut ~str, node: @node::Node) { + let mut str = ~""; + fn aux(str: &mut ~str, node: @node::Node) { match (*node) { - node::Leaf(x) => { - *str += str::slice( - *x.content, x.byte_offset, - x.byte_offset + x.byte_len).to_owned(); - } - node::Concat(ref x) => { - aux(str, x.left); - aux(str, x.right); - } + node::Leaf(x) => { + str::push_str( + str, + str::slice( + *x.content, x.byte_offset, + x.byte_offset + x.byte_len)); + } + node::Concat(ref x) => { + aux(str, x.left); + aux(str, x.right); + } } } - aux(str, x); - return *str + aux(&mut str, x); + return str } } } diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index f3d30ecd5cdf1..119b47c904e8e 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -22,12 +22,12 @@ type Le<'self, T> = &'self fn(v1: &T, v2: &T) -> bool; * Has worst case O(n log n) performance, best case O(n), but * is not space efficient. This is a stable sort. */ -pub fn merge_sort(v: &const [T], le: Le) -> ~[T] { +pub fn merge_sort(v: &[T], le: Le) -> ~[T] { type Slice = (uint, uint); return merge_sort_(v, (0u, len(v)), le); - fn merge_sort_(v: &const [T], slice: Slice, le: Le) + fn merge_sort_(v: &[T], slice: Slice, le: Le) -> ~[T] { let begin = slice.first(); let end = slice.second(); @@ -179,7 +179,7 @@ fn qsort3(arr: &mut [T], left: int, right: int) { */ pub fn quick_sort3(arr: &mut [T]) { if arr.len() <= 1 { return; } - let len = arr.len() - 1; // FIXME(#5074) nested calls + let len = arr.len(); // FIXME(#5074) nested calls qsort3(arr, 0, (len - 1) as int); } @@ -263,7 +263,7 @@ fn binarysort(array: &mut [T], start: uint) { assert!(left == right); let n = start-left; - copy_vec(array, left+1, array, left, n); + shift_vec(array, left+1, left, n); array[left] = pivot; start += 1; } @@ -309,8 +309,8 @@ fn count_run_ascending(array: &mut [T]) -> uint { return run; } -fn gallop_left(key: &const T, - array: &const [T], +fn gallop_left(key: &T, + array: &[T], hint: uint) -> uint { let size = array.len(); @@ -360,8 +360,8 @@ fn gallop_left(key: &const T, return ofs; } -fn gallop_right(key: &const T, - array: &const [T], +fn gallop_right(key: &T, + array: &[T], hint: uint) -> uint { let size = array.len(); @@ -457,15 +457,15 @@ impl MergeState { } let k = { // constrain lifetime of slice below - let slice = vec::mut_slice(array, b1, b1+l1); - gallop_right(&const array[b2], slice, 0) + let slice = vec::slice(array, b1, b1+l1); + gallop_right(&array[b2], slice, 0) }; b1 += k; l1 -= k; if l1 != 0 { let l2 = { // constrain lifetime of slice below - let slice = vec::mut_slice(array, b2, b2+l2); - gallop_left(&const array[b1+l1-1],slice,l2-1) + let slice = vec::slice(array, b2, b2+l2); + gallop_left(&array[b1+l1-1],slice,l2-1) }; if l2 > 0 { if l1 <= l2 { @@ -497,11 +497,11 @@ impl MergeState { dest += 1; c2 += 1; len2 -= 1; if len2 == 0 { - copy_vec(array, dest, tmp, 0, len1); + copy_vec(array, dest, tmp.slice(0, len1)); return; } if len1 == 1 { - copy_vec(array, dest, array, c2, len2); + shift_vec(array, dest, c2, len2); array[dest+len2] <-> tmp[c1]; return; } @@ -539,10 +539,12 @@ impl MergeState { loop { assert!(len1 > 1 && len2 != 0); - let tmp_view = vec::const_slice(tmp, c1, c1+len1); - count1 = gallop_right(&const array[c2], tmp_view, 0); + count1 = { + let tmp_view = vec::slice(tmp, c1, c1+len1); + gallop_right(&array[c2], tmp_view, 0) + }; if count1 != 0 { - copy_vec(array, dest, tmp, c1, count1); + copy_vec(array, dest, tmp.slice(c1, c1+count1)); dest += count1; c1 += count1; len1 -= count1; if len1 <= 1 { break_outer = true; break; } } @@ -550,10 +552,12 @@ impl MergeState { dest += 1; c2 += 1; len2 -= 1; if len2 == 0 { break_outer = true; break; } - let tmp_view = vec::const_slice(array, c2, c2+len2); - count2 = gallop_left(&const tmp[c1], tmp_view, 0); + count2 = { + let tmp_view = vec::slice(array, c2, c2+len2); + gallop_left(&tmp[c1], tmp_view, 0) + }; if count2 != 0 { - copy_vec(array, dest, array, c2, count2); + shift_vec(array, dest, c2, count2); dest += count2; c2 += count2; len2 -= count2; if len2 == 0 { break_outer = true; break; } } @@ -573,14 +577,14 @@ impl MergeState { if len1 == 1 { assert!(len2 > 0); - copy_vec(array, dest, array, c2, len2); + shift_vec(array, dest, c2, len2); array[dest+len2] <-> tmp[c1]; } else if len1 == 0 { fail!(~"Comparison violates its contract!"); } else { assert!(len2 == 0); assert!(len1 > 1); - copy_vec(array, dest, tmp, c1, len1); + copy_vec(array, dest, tmp.slice(c1, c1+len1)); } } @@ -603,13 +607,13 @@ impl MergeState { dest -= 1; c1 -= 1; len1 -= 1; if len1 == 0 { - copy_vec(array, dest-(len2-1), tmp, 0, len2); + copy_vec(array, dest-(len2-1), tmp.slice(0, len2)); return; } if len2 == 1 { dest -= len1; c1 -= len1; - copy_vec(array, dest+1, array, c1+1, len1); + shift_vec(array, dest+1, c1+1, len1); array[dest] <-> tmp[c2]; return; } @@ -650,12 +654,12 @@ impl MergeState { { // constrain scope of tmp_view: let tmp_view = vec::mut_slice (array, base1, base1+len1); count1 = len1 - gallop_right( - &const tmp[c2], tmp_view, len1-1); + &tmp[c2], tmp_view, len1-1); } if count1 != 0 { dest -= count1; c1 -= count1; len1 -= count1; - copy_vec(array, dest+1, array, c1+1, count1); + shift_vec(array, dest+1, c1+1, count1); if len1 == 0 { break_outer = true; break; } } @@ -666,14 +670,14 @@ impl MergeState { let count2; { // constrain scope of tmp_view let tmp_view = vec::mut_slice(tmp, 0, len2); - count2 = len2 - gallop_left(&const array[c1], + count2 = len2 - gallop_left(&array[c1], tmp_view, len2-1); } if count2 != 0 { dest -= count2; c2 -= count2; len2 -= count2; - copy_vec(array, dest+1, tmp, c2+1, count2); + copy_vec(array, dest+1, tmp.slice(c2+1, c2+1+count2)); if len2 <= 1 { break_outer = true; break; } } array[dest] <-> array[c1]; @@ -695,14 +699,14 @@ impl MergeState { assert!(len1 > 0); dest -= len1; c1 -= len1; - copy_vec(array, dest+1, array, c1+1, len1); + shift_vec(array, dest+1, c1+1, len1); array[dest] <-> tmp[c2]; } else if len2 == 0 { fail!(~"Comparison violates its contract!"); } else { assert!(len1 == 0); assert!(len2 != 0); - copy_vec(array, dest-(len2-1), tmp, 0, len2); + copy_vec(array, dest-(len2-1), tmp.slice(0, len2)); } } @@ -738,21 +742,25 @@ impl MergeState { #[inline(always)] fn copy_vec(dest: &mut [T], s1: uint, - from: &const [T], - s2: uint, - len: uint) { - assert!(s1+len <= dest.len() && s2+len <= from.len()); - - let mut slice = ~[]; - for uint::range(s2, s2+len) |i| { - slice.push(from[i]); - } + from: &[T]) { + assert!(s1+from.len() <= dest.len()); - for slice.eachi |i, v| { + for from.eachi |i, v| { dest[s1+i] = *v; } } +#[inline(always)] +fn shift_vec(dest: &mut [T], + s1: uint, + s2: uint, + len: uint) { + assert!(s1+len <= dest.len()); + + let tmp = dest.slice(s2, s2+len).to_vec(); + copy_vec(dest, s1, tmp); +} + #[cfg(test)] mod test_qsort3 { use sort::*; @@ -764,8 +772,7 @@ mod test_qsort3 { quick_sort3::(v1); let mut i = 0; while i < len { - // debug!(v2[i]); - assert!((v2[i] == v1[i])); + assert_eq!(v2[i], v1[i]); i += 1; } } @@ -1036,7 +1043,7 @@ mod big_tests { tabulate_managed(low, high); } - fn multiplyVec(arr: &const [T], num: uint) -> ~[T] { + fn multiplyVec(arr: &[T], num: uint) -> ~[T] { let size = arr.len(); let res = do vec::from_fn(num) |i| { arr[i % size] @@ -1052,7 +1059,7 @@ mod big_tests { } fn tabulate_unique(lo: uint, hi: uint) { - fn isSorted(arr: &const [T]) { + fn isSorted(arr: &[T]) { for uint::range(0, arr.len()-1) |i| { if arr[i] > arr[i+1] { fail!(~"Array not sorted"); @@ -1123,7 +1130,7 @@ mod big_tests { } fn tabulate_managed(lo: uint, hi: uint) { - fn isSorted(arr: &const [@T]) { + fn isSorted(arr: &[@T]) { for uint::range(0, arr.len()-1) |i| { if arr[i] > arr[i+1] { fail!(~"Array not sorted"); diff --git a/src/libstd/std.rc b/src/libstd/std.rc index d9af8b111bba7..9d1ddb8ec544b 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -69,7 +69,14 @@ pub mod list; pub mod priority_queue; pub mod rope; pub mod smallintmap; + +#[cfg(stage0)] +#[path="sort_stage0.rs"] +pub mod sort; + +#[cfg(not(stage0))] pub mod sort; + pub mod dlist; pub mod treemap; diff --git a/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs b/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs index 482d1b6b8b617..0361213af2226 100644 --- a/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs +++ b/src/test/compile-fail/borrowck-loan-in-overloaded-op.rs @@ -8,18 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// xfail-test #3387 - struct foo(~uint); impl Add for foo { - fn add(f: &foo) -> foo { - foo(~(**self + **(*f))) + fn add(&self, f: &foo) -> foo { + foo(~(***self + **(*f))) } } fn main() { let x = foo(~3); - let _y = x + x; - //~^ ERROR moving out of immutable local variable prohibited due to outstanding loan + let _y = x + {x}; // the `{x}` forces a move to occur + //~^ ERROR cannot move out of `x` } diff --git a/src/test/run-pass/auto-ref-slice-plus-ref.rs b/src/test/run-pass/auto-ref-slice-plus-ref.rs index 1dc56132875d4..07629651e5605 100644 --- a/src/test/run-pass/auto-ref-slice-plus-ref.rs +++ b/src/test/run-pass/auto-ref-slice-plus-ref.rs @@ -17,13 +17,13 @@ trait MyIter { } impl<'self> MyIter for &'self [int] { - fn test_imm(&self) { assert!(self[0] == 1) } - fn test_const(&const self) { assert!(self[0] == 1) } + fn test_imm(&self) { assert_eq!(self[0], 1) } + fn test_const(&const self) { assert_eq!(self[0], 1) } } impl<'self> MyIter for &'self str { - fn test_imm(&self) { assert!(*self == "test") } - fn test_const(&const self) { assert!(*self == "test") } + fn test_imm(&self) { assert_eq!(*self, "test") } + fn test_const(&const self) { assert_eq!(self[0], 't') } } pub fn main() { From d96c65afc88b159b9ae76136f8d2695574e273f0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2013 08:50:04 -0400 Subject: [PATCH 095/215] keep old sort for stage0 --- src/libstd/sort_stage0.rs | 1239 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1239 insertions(+) create mode 100644 src/libstd/sort_stage0.rs diff --git a/src/libstd/sort_stage0.rs b/src/libstd/sort_stage0.rs new file mode 100644 index 0000000000000..f3d30ecd5cdf1 --- /dev/null +++ b/src/libstd/sort_stage0.rs @@ -0,0 +1,1239 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Sorting methods + +use core::cmp::{Eq, Ord}; +use core::vec::len; +use core::vec; + +type Le<'self, T> = &'self fn(v1: &T, v2: &T) -> bool; + +/** + * Merge sort. Returns a new vector containing the sorted list. + * + * Has worst case O(n log n) performance, best case O(n), but + * is not space efficient. This is a stable sort. + */ +pub fn merge_sort(v: &const [T], le: Le) -> ~[T] { + type Slice = (uint, uint); + + return merge_sort_(v, (0u, len(v)), le); + + fn merge_sort_(v: &const [T], slice: Slice, le: Le) + -> ~[T] { + let begin = slice.first(); + let end = slice.second(); + + let v_len = end - begin; + if v_len == 0 { return ~[]; } + if v_len == 1 { return ~[v[begin]]; } + + let mid = v_len / 2 + begin; + let a = (begin, mid); + let b = (mid, end); + return merge(le, merge_sort_(v, a, le), merge_sort_(v, b, le)); + } + + fn merge(le: Le, a: &[T], b: &[T]) -> ~[T] { + let mut rs = vec::with_capacity(len(a) + len(b)); + let a_len = len(a); + let mut a_ix = 0; + let b_len = len(b); + let mut b_ix = 0; + while a_ix < a_len && b_ix < b_len { + if le(&a[a_ix], &b[b_ix]) { + rs.push(a[a_ix]); + a_ix += 1; + } else { rs.push(b[b_ix]); b_ix += 1; } + } + rs.push_all(vec::slice(a, a_ix, a_len)); + rs.push_all(vec::slice(b, b_ix, b_len)); + rs + } +} + +#[cfg(stage0)] +fn part(arr: &mut [T], left: uint, + right: uint, pivot: uint, compare_func: Le) -> uint { + arr[pivot] <-> arr[right]; + let mut storage_index: uint = left; + let mut i: uint = left; + while i < right { + let a: &mut T = &mut arr[i]; + let b: &mut T = &mut arr[right]; + if compare_func(a, b) { + arr[i] <-> arr[storage_index]; + storage_index += 1; + } + i += 1; + } + arr[storage_index] <-> arr[right]; + return storage_index; +} + +#[cfg(not(stage0))] +fn part(arr: &mut [T], left: uint, + right: uint, pivot: uint, compare_func: Le) -> uint { + arr[pivot] <-> arr[right]; + let mut storage_index: uint = left; + let mut i: uint = left; + while i < right { + if compare_func(&arr[i], &arr[right]) { + arr[i] <-> arr[storage_index]; + storage_index += 1; + } + i += 1; + } + arr[storage_index] <-> arr[right]; + return storage_index; +} + +fn qsort(arr: &mut [T], left: uint, + right: uint, compare_func: Le) { + if right > left { + let pivot = (left + right) / 2u; + let new_pivot = part::(arr, left, right, pivot, compare_func); + if new_pivot != 0u { + // Need to do this check before recursing due to overflow + qsort::(arr, left, new_pivot - 1u, compare_func); + } + qsort::(arr, new_pivot + 1u, right, compare_func); + } +} + +/** + * Quicksort. Sorts a mut vector in place. + * + * Has worst case O(n^2) performance, average case O(n log n). + * This is an unstable sort. + */ +pub fn quick_sort(arr: &mut [T], compare_func: Le) { + if len::(arr) == 0u { return; } + qsort::(arr, 0u, len::(arr) - 1u, compare_func); +} + +fn qsort3(arr: &mut [T], left: int, right: int) { + if right <= left { return; } + let v: T = arr[right]; + let mut i: int = left - 1; + let mut j: int = right; + let mut p: int = i; + let mut q: int = j; + loop { + i += 1; + while arr[i] < v { i += 1; } + j -= 1; + while v < arr[j] { + if j == left { break; } + j -= 1; + } + if i >= j { break; } + arr[i] <-> arr[j]; + if arr[i] == v { + p += 1; + arr[p] <-> arr[i]; + } + if v == arr[j] { + q -= 1; + arr[j] <-> arr[q]; + } + } + arr[i] <-> arr[right]; + j = i - 1; + i += 1; + let mut k: int = left; + while k < p { + arr[k] <-> arr[j]; + k += 1; + j -= 1; + if k == len::(arr) as int { break; } + } + k = right - 1; + while k > q { + arr[i] <-> arr[k]; + k -= 1; + i += 1; + if k == 0 { break; } + } + qsort3::(arr, left, j); + qsort3::(arr, i, right); +} + +/** + * Fancy quicksort. Sorts a mut vector in place. + * + * Based on algorithm presented by ~[Sedgewick and Bentley] + * (http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf). + * According to these slides this is the algorithm of choice for + * 'randomly ordered keys, abstract compare' & 'small number of key values'. + * + * This is an unstable sort. + */ +pub fn quick_sort3(arr: &mut [T]) { + if arr.len() <= 1 { return; } + let len = arr.len() - 1; // FIXME(#5074) nested calls + qsort3(arr, 0, (len - 1) as int); +} + +pub trait Sort { + fn qsort(self); +} + +impl<'self, T:Copy + Ord + Eq> Sort for &'self mut [T] { + fn qsort(self) { quick_sort3(self); } +} + +static MIN_MERGE: uint = 64; +static MIN_GALLOP: uint = 7; +static INITIAL_TMP_STORAGE: uint = 128; + +pub fn tim_sort(array: &mut [T]) { + let size = array.len(); + if size < 2 { + return; + } + + if size < MIN_MERGE { + let init_run_len = count_run_ascending(array); + binarysort(array, init_run_len); + return; + } + + let mut ms = MergeState(); + let min_run = min_run_length(size); + + let mut idx = 0; + let mut remaining = size; + loop { + let run_len: uint = { + // This scope contains the slice `arr` here: + let arr = vec::mut_slice(array, idx, size); + let mut run_len: uint = count_run_ascending(arr); + + if run_len < min_run { + let force = if remaining <= min_run {remaining} else {min_run}; + let slice = vec::mut_slice(arr, 0, force); + binarysort(slice, run_len); + run_len = force; + } + + run_len + }; + + ms.push_run(idx, run_len); + ms.merge_collapse(array); + + idx += run_len; + remaining -= run_len; + if remaining == 0 { break; } + } + + ms.merge_force_collapse(array); +} + +fn binarysort(array: &mut [T], start: uint) { + let size = array.len(); + let mut start = start; + assert!(start <= size); + + if start == 0 { start += 1; } + + while start < size { + let pivot = array[start]; + let mut left = 0; + let mut right = start; + assert!(left <= right); + + while left < right { + let mid = (left + right) >> 1; + if pivot < array[mid] { + right = mid; + } else { + left = mid+1; + } + } + assert!(left == right); + let n = start-left; + + copy_vec(array, left+1, array, left, n); + array[left] = pivot; + start += 1; + } +} + +// Reverse the order of elements in a slice, in place +fn reverse_slice(v: &mut [T], start: uint, end:uint) { + let mut i = start; + while i < end / 2 { + v[i] <-> v[end - i - 1]; + i += 1; + } +} + +fn min_run_length(n: uint) -> uint { + let mut n = n; + let mut r = 0; // becomes 1 if any 1 bits are shifted off + + while n >= MIN_MERGE { + r |= n & 1; + n >>= 1; + } + return n + r; +} + +fn count_run_ascending(array: &mut [T]) -> uint { + let size = array.len(); + assert!(size > 0); + if size == 1 { return 1; } + + let mut run = 2; + if array[1] < array[0] { + while run < size && array[run] < array[run-1] { + run += 1; + } + reverse_slice(array, 0, run); + } else { + while run < size && array[run] >= array[run-1] { + run += 1; + } + } + + return run; +} + +fn gallop_left(key: &const T, + array: &const [T], + hint: uint) + -> uint { + let size = array.len(); + assert!(size != 0 && hint < size); + + let mut last_ofs = 0; + let mut ofs = 1; + + if *key > array[hint] { + // Gallop right until array[hint+last_ofs] < key <= array[hint+ofs] + let max_ofs = size - hint; + while ofs < max_ofs && *key > array[hint+ofs] { + last_ofs = ofs; + ofs = (ofs << 1) + 1; + if ofs < last_ofs { ofs = max_ofs; } // uint overflow guard + } + if ofs > max_ofs { ofs = max_ofs; } + + last_ofs += hint; + ofs += hint; + } else { + let max_ofs = hint + 1; + while ofs < max_ofs && *key <= array[hint-ofs] { + last_ofs = ofs; + ofs = (ofs << 1) + 1; + if ofs < last_ofs { ofs = max_ofs; } // uint overflow guard + } + + if ofs > max_ofs { ofs = max_ofs; } + + let tmp = last_ofs; + last_ofs = hint - ofs; + ofs = hint - tmp; + } + assert!((last_ofs < ofs || last_ofs+1 < ofs+1) && ofs <= size); + + last_ofs += 1; + while last_ofs < ofs { + let m = last_ofs + ((ofs - last_ofs) >> 1); + if *key > array[m] { + last_ofs = m+1; + } else { + ofs = m; + } + } + assert!(last_ofs == ofs); + return ofs; +} + +fn gallop_right(key: &const T, + array: &const [T], + hint: uint) + -> uint { + let size = array.len(); + assert!(size != 0 && hint < size); + + let mut last_ofs = 0; + let mut ofs = 1; + + if *key >= array[hint] { + // Gallop right until array[hint+last_ofs] <= key < array[hint+ofs] + let max_ofs = size - hint; + while ofs < max_ofs && *key >= array[hint+ofs] { + last_ofs = ofs; + ofs = (ofs << 1) + 1; + if ofs < last_ofs { ofs = max_ofs; } + } + if ofs > max_ofs { ofs = max_ofs; } + + last_ofs += hint; + ofs += hint; + } else { + // Gallop left until array[hint-ofs] <= key < array[hint-last_ofs] + let max_ofs = hint + 1; + while ofs < max_ofs && *key < array[hint-ofs] { + last_ofs = ofs; + ofs = (ofs << 1) + 1; + if ofs < last_ofs { ofs = max_ofs; } + } + if ofs > max_ofs { ofs = max_ofs; } + + let tmp = last_ofs; + last_ofs = hint - ofs; + ofs = hint - tmp; + } + + assert!((last_ofs < ofs || last_ofs+1 < ofs+1) && ofs <= size); + + last_ofs += 1; + while last_ofs < ofs { + let m = last_ofs + ((ofs - last_ofs) >> 1); + + if *key >= array[m] { + last_ofs = m + 1; + } else { + ofs = m; + } + } + assert!(last_ofs == ofs); + return ofs; +} + +struct RunState { + base: uint, + len: uint, +} + +struct MergeState { + min_gallop: uint, + runs: ~[RunState], +} + +// Fixme (#3853) Move into MergeState +fn MergeState() -> MergeState { + MergeState { + min_gallop: MIN_GALLOP, + runs: ~[], + } +} + +impl MergeState { + fn push_run(&mut self, run_base: uint, run_len: uint) { + let tmp = RunState{base: run_base, len: run_len}; + self.runs.push(tmp); + } + + fn merge_at(&mut self, n: uint, array: &mut [T]) { + let size = self.runs.len(); + assert!(size >= 2); + assert!(n == size-2 || n == size-3); + + let mut b1 = self.runs[n].base; + let mut l1 = self.runs[n].len; + let b2 = self.runs[n+1].base; + let l2 = self.runs[n+1].len; + + assert!(l1 > 0 && l2 > 0); + assert!(b1 + l1 == b2); + + self.runs[n].len = l1 + l2; + if n == size-3 { + self.runs[n+1].base = self.runs[n+2].base; + self.runs[n+1].len = self.runs[n+2].len; + } + + let k = { // constrain lifetime of slice below + let slice = vec::mut_slice(array, b1, b1+l1); + gallop_right(&const array[b2], slice, 0) + }; + b1 += k; + l1 -= k; + if l1 != 0 { + let l2 = { // constrain lifetime of slice below + let slice = vec::mut_slice(array, b2, b2+l2); + gallop_left(&const array[b1+l1-1],slice,l2-1) + }; + if l2 > 0 { + if l1 <= l2 { + self.merge_lo(array, b1, l1, b2, l2); + } else { + self.merge_hi(array, b1, l1, b2, l2); + } + } + } + self.runs.pop(); + } + + fn merge_lo(&mut self, array: &mut [T], base1: uint, len1: uint, + base2: uint, len2: uint) { + assert!(len1 != 0 && len2 != 0 && base1+len1 == base2); + + let mut tmp = ~[]; + for uint::range(base1, base1+len1) |i| { + tmp.push(array[i]); + } + + let mut c1 = 0; + let mut c2 = base2; + let mut dest = base1; + let mut len1 = len1; + let mut len2 = len2; + + array[dest] <-> array[c2]; + dest += 1; c2 += 1; len2 -= 1; + + if len2 == 0 { + copy_vec(array, dest, tmp, 0, len1); + return; + } + if len1 == 1 { + copy_vec(array, dest, array, c2, len2); + array[dest+len2] <-> tmp[c1]; + return; + } + + let mut min_gallop = self.min_gallop; + loop { + let mut count1 = 0; + let mut count2 = 0; + let mut break_outer = false; + + loop { + assert!(len1 > 1 && len2 != 0); + if array[c2] < tmp[c1] { + array[dest] <-> array[c2]; + dest += 1; c2 += 1; len2 -= 1; + count2 += 1; count1 = 0; + if len2 == 0 { + break_outer = true; + } + } else { + array[dest] <-> tmp[c1]; + dest += 1; c1 += 1; len1 -= 1; + count1 += 1; count2 = 0; + if len1 == 1 { + break_outer = true; + } + } + if break_outer || ((count1 | count2) >= min_gallop) { + break; + } + } + if break_outer { break; } + + // Start to gallop + loop { + assert!(len1 > 1 && len2 != 0); + + let tmp_view = vec::const_slice(tmp, c1, c1+len1); + count1 = gallop_right(&const array[c2], tmp_view, 0); + if count1 != 0 { + copy_vec(array, dest, tmp, c1, count1); + dest += count1; c1 += count1; len1 -= count1; + if len1 <= 1 { break_outer = true; break; } + } + array[dest] <-> array[c2]; + dest += 1; c2 += 1; len2 -= 1; + if len2 == 0 { break_outer = true; break; } + + let tmp_view = vec::const_slice(array, c2, c2+len2); + count2 = gallop_left(&const tmp[c1], tmp_view, 0); + if count2 != 0 { + copy_vec(array, dest, array, c2, count2); + dest += count2; c2 += count2; len2 -= count2; + if len2 == 0 { break_outer = true; break; } + } + array[dest] <-> tmp[c1]; + dest += 1; c1 += 1; len1 -= 1; + if len1 == 1 { break_outer = true; break; } + min_gallop -= 1; + if !(count1 >= MIN_GALLOP || count2 >= MIN_GALLOP) { + break; + } + } + if break_outer { break; } + if min_gallop < 0 { min_gallop = 0; } + min_gallop += 2; // Penalize for leaving gallop + } + self.min_gallop = if min_gallop < 1 { 1 } else { min_gallop }; + + if len1 == 1 { + assert!(len2 > 0); + copy_vec(array, dest, array, c2, len2); + array[dest+len2] <-> tmp[c1]; + } else if len1 == 0 { + fail!(~"Comparison violates its contract!"); + } else { + assert!(len2 == 0); + assert!(len1 > 1); + copy_vec(array, dest, tmp, c1, len1); + } + } + + fn merge_hi(&mut self, array: &mut [T], base1: uint, len1: uint, + base2: uint, len2: uint) { + assert!(len1 != 1 && len2 != 0 && base1 + len1 == base2); + + let mut tmp = ~[]; + for uint::range(base2, base2+len2) |i| { + tmp.push(array[i]); + } + + let mut c1 = base1 + len1 - 1; + let mut c2 = len2 - 1; + let mut dest = base2 + len2 - 1; + let mut len1 = len1; + let mut len2 = len2; + + array[dest] <-> array[c1]; + dest -= 1; c1 -= 1; len1 -= 1; + + if len1 == 0 { + copy_vec(array, dest-(len2-1), tmp, 0, len2); + return; + } + if len2 == 1 { + dest -= len1; + c1 -= len1; + copy_vec(array, dest+1, array, c1+1, len1); + array[dest] <-> tmp[c2]; + return; + } + + let mut min_gallop = self.min_gallop; + loop { + let mut count1 = 0; + let mut count2 = 0; + let mut break_outer = false; + + loop { + assert!(len1 != 0 && len2 > 1); + if tmp[c2] < array[c1] { + array[dest] <-> array[c1]; + dest -= 1; c1 -= 1; len1 -= 1; + count1 += 1; count2 = 0; + if len1 == 0 { + break_outer = true; + } + } else { + array[dest] <-> tmp[c2]; + dest -= 1; c2 -= 1; len2 -= 1; + count2 += 1; count1 = 0; + if len2 == 1 { + break_outer = true; + } + } + if break_outer || ((count1 | count2) >= min_gallop) { + break; + } + } + if break_outer { break; } + + // Start to gallop + loop { + assert!(len2 > 1 && len1 != 0); + + { // constrain scope of tmp_view: + let tmp_view = vec::mut_slice (array, base1, base1+len1); + count1 = len1 - gallop_right( + &const tmp[c2], tmp_view, len1-1); + } + + if count1 != 0 { + dest -= count1; c1 -= count1; len1 -= count1; + copy_vec(array, dest+1, array, c1+1, count1); + if len1 == 0 { break_outer = true; break; } + } + + array[dest] <-> tmp[c2]; + dest -= 1; c2 -= 1; len2 -= 1; + if len2 == 1 { break_outer = true; break; } + + let count2; + { // constrain scope of tmp_view + let tmp_view = vec::mut_slice(tmp, 0, len2); + count2 = len2 - gallop_left(&const array[c1], + tmp_view, + len2-1); + } + + if count2 != 0 { + dest -= count2; c2 -= count2; len2 -= count2; + copy_vec(array, dest+1, tmp, c2+1, count2); + if len2 <= 1 { break_outer = true; break; } + } + array[dest] <-> array[c1]; + dest -= 1; c1 -= 1; len1 -= 1; + if len1 == 0 { break_outer = true; break; } + min_gallop -= 1; + if !(count1 >= MIN_GALLOP || count2 >= MIN_GALLOP) { + break; + } + } + + if break_outer { break; } + if min_gallop < 0 { min_gallop = 0; } + min_gallop += 2; // Penalize for leaving gallop + } + self.min_gallop = if min_gallop < 1 { 1 } else { min_gallop }; + + if len2 == 1 { + assert!(len1 > 0); + dest -= len1; + c1 -= len1; + copy_vec(array, dest+1, array, c1+1, len1); + array[dest] <-> tmp[c2]; + } else if len2 == 0 { + fail!(~"Comparison violates its contract!"); + } else { + assert!(len1 == 0); + assert!(len2 != 0); + copy_vec(array, dest-(len2-1), tmp, 0, len2); + } + } + + fn merge_collapse(&mut self, array: &mut [T]) { + while self.runs.len() > 1 { + let mut n = self.runs.len()-2; + if n > 0 && + self.runs[n-1].len <= self.runs[n].len + self.runs[n+1].len + { + if self.runs[n-1].len < self.runs[n+1].len { n -= 1; } + } else if self.runs[n].len <= self.runs[n+1].len { + /* keep going */ + } else { + break; + } + self.merge_at(n, array); + } + } + + fn merge_force_collapse(&mut self, array: &mut [T]) { + while self.runs.len() > 1 { + let mut n = self.runs.len()-2; + if n > 0 { + if self.runs[n-1].len < self.runs[n+1].len { + n -= 1; + } + } + self.merge_at(n, array); + } + } +} + +#[inline(always)] +fn copy_vec(dest: &mut [T], + s1: uint, + from: &const [T], + s2: uint, + len: uint) { + assert!(s1+len <= dest.len() && s2+len <= from.len()); + + let mut slice = ~[]; + for uint::range(s2, s2+len) |i| { + slice.push(from[i]); + } + + for slice.eachi |i, v| { + dest[s1+i] = *v; + } +} + +#[cfg(test)] +mod test_qsort3 { + use sort::*; + + use core::vec; + + fn check_sort(v1: &mut [int], v2: &mut [int]) { + let len = vec::len::(v1); + quick_sort3::(v1); + let mut i = 0; + while i < len { + // debug!(v2[i]); + assert!((v2[i] == v1[i])); + i += 1; + } + } + + #[test] + fn test() { + { + let mut v1 = ~[3, 7, 4, 5, 2, 9, 5, 8]; + let mut v2 = ~[2, 3, 4, 5, 5, 7, 8, 9]; + check_sort(v1, v2); + } + { + let mut v1 = ~[1, 1, 1]; + let mut v2 = ~[1, 1, 1]; + check_sort(v1, v2); + } + { + let mut v1: ~[int] = ~[]; + let mut v2: ~[int] = ~[]; + check_sort(v1, v2); + } + { let mut v1 = ~[9]; let mut v2 = ~[9]; check_sort(v1, v2); } + { + let mut v1 = ~[9, 3, 3, 3, 9]; + let mut v2 = ~[3, 3, 3, 9, 9]; + check_sort(v1, v2); + } + } +} + +#[cfg(test)] +mod test_qsort { + use sort::*; + + use core::int; + use core::vec; + + fn check_sort(v1: &mut [int], v2: &mut [int]) { + let len = vec::len::(v1); + fn leual(a: &int, b: &int) -> bool { *a <= *b } + quick_sort::(v1, leual); + let mut i = 0u; + while i < len { + // debug!(v2[i]); + assert!((v2[i] == v1[i])); + i += 1; + } + } + + #[test] + fn test() { + { + let mut v1 = ~[3, 7, 4, 5, 2, 9, 5, 8]; + let mut v2 = ~[2, 3, 4, 5, 5, 7, 8, 9]; + check_sort(v1, v2); + } + { + let mut v1 = ~[1, 1, 1]; + let mut v2 = ~[1, 1, 1]; + check_sort(v1, v2); + } + { + let mut v1: ~[int] = ~[]; + let mut v2: ~[int] = ~[]; + check_sort(v1, v2); + } + { let mut v1 = ~[9]; let mut v2 = ~[9]; check_sort(v1, v2); } + { + let mut v1 = ~[9, 3, 3, 3, 9]; + let mut v2 = ~[3, 3, 3, 9, 9]; + check_sort(v1, v2); + } + } + + // Regression test for #750 + #[test] + fn test_simple() { + let mut names = ~[2, 1, 3]; + + let expected = ~[1, 2, 3]; + + do quick_sort(names) |x, y| { int::le(*x, *y) }; + + let immut_names = names; + + let pairs = vec::zip_slice(expected, immut_names); + for vec::each(pairs) |p| { + let (a, b) = *p; + debug!("%d %d", a, b); + assert!((a == b)); + } + } +} + +#[cfg(test)] +mod tests { + + use sort::*; + + use core::vec; + + fn check_sort(v1: &[int], v2: &[int]) { + let len = vec::len::(v1); + pub fn le(a: &int, b: &int) -> bool { *a <= *b } + let f = le; + let v3 = merge_sort::(v1, f); + let mut i = 0u; + while i < len { + debug!(v3[i]); + assert!((v3[i] == v2[i])); + i += 1; + } + } + + #[test] + fn test() { + { + let v1 = ~[3, 7, 4, 5, 2, 9, 5, 8]; + let v2 = ~[2, 3, 4, 5, 5, 7, 8, 9]; + check_sort(v1, v2); + } + { let v1 = ~[1, 1, 1]; let v2 = ~[1, 1, 1]; check_sort(v1, v2); } + { let v1:~[int] = ~[]; let v2:~[int] = ~[]; check_sort(v1, v2); } + { let v1 = ~[9]; let v2 = ~[9]; check_sort(v1, v2); } + { + let v1 = ~[9, 3, 3, 3, 9]; + let v2 = ~[3, 3, 3, 9, 9]; + check_sort(v1, v2); + } + } + + #[test] + fn test_merge_sort_mutable() { + pub fn le(a: &int, b: &int) -> bool { *a <= *b } + let mut v1 = ~[3, 2, 1]; + let v2 = merge_sort(v1, le); + assert!(v2 == ~[1, 2, 3]); + } + + #[test] + fn test_merge_sort_stability() { + // tjc: funny that we have to use parens + fn ile(x: &(&'static str), y: &(&'static str)) -> bool + { + // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use + // to_ascii_consume and to_str_consume to not do a unnecessary copy. + // (Actually, could just remove the to_str_* call, but needs an deriving(Ord) on + // Ascii) + let x = x.to_ascii().to_lower().to_str_ascii(); + let y = y.to_ascii().to_lower().to_str_ascii(); + x <= y + } + + let names1 = ~["joe bob", "Joe Bob", "Jack Brown", "JOE Bob", + "Sally Mae", "JOE BOB", "Alex Andy"]; + let names2 = ~["Alex Andy", "Jack Brown", "joe bob", "Joe Bob", + "JOE Bob", "JOE BOB", "Sally Mae"]; + let names3 = merge_sort(names1, ile); + assert!(names3 == names2); + } +} + +#[cfg(test)] +mod test_tim_sort { + use sort::tim_sort; + use core::rand::RngUtil; + + struct CVal { + val: float, + } + + impl Ord for CVal { + fn lt(&self, other: &CVal) -> bool { + let rng = rand::rng(); + if rng.gen::() > 0.995 { fail!(~"It's happening!!!"); } + (*self).val < other.val + } + fn le(&self, other: &CVal) -> bool { (*self).val <= other.val } + fn gt(&self, other: &CVal) -> bool { (*self).val > other.val } + fn ge(&self, other: &CVal) -> bool { (*self).val >= other.val } + } + + fn check_sort(v1: &mut [int], v2: &mut [int]) { + let len = vec::len::(v1); + tim_sort::(v1); + let mut i = 0u; + while i < len { + // debug!(v2[i]); + assert!((v2[i] == v1[i])); + i += 1u; + } + } + + #[test] + fn test() { + { + let mut v1 = ~[3, 7, 4, 5, 2, 9, 5, 8]; + let mut v2 = ~[2, 3, 4, 5, 5, 7, 8, 9]; + check_sort(v1, v2); + } + { + let mut v1 = ~[1, 1, 1]; + let mut v2 = ~[1, 1, 1]; + check_sort(v1, v2); + } + { + let mut v1: ~[int] = ~[]; + let mut v2: ~[int] = ~[]; + check_sort(v1, v2); + } + { let mut v1 = ~[9]; let mut v2 = ~[9]; check_sort(v1, v2); } + { + let mut v1 = ~[9, 3, 3, 3, 9]; + let mut v2 = ~[3, 3, 3, 9, 9]; + check_sort(v1, v2); + } + } + + #[test] + #[should_fail] + #[cfg(unix)] + fn crash_test() { + let rng = rand::rng(); + let mut arr = do vec::from_fn(1000) |_i| { + CVal { val: rng.gen() } + }; + + tim_sort(arr); + fail!(~"Guarantee the fail"); + } + + struct DVal { val: uint } + + impl Ord for DVal { + fn lt(&self, _x: &DVal) -> bool { true } + fn le(&self, _x: &DVal) -> bool { true } + fn gt(&self, _x: &DVal) -> bool { true } + fn ge(&self, _x: &DVal) -> bool { true } + } + + #[test] + fn test_bad_Ord_impl() { + let rng = rand::rng(); + let mut arr = do vec::from_fn(500) |_i| { + DVal { val: rng.gen() } + }; + + tim_sort(arr); + } +} + +#[cfg(test)] +mod big_tests { + use sort::*; + use core::rand::RngUtil; + + #[test] + fn test_unique() { + let low = 5; + let high = 10; + tabulate_unique(low, high); + } + + #[test] + fn test_managed() { + let low = 5; + let high = 10; + tabulate_managed(low, high); + } + + fn multiplyVec(arr: &const [T], num: uint) -> ~[T] { + let size = arr.len(); + let res = do vec::from_fn(num) |i| { + arr[i % size] + }; + res + } + + fn makeRange(n: uint) -> ~[uint] { + let one = do vec::from_fn(n) |i| { i }; + let mut two = copy one; + vec::reverse(two); + vec::append(two, one) + } + + fn tabulate_unique(lo: uint, hi: uint) { + fn isSorted(arr: &const [T]) { + for uint::range(0, arr.len()-1) |i| { + if arr[i] > arr[i+1] { + fail!(~"Array not sorted"); + } + } + } + + let rng = rand::rng(); + + for uint::range(lo, hi) |i| { + let n = 1 << i; + let mut arr: ~[float] = do vec::from_fn(n) |_i| { + rng.gen() + }; + + tim_sort(arr); // *sort + isSorted(arr); + + vec::reverse(arr); + tim_sort(arr); // \sort + isSorted(arr); + + tim_sort(arr); // /sort + isSorted(arr); + + for 3.times { + let i1 = rng.gen_uint_range(0, n); + let i2 = rng.gen_uint_range(0, n); + arr[i1] <-> arr[i2]; + } + tim_sort(arr); // 3sort + isSorted(arr); + + if n >= 10 { + let size = arr.len(); + let mut idx = 1; + while idx <= 10 { + arr[size-idx] = rng.gen(); + idx += 1; + } + } + tim_sort(arr); // +sort + isSorted(arr); + + for (n/100).times { + let idx = rng.gen_uint_range(0, n); + arr[idx] = rng.gen(); + } + tim_sort(arr); + isSorted(arr); + + let mut arr = if n > 4 { + let part = vec::slice(arr, 0, 4); + multiplyVec(part, n) + } else { arr }; + tim_sort(arr); // ~sort + isSorted(arr); + + let mut arr = vec::from_elem(n, -0.5); + tim_sort(arr); // =sort + isSorted(arr); + + let half = n / 2; + let mut arr = makeRange(half).map(|i| *i as float); + tim_sort(arr); // !sort + isSorted(arr); + } + } + + fn tabulate_managed(lo: uint, hi: uint) { + fn isSorted(arr: &const [@T]) { + for uint::range(0, arr.len()-1) |i| { + if arr[i] > arr[i+1] { + fail!(~"Array not sorted"); + } + } + } + + let rng = rand::rng(); + + for uint::range(lo, hi) |i| { + let n = 1 << i; + let arr: ~[@float] = do vec::from_fn(n) |_i| { + @rng.gen() + }; + let mut arr = arr; + + tim_sort(arr); // *sort + isSorted(arr); + + vec::reverse(arr); + tim_sort(arr); // \sort + isSorted(arr); + + tim_sort(arr); // /sort + isSorted(arr); + + for 3.times { + let i1 = rng.gen_uint_range(0, n); + let i2 = rng.gen_uint_range(0, n); + arr[i1] <-> arr[i2]; + } + tim_sort(arr); // 3sort + isSorted(arr); + + if n >= 10 { + let size = arr.len(); + let mut idx = 1; + while idx <= 10 { + arr[size-idx] = @rng.gen(); + idx += 1; + } + } + tim_sort(arr); // +sort + isSorted(arr); + + for (n/100).times { + let idx = rng.gen_uint_range(0, n); + arr[idx] = @rng.gen(); + } + tim_sort(arr); + isSorted(arr); + + let mut arr = if n > 4 { + let part = vec::slice(arr, 0, 4); + multiplyVec(part, n) + } else { arr }; + tim_sort(arr); // ~sort + isSorted(arr); + + let mut arr = vec::from_elem(n, @(-0.5)); + tim_sort(arr); // =sort + isSorted(arr); + + let half = n / 2; + let mut arr = makeRange(half).map(|i| @(*i as float)); + tim_sort(arr); // !sort + isSorted(arr); + } + } + + struct LVal<'self> { + val: uint, + key: &'self fn(@uint), + } + + #[unsafe_destructor] + impl<'self> Drop for LVal<'self> { + fn finalize(&self) { + let x = unsafe { task::local_data::local_data_get(self.key) }; + match x { + Some(@y) => { + unsafe { + task::local_data::local_data_set(self.key, @(y+1)); + } + } + _ => fail!(~"Expected key to work"), + } + } + } + + impl<'self> Ord for LVal<'self> { + fn lt<'a>(&self, other: &'a LVal<'self>) -> bool { + (*self).val < other.val + } + fn le<'a>(&self, other: &'a LVal<'self>) -> bool { + (*self).val <= other.val + } + fn gt<'a>(&self, other: &'a LVal<'self>) -> bool { + (*self).val > other.val + } + fn ge<'a>(&self, other: &'a LVal<'self>) -> bool { + (*self).val >= other.val + } + } +} + +// Local Variables: +// mode: rust; +// fill-column: 78; +// indent-tabs-mode: nil +// c-basic-offset: 4 +// buffer-file-coding-system: utf-8-unix +// End: From 84861101eca12942b42f36f8adb18cfc74515431 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2013 09:14:47 -0400 Subject: [PATCH 096/215] rustc: print out filename/line-number when a borrow fails --- src/libcore/unstable/lang.rs | 25 ++++++++++++++----- .../middle/borrowck/gather_loans/mod.rs | 1 - src/librustc/middle/trans/datum.rs | 20 +++++++++++---- src/librustc/middle/trans/expr.rs | 2 +- src/libsyntax/parse/parser.rs | 2 +- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index cf71b01aeaeeb..c5062f25ea540 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -53,7 +53,7 @@ pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! { #[lang="fail_bounds_check"] pub fn fail_bounds_check(file: *c_char, line: size_t, - index: size_t, len: size_t) { + index: size_t, len: size_t) { let msg = fmt!("index out of bounds: the len is %d but the index is %d", len as int, index as int); do str::as_buf(msg) |p, _len| { @@ -61,12 +61,10 @@ pub fn fail_bounds_check(file: *c_char, line: size_t, } } -pub fn fail_borrowed() { +pub fn fail_borrowed(file: *c_char, line: size_t) { let msg = "borrowed"; do str::as_buf(msg) |msg_p, _| { - do str::as_buf("???") |file_p, _| { - fail_(msg_p as *c_char, file_p as *c_char, 0); - } + fail_(msg_p as *c_char, file, line); } } @@ -160,12 +158,27 @@ pub unsafe fn return_to_mut(a: *u8) { } } +#[cfg(stage0)] #[lang="check_not_borrowed"] #[inline(always)] pub unsafe fn check_not_borrowed(a: *u8) { let a: *mut BoxRepr = transmute(a); if ((*a).header.ref_count & FROZEN_BIT) != 0 { - fail_borrowed(); + do str::as_buf("XXX") |file_p, _| { + fail_borrowed(file_p as *c_char, 0); + } + } +} + +#[cfg(not(stage0))] +#[lang="check_not_borrowed"] +#[inline(always)] +pub unsafe fn check_not_borrowed(a: *u8, + file: *c_char, + line: size_t) { + let a: *mut BoxRepr = transmute(a); + if ((*a).header.ref_count & FROZEN_BIT) != 0 { + fail_borrowed(file, line); } } diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index ecdf260bffffa..7ac6dfd3ec385 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -26,7 +26,6 @@ use middle::ty; use util::common::indenter; use util::ppaux::{Repr}; -use core::hashmap::HashSet; use syntax::ast::{m_const, m_imm, m_mutbl}; use syntax::ast; use syntax::ast_util::id_range; diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 705d443b1155d..03c81cad50e11 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -105,6 +105,7 @@ use util::ppaux::ty_to_str; use core::container::Set; // XXX: this should not be necessary use core::to_bytes; use syntax::ast; +use syntax::codemap::span; use syntax::parse::token::special_idents; #[deriving(Eq)] @@ -556,17 +557,24 @@ pub impl Datum { } } - fn perform_write_guard(&self, bcx: block) -> block { + fn perform_write_guard(&self, bcx: block, span: span) -> block { // Create scratch space, but do not root it. let llval = match self.mode { ByValue => self.val, ByRef => Load(bcx, self.val), }; + let loc = bcx.sess().parse_sess.cm.lookup_char_pos(span.lo); + let line = C_int(bcx.ccx(), loc.line as int); + let filename_cstr = C_cstr(bcx.ccx(), @/*bad*/copy loc.file.name); + let filename = PointerCast(bcx, filename_cstr, T_ptr(T_i8())); + callee::trans_lang_call( bcx, bcx.tcx().lang_items.check_not_borrowed_fn(), - ~[ PointerCast(bcx, llval, T_ptr(T_i8())) ], + ~[PointerCast(bcx, llval, T_ptr(T_i8())), + filename, + line], expr::Ignore) } @@ -621,6 +629,7 @@ pub impl Datum { fn try_deref(&self, bcx: block, // block wherein to generate insn's + span: span, // location where deref occurs expr_id: ast::node_id, // id of expr being deref'd derefs: uint, // number of times deref'd already is_auto: bool) // if true, only deref if auto-derefable @@ -645,7 +654,7 @@ pub impl Datum { // // (Note: write-guarded values are always boxes) let bcx = if ccx.maps.write_guard_map.contains(&key) { - self.perform_write_guard(bcx) + self.perform_write_guard(bcx, span) } else { bcx }; match ty::get(self.ty).sty { @@ -759,7 +768,7 @@ pub impl Datum { expr: @ast::expr, // the expression whose value is being deref'd derefs: uint) -> DatumBlock { - match self.try_deref(bcx, expr.id, derefs, false) { + match self.try_deref(bcx, expr.span, expr.id, derefs, false) { (Some(lvres), bcx) => DatumBlock { bcx: bcx, datum: lvres }, (None, _) => { bcx.ccx().sess.span_bug( @@ -769,6 +778,7 @@ pub impl Datum { } fn autoderef(&self, bcx: block, + span: span, expr_id: ast::node_id, max: uint) -> DatumBlock { @@ -783,7 +793,7 @@ pub impl Datum { let mut bcx = bcx; while derefs < max { derefs += 1u; - match datum.try_deref(bcx, expr_id, derefs, true) { + match datum.try_deref(bcx, span, expr_id, derefs, true) { (None, new_bcx) => { bcx = new_bcx; break } (Some(datum_deref), new_bcx) => { datum = datum_deref; diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index fa6f7802e7d50..bc44d7de98342 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -205,7 +205,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { if adj.autoderefs > 0 { let DatumBlock { bcx: new_bcx, datum: new_datum } = - datum.autoderef(bcx, expr.id, adj.autoderefs); + datum.autoderef(bcx, expr.span, expr.id, adj.autoderefs); datum = new_datum; bcx = new_bcx; } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1129e7b708ea2..1ee651ede7510 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3723,7 +3723,7 @@ pub impl Parser { first_item_attrs: ~[attribute]) -> foreign_mod { let ParsedItemsAndViewItems { - attrs_remaining: attrs_remaining, + attrs_remaining: _, view_items: view_items, items: _, foreign_items: foreign_items From 4af2d90af59bb5e28e5d114d8a6004d68fad3bd5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2013 10:29:47 -0400 Subject: [PATCH 097/215] add an option to debug borrows (RUST_DEBUG_BORROW) so you can find out where the offending borrow occurred. This ... still needs some work. --- src/libcore/rt/env.rs | 6 ++- src/libcore/unstable/lang.rs | 78 ++++++++++++++++++++++++++--- src/librustc/middle/trans/_match.rs | 2 +- src/librustc/middle/trans/datum.rs | 14 ++++-- src/librustc/middle/trans/expr.rs | 2 +- src/rt/rust_builtin.cpp | 14 ++++++ src/rt/rust_env.cpp | 2 + src/rt/rust_env.h | 1 + src/rt/rust_task.cpp | 11 ++++ src/rt/rust_task.h | 5 ++ 10 files changed, 121 insertions(+), 14 deletions(-) diff --git a/src/libcore/rt/env.rs b/src/libcore/rt/env.rs index 92e2ec51306e2..1f52cf77868a2 100644 --- a/src/libcore/rt/env.rs +++ b/src/libcore/rt/env.rs @@ -31,8 +31,10 @@ pub struct Environment { argc: c_int, /// The argv value passed to main argv: **c_char, - /// Print GC debugging info - debug_mem: bool + /// Print GC debugging info (true if env var RUST_DEBUG_MEM is set) + debug_mem: bool, + /// Track origin of `@mut` borrows (true if env var RUST_DEBUG_BORROWS is set) + debug_borrows: bool } /// Get the global environment settings diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index c5062f25ea540..0705be7cdefe5 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -17,6 +17,7 @@ use str; use sys; use unstable::exchange_alloc; use cast::transmute; +use task::rt::rust_get_task; #[allow(non_camel_case_types)] pub type rust_task = c_void; @@ -27,7 +28,8 @@ pub static FROZEN_BIT: uint = 0x80000000; pub static FROZEN_BIT: uint = 0x8000000000000000; pub mod rustrt { - use libc::{c_char, uintptr_t}; + use unstable::lang::rust_task; + use libc::{c_void, c_char, uintptr_t}; pub extern { #[rust_stack] @@ -43,6 +45,12 @@ pub mod rustrt { #[fast_ffi] unsafe fn rust_upcall_free_noswitch(ptr: *c_char); + + #[rust_stack] + fn rust_take_task_borrow_list(task: *rust_task) -> *c_void; + + #[rust_stack] + fn rust_set_task_borrow_list(task: *rust_task, map: *c_void); } } @@ -61,10 +69,50 @@ pub fn fail_bounds_check(file: *c_char, line: size_t, } } -pub fn fail_borrowed(file: *c_char, line: size_t) { - let msg = "borrowed"; - do str::as_buf(msg) |msg_p, _| { - fail_(msg_p as *c_char, file, line); +struct BorrowRecord { + box: *mut BoxRepr, + file: *c_char, + line: size_t +} + +fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { + unsafe { + let cur_task = rust_get_task(); + let mut borrow_list: ~[BorrowRecord] = { + let ptr = rustrt::rust_take_task_borrow_list(cur_task); + if ptr.is_null() { ~[] } else { transmute(ptr) } + }; + borrow_list = f(borrow_list); + rustrt::rust_set_task_borrow_list(cur_task, transmute(borrow_list)); + } +} + +pub fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { + if !::rt::env::get().debug_borrows { + let msg = "borrowed"; + do str::as_buf(msg) |msg_p, _| { + fail_(msg_p as *c_char, file, line); + } + } else { + do swap_task_borrow_list |borrow_list| { + let mut msg = ~"borrowed"; + let mut sep = " at "; + for borrow_list.each_reverse |entry| { + if entry.box == box { + str::push_str(&mut msg, sep); + let filename = unsafe { + str::raw::from_c_str(entry.file) + }; + str::push_str(&mut msg, filename); + str::push_str(&mut msg, fmt!(":%u", line as uint)); + sep = " and at "; + } + } + do str::as_buf(msg) |msg_p, _| { + fail_(msg_p as *c_char, file, line) + } + borrow_list + } } } @@ -140,6 +188,7 @@ pub unsafe fn local_free(ptr: *c_char) { rustrt::rust_upcall_free_noswitch(ptr); } +#[cfg(stage0)] #[lang="borrow_as_imm"] #[inline(always)] pub unsafe fn borrow_as_imm(a: *u8) { @@ -147,6 +196,21 @@ pub unsafe fn borrow_as_imm(a: *u8) { (*a).header.ref_count |= FROZEN_BIT; } +#[cfg(not(stage0))] +#[lang="borrow_as_imm"] +#[inline(always)] +pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) { + let a: *mut BoxRepr = transmute(a); + (*a).header.ref_count |= FROZEN_BIT; + if ::rt::env::get().debug_borrows { + do swap_task_borrow_list |borrow_list| { + let mut borrow_list = borrow_list; + borrow_list.push(BorrowRecord {box: a, file: file, line: line}); + borrow_list + } + } +} + #[lang="return_to_mut"] #[inline(always)] pub unsafe fn return_to_mut(a: *u8) { @@ -165,7 +229,7 @@ pub unsafe fn check_not_borrowed(a: *u8) { let a: *mut BoxRepr = transmute(a); if ((*a).header.ref_count & FROZEN_BIT) != 0 { do str::as_buf("XXX") |file_p, _| { - fail_borrowed(file_p as *c_char, 0); + fail_borrowed(a, file_p as *c_char, 0); } } } @@ -178,7 +242,7 @@ pub unsafe fn check_not_borrowed(a: *u8, line: size_t) { let a: *mut BoxRepr = transmute(a); if ((*a).header.ref_count & FROZEN_BIT) != 0 { - fail_borrowed(file, line); + fail_borrowed(a, file, line); } } diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 785bb3edc07cd..d7f9567c333d0 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -966,7 +966,7 @@ pub fn root_pats_as_necessary(bcx: block, let datum = Datum {val: val, ty: node_id_type(bcx, pat_id), mode: ByRef, source: ZeroMem}; - bcx = datum.root(bcx, root_info); + bcx = datum.root(bcx, br.pats[col].span, root_info); // If we kept going, we'd only re-root the same value, so // return now. return bcx; diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 03c81cad50e11..ae71a3e6c22c0 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -517,7 +517,7 @@ pub impl Datum { } } - fn root(&self, bcx: block, root_info: RootInfo) -> block { + fn root(&self, bcx: block, span: span, root_info: RootInfo) -> block { /*! * * In some cases, borrowck will decide that an @T/@[]/@str @@ -542,6 +542,12 @@ pub impl Datum { // If we need to freeze the box, do that now. if root_info.freeze.is_some() { // NOTE distinguish the two kinds of freezing here + + let loc = bcx.sess().parse_sess.cm.lookup_char_pos(span.lo); + let line = C_int(bcx.ccx(), loc.line as int); + let filename_cstr = C_cstr(bcx.ccx(), @/*bad*/copy loc.file.name); + let filename = PointerCast(bcx, filename_cstr, T_ptr(T_i8())); + callee::trans_lang_call( bcx, bcx.tcx().lang_items.borrow_as_imm_fn(), @@ -549,7 +555,9 @@ pub impl Datum { Load(bcx, PointerCast(bcx, scratch.val, - T_ptr(T_ptr(T_i8())))) + T_ptr(T_ptr(T_i8())))), + filename, + line ], expr::Ignore) } else { @@ -647,7 +655,7 @@ pub impl Datum { let key = root_map_key { id: expr_id, derefs: derefs }; let bcx = match ccx.maps.root_map.find(&key) { None => bcx, - Some(&root_info) => self.root(bcx, root_info) + Some(&root_info) => self.root(bcx, span, root_info) }; // Perform the write guard, if necessary. diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index bc44d7de98342..166b8bc01f856 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -828,7 +828,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { // at the end of the scope with id `scope_id`: let root_key = root_map_key { id: expr.id, derefs: 0u }; for bcx.ccx().maps.root_map.find(&root_key).each |&root_info| { - bcx = unrooted_datum.root(bcx, *root_info); + bcx = unrooted_datum.root(bcx, expr.span, *root_info); } return DatumBlock {bcx: bcx, datum: unrooted_datum}; diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index ee025a39ff472..197b8b36d2d4f 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -683,6 +683,20 @@ rust_task_local_data_atexit(rust_task *task, void (*cleanup_fn)(void *data)) { task->task_local_data_cleanup = cleanup_fn; } +// set/get/atexit task_borrow_list can run on the rust stack for speed. +extern "C" void * +rust_take_task_borrow_list(rust_task *task) { + void *r = task->borrow_list; + task->borrow_list = NULL; + return r; +} +extern "C" void +rust_set_task_borrow_list(rust_task *task, void *data) { + assert(task->borrow_list == NULL); + assert(data != NULL); + task->borrow_list = data; +} + extern "C" void task_clear_event_reject(rust_task *task) { task->clear_event_reject(); diff --git a/src/rt/rust_env.cpp b/src/rt/rust_env.cpp index 041b4efac52a2..e6fe35609ec93 100644 --- a/src/rt/rust_env.cpp +++ b/src/rt/rust_env.cpp @@ -24,6 +24,7 @@ #define RUST_SEED "RUST_SEED" #define RUST_POISON_ON_FREE "RUST_POISON_ON_FREE" #define RUST_DEBUG_MEM "RUST_DEBUG_MEM" +#define RUST_DEBUG_BORROWS "RUST_DEBUG_BORROWS" #if defined(__WIN32__) static int @@ -130,6 +131,7 @@ load_env(int argc, char **argv) { env->argc = argc; env->argv = argv; env->debug_mem = getenv(RUST_DEBUG_MEM) != NULL; + env->debug_borrows = getenv(RUST_DEBUG_BORROWS) != NULL; return env; } diff --git a/src/rt/rust_env.h b/src/rt/rust_env.h index df27f7674f265..322198bb031ff 100644 --- a/src/rt/rust_env.h +++ b/src/rt/rust_env.h @@ -28,6 +28,7 @@ struct rust_env { int argc; char **argv; rust_bool debug_mem; + rust_bool debug_borrows; }; rust_env* load_env(int argc, char **argv); diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp index e6293aa5c1de0..ea42936f2e51d 100644 --- a/src/rt/rust_task.cpp +++ b/src/rt/rust_task.cpp @@ -42,6 +42,7 @@ rust_task::rust_task(rust_sched_loop *sched_loop, rust_task_state state, total_stack_sz(0), task_local_data(NULL), task_local_data_cleanup(NULL), + borrow_list(NULL), state(state), cond(NULL), cond_name("none"), @@ -75,6 +76,16 @@ rust_task::delete_this() assert(ref_count == 0); // || // (ref_count == 1 && this == sched->root_task)); + if (borrow_list) { + // NOTE should free borrow_list from within rust code! + // If there is a pointer in there, it is a ~[BorrowRecord] pointer, + // which are currently allocated with LIBC malloc/free. But this is + // not really the right way to do this, we should be freeing this + // pointer from Rust code. + free(borrow_list); + borrow_list = NULL; + } + sched_loop->release_task(this); } diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index 4aa1199cabc3f..dc45c0439ea12 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -241,6 +241,11 @@ rust_task : public kernel_owned void *task_local_data; void (*task_local_data_cleanup)(void *data); + // Contains a ~[BorrowRecord] pointer, or NULL. + // + // Used by borrow management code in libcore/unstable/lang.rs. + void *borrow_list; + private: // Protects state, cond, cond_name From 5d79f94a2f74a0502f665c5eb432aa7231666392 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 30 Apr 2013 18:03:09 -0700 Subject: [PATCH 098/215] core: Remove use of deprecated `drop` --- src/libcore/core.rc | 1 - src/libcore/pipes.rs | 9 ++++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libcore/core.rc b/src/libcore/core.rc index f9a56f613d542..7ccf5cb6a9125 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -63,7 +63,6 @@ they contained the following prologue: #[warn(vecs_implicitly_copyable)]; #[deny(non_camel_case_types)]; #[allow(deprecated_mutable_fields)]; -#[allow(deprecated_drop)]; // Make core testable by not duplicating lang items. See #2912 #[cfg(test)] extern mod realcore(name = "core", vers = "0.7-pre"); diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 95b24d20a4bc2..82dc598c750eb 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -86,6 +86,7 @@ use cast::{forget, transmute, transmute_copy}; use either::{Either, Left, Right}; use kinds::Owned; use libc; +use ops::Drop; use option::{None, Option, Some}; use unstable::intrinsics; use ptr; @@ -395,11 +396,13 @@ pub fn try_recv(p: RecvPacketBuffered) let p_ = p.unwrap(); let p = unsafe { &*p_ }; - #[unsafe_destructor] struct DropState<'self> { p: &'self PacketHeader, + } - drop { + #[unsafe_destructor] + impl<'self> Drop for DropState<'self> { + fn finalize(&self) { unsafe { if task::failing() { self.p.state = Terminated; @@ -411,7 +414,7 @@ pub fn try_recv(p: RecvPacketBuffered) } } } - }; + } let _drop_state = DropState { p: &p.header }; From 7d6d0029ba0392bc0e8f2e7211f58a77cf85a231 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 30 Apr 2013 21:00:30 -0700 Subject: [PATCH 099/215] syntax: remove parsing destructors --- src/libsyntax/parse/parser.rs | 92 ++++++----------------------------- 1 file changed, 14 insertions(+), 78 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 50bdfb2f55726..1a4a15b3bf522 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -102,11 +102,6 @@ enum restriction { RESTRICT_NO_BAR_OR_DOUBLEBAR_OP, } -// So that we can distinguish a class dtor from other class members - -enum class_contents { dtor_decl(blk, ~[attribute], codemap::span), - members(~[@struct_field]) } - type arg_or_capture_item = Either; type item_info = (ident, item_, Option<~[attribute]>); @@ -3299,7 +3294,6 @@ pub impl Parser { } let mut fields: ~[@struct_field]; - let mut the_dtor: Option<(blk, ~[attribute], codemap::span)> = None; let is_tuple_like; if self.eat(&token::LBRACE) { @@ -3307,26 +3301,8 @@ pub impl Parser { is_tuple_like = false; fields = ~[]; while *self.token != token::RBRACE { - match self.parse_struct_decl_field() { - dtor_decl(ref blk, ref attrs, s) => { - match the_dtor { - Some((_, _, s_first)) => { - self.span_note(s, fmt!("Duplicate destructor \ - declaration for class %s", - *self.interner.get(class_name))); - self.span_fatal(copy s_first, ~"First destructor \ - declared here"); - } - None => { - the_dtor = Some((copy *blk, copy *attrs, s)); - } - } - } - members(mms) => { - for mms.each |struct_field| { - fields.push(*struct_field) - } - } + for self.parse_struct_decl_field().each |struct_field| { + fields.push(*struct_field) } } if fields.len() == 0 { @@ -3365,19 +3341,12 @@ pub impl Parser { ); } - let actual_dtor = do the_dtor.map |dtor| { - let (d_body, d_attrs, d_s) = copy *dtor; - codemap::spanned { node: ast::struct_dtor_ { id: self.get_id(), - attrs: d_attrs, - self_id: self.get_id(), - body: d_body}, - span: d_s}}; let _ = self.get_id(); // XXX: Workaround for crazy bug. let new_id = self.get_id(); (class_name, item_struct(@ast::struct_def { fields: fields, - dtor: actual_dtor, + dtor: None, ctor_id: if is_tuple_like { Some(new_id) } else { None } }, generics), None) @@ -3420,34 +3389,28 @@ pub impl Parser { } // parse an element of a struct definition - fn parse_struct_decl_field(&self) -> class_contents { + fn parse_struct_decl_field(&self) -> ~[@struct_field] { if self.try_parse_obsolete_priv_section() { - return members(~[]); + return ~[]; } - let attrs = self.parse_outer_attributes(); + // Need this to parse comments on fields. + let _attrs = self.parse_outer_attributes(); if self.eat_keyword(&~"priv") { - return members(~[self.parse_single_struct_field(private)]) + return ~[self.parse_single_struct_field(private)] } if self.eat_keyword(&~"pub") { - return members(~[self.parse_single_struct_field(public)]); + return ~[self.parse_single_struct_field(public)]; } if self.try_parse_obsolete_struct_ctor() { - return members(~[]); + return ~[]; } - if self.eat_keyword(&~"drop") { - let lo = self.last_span.lo; - let body = self.parse_block(); - return dtor_decl(body, attrs, mk_sp(lo, self.last_span.hi)) - } - else { - return members(~[self.parse_single_struct_field(inherited)]); - } + return ~[self.parse_single_struct_field(inherited)]; } // parse visiility: PUB, PRIV, or nothing @@ -3830,44 +3793,17 @@ pub impl Parser { // parse a structure-like enum variant definition // this should probably be renamed or refactored... fn parse_struct_def(&self) -> @struct_def { - let mut the_dtor: Option<(blk, ~[attribute], codemap::span)> = None; let mut fields: ~[@struct_field] = ~[]; while *self.token != token::RBRACE { - match self.parse_struct_decl_field() { - dtor_decl(ref blk, ref attrs, s) => { - match the_dtor { - Some((_, _, s_first)) => { - self.span_note(s, ~"duplicate destructor \ - declaration"); - self.span_fatal(copy s_first, - ~"first destructor \ - declared here"); - } - None => { - the_dtor = Some((copy *blk, copy *attrs, s)); - } - } - } - members(mms) => { - for mms.each |struct_field| { - fields.push(*struct_field); - } - } + for self.parse_struct_decl_field().each |struct_field| { + fields.push(*struct_field); } } self.bump(); - let actual_dtor = do the_dtor.map |dtor| { - let (d_body, d_attrs, d_s) = copy *dtor; - codemap::spanned { node: ast::struct_dtor_ { id: self.get_id(), - attrs: d_attrs, - self_id: self.get_id(), - body: d_body }, - span: d_s } - }; return @ast::struct_def { fields: fields, - dtor: actual_dtor, + dtor: None, ctor_id: None }; } From c2e1f47955571fab24fc731c0af97e4c71f4ada9 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 30 Apr 2013 21:00:45 -0700 Subject: [PATCH 100/215] rustc: remove the rest of drop Removes: ast::struct_def::dtor syntax::ast::ii_dtor syntax::visit::fk_dtor syntax::ast_map::node_dtor syntax:struct_dtor --- src/librustc/metadata/common.rs | 1 - src/librustc/metadata/csearch.rs | 7 -- src/librustc/metadata/decoder.rs | 16 --- src/librustc/metadata/encoder.rs | 27 ---- src/librustc/middle/astencode.rs | 26 ---- src/librustc/middle/borrowck/check_loans.rs | 6 +- src/librustc/middle/borrowck/gather_loans.rs | 3 +- src/librustc/middle/kind.rs | 11 -- src/librustc/middle/lint.rs | 29 ----- src/librustc/middle/liveness.rs | 5 +- src/librustc/middle/region.rs | 3 +- src/librustc/middle/resolve.rs | 21 +--- src/librustc/middle/trans/base.rs | 124 +------------------ src/librustc/middle/trans/debuginfo.rs | 3 - src/librustc/middle/trans/inline.rs | 4 - src/librustc/middle/trans/monomorphize.rs | 15 +-- src/librustc/middle/trans/reachable.rs | 13 +- src/librustc/middle/trans/type_use.rs | 3 - src/librustc/middle/ty.rs | 27 +--- src/librustc/middle/typeck/check/mod.rs | 29 +---- src/librustc/middle/typeck/collect.rs | 25 ---- src/librustdoc/tystr_pass.rs | 8 +- src/libsyntax/ast.rs | 18 +-- src/libsyntax/ast_map.rs | 29 +---- src/libsyntax/ast_util.rs | 26 ---- src/libsyntax/ext/pipes/pipec.rs | 1 - src/libsyntax/fold.rs | 26 ---- src/libsyntax/parse/parser.rs | 2 - src/libsyntax/print/pprust.rs | 7 -- src/libsyntax/visit.rs | 44 +------ 30 files changed, 21 insertions(+), 538 deletions(-) diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 8e689f3147b6b..111c201d5023c 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -100,7 +100,6 @@ pub static tag_mod_impl_trait: uint = 0x47u; different tags. */ pub static tag_item_impl_method: uint = 0x48u; -pub static tag_item_dtor: uint = 0x49u; pub static tag_item_trait_method_self_ty: uint = 0x4b; pub static tag_item_trait_method_self_ty_region: uint = 0x4c; diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index 5626714260b87..f8dc34f9cee3a 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -230,13 +230,6 @@ pub fn get_impl_method(cstore: @mut cstore::CStore, decoder::get_impl_method(cstore.intr, cdata, def.node, mname) } -/* If def names a class with a dtor, return it. Otherwise, return none. */ -pub fn struct_dtor(cstore: @mut cstore::CStore, def: ast::def_id) - -> Option { - let cdata = cstore::get_crate_data(cstore, def.crate); - decoder::struct_dtor(cdata, def.node) -} - pub fn get_item_visibility(cstore: @mut cstore::CStore, def_id: ast::def_id) -> ast::visibility { diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index cfe31360d321b..fb7b3f9c8b129 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -445,22 +445,6 @@ pub fn get_impl_method(intr: @ident_interner, cdata: cmd, id: ast::node_id, found.get() } -pub fn struct_dtor(cdata: cmd, id: ast::node_id) -> Option { - let items = reader::get_doc(reader::Doc(cdata.data), tag_items); - let mut found = None; - let cls_items = match maybe_find_item(id, items) { - Some(it) => it, - None => fail!(fmt!("struct_dtor: class id not found \ - when looking up dtor for %d", id)) - }; - for reader::tagged_docs(cls_items, tag_item_dtor) |doc| { - let doc1 = reader::get_doc(doc, tag_def_id); - let did = reader::with_doc_data(doc1, |d| parse_def_id(d)); - found = Some(translate_def_id(cdata, did)); - }; - found -} - pub fn get_symbol(data: @~[u8], id: ast::node_id) -> ~str { return item_symbol(lookup_item(id, data)); } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index dd4ef0d2e688f..ba6a4f30857eb 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -765,26 +765,6 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: &writer::Encoder, class itself */ let idx = encode_info_for_struct(ecx, ebml_w, path, struct_def.fields, index); - /* Encode the dtor */ - for struct_def.dtor.each |dtor| { - index.push(entry {val: dtor.node.id, pos: ebml_w.writer.tell()}); - encode_info_for_ctor(ecx, - ebml_w, - dtor.node.id, - ecx.tcx.sess.ident_of( - *ecx.tcx.sess.str_of(item.ident) + - ~"_dtor"), - path, - if generics.ty_params.len() > 0u { - Some(ii_dtor(copy *dtor, - item.ident, - copy *generics, - local_def(item.id))) } - else { - None - }, - generics); - } /* Index the class*/ add_to_index(); @@ -816,13 +796,6 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: &writer::Encoder, encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); encode_region_param(ecx, ebml_w, item); - /* Encode the dtor */ - /* Encode id for dtor */ - for struct_def.dtor.each |dtor| { - do ebml_w.wr_tag(tag_item_dtor) { - encode_def_id(ebml_w, local_def(dtor.node.id)); - } - }; /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index c7c9c110586c7..2f753523a7bc0 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -327,15 +327,6 @@ fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item { ast::ii_foreign(i) => { ast::ii_foreign(fld.fold_foreign_item(i)) } - ast::ii_dtor(ref dtor, nm, ref tps, parent_id) => { - let dtor_body = fld.fold_block(&dtor.node.body); - ast::ii_dtor( - codemap::spanned { - node: ast::struct_dtor_ { body: dtor_body, - .. /*bad*/copy (*dtor).node }, - .. (/*bad*/copy *dtor) }, - nm, /*bad*/copy *tps, parent_id) - } } } @@ -363,23 +354,6 @@ fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item) ast::ii_foreign(i) => { ast::ii_foreign(fld.fold_foreign_item(i)) } - ast::ii_dtor(ref dtor, nm, ref generics, parent_id) => { - let dtor_body = fld.fold_block(&dtor.node.body); - let dtor_attrs = fld.fold_attributes(/*bad*/copy (*dtor).node.attrs); - let new_generics = fold::fold_generics(generics, fld); - let dtor_id = fld.new_id((*dtor).node.id); - let new_parent = xcx.tr_def_id(parent_id); - let new_self = fld.new_id((*dtor).node.self_id); - ast::ii_dtor( - codemap::spanned { - node: ast::struct_dtor_ { id: dtor_id, - attrs: dtor_attrs, - self_id: new_self, - body: dtor_body }, - .. (/*bad*/copy *dtor) - }, - nm, new_generics, new_parent) - } } } diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 07b6c80d4201c..526a5a3a9dd4c 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -629,8 +629,7 @@ fn check_loans_in_fn(fk: &visit::fn_kind, let declared_purity, src; match *fk { - visit::fk_item_fn(*) | visit::fk_method(*) | - visit::fk_dtor(*) => { + visit::fk_item_fn(*) | visit::fk_method(*) => { declared_purity = ty::ty_fn_purity(fty); src = id; } @@ -658,8 +657,7 @@ fn check_loans_in_fn(fk: &visit::fn_kind, // inherits the fn_args from enclosing ctxt } visit::fk_anon(*) | visit::fk_fn_block(*) | - visit::fk_method(*) | visit::fk_item_fn(*) | - visit::fk_dtor(*) => { + visit::fk_method(*) | visit::fk_item_fn(*) => { let mut fn_args = ~[]; for decl.inputs.each |input| { // For the purposes of purity, only consider function- diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs index e40d0e63eb38e..da04853411865 100644 --- a/src/librustc/middle/borrowck/gather_loans.rs +++ b/src/librustc/middle/borrowck/gather_loans.rs @@ -104,8 +104,7 @@ fn req_loans_in_fn(fk: &visit::fn_kind, match *fk { visit::fk_anon(*) | visit::fk_fn_block(*) => {} - visit::fk_item_fn(*) | visit::fk_method(*) | - visit::fk_dtor(*) => { + visit::fk_item_fn(*) | visit::fk_method(*) => { self.item_ub = body.node.id; } } diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index cf488b0ac8939..0925e8cdd6375 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -153,17 +153,6 @@ fn check_item(item: @item, cx: Context, visitor: visit::vt) { } } } - item_struct(struct_def, _) => { - match struct_def.dtor { - None => {} - Some(ref dtor) => { - let struct_did = def_id { crate: 0, node: item.id }; - check_struct_safe_for_destructor(cx, - dtor.span, - struct_did); - } - } - } _ => {} } } diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index faf4b1c31061b..b67d74bc272b6 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -57,7 +57,6 @@ pub enum lint { type_limits, default_methods, deprecated_mutable_fields, - deprecated_drop, unused_unsafe, managed_heap_memory, @@ -210,13 +209,6 @@ pub fn get_lint_dict() -> LintDict { default: deny }), - (~"deprecated_drop", - LintSpec { - lint: deprecated_drop, - desc: "deprecated \"drop\" notation for the destructor", - default: deny - }), - (~"unused_unsafe", LintSpec { lint: unused_unsafe, @@ -463,7 +455,6 @@ fn check_item(i: @ast::item, cx: ty::ctxt) { check_item_type_limits(cx, i); check_item_default_methods(cx, i); check_item_deprecated_mutable_fields(cx, i); - check_item_deprecated_drop(cx, i); check_item_unused_unsafe(cx, i); check_item_unused_mut(cx, i); } @@ -668,26 +659,6 @@ fn check_item_deprecated_mutable_fields(cx: ty::ctxt, item: @ast::item) { } } -fn check_item_deprecated_drop(cx: ty::ctxt, item: @ast::item) { - match item.node { - ast::item_struct(struct_def, _) => { - match struct_def.dtor { - None => {} - Some(ref dtor) => { - cx.sess.span_lint(deprecated_drop, - item.id, - item.id, - dtor.span, - ~"`drop` notation for destructors is \ - deprecated; implement the `Drop` \ - trait instead"); - } - } - } - _ => {} - } -} - fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) { fn check_foreign_fn(cx: ty::ctxt, fn_id: ast::node_id, diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 94d82d0acb8e4..0df10c59a8aac 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -117,7 +117,7 @@ use syntax::ast::*; use syntax::codemap::span; use syntax::parse::token::special_idents; use syntax::print::pprust::{expr_to_str, block_to_str}; -use syntax::visit::{fk_anon, fk_dtor, fk_fn_block, fk_item_fn, fk_method}; +use syntax::visit::{fk_anon, fk_fn_block, fk_item_fn, fk_method}; use syntax::visit::{vt}; use syntax::{visit, ast_util}; @@ -440,9 +440,6 @@ fn visit_fn(fk: &visit::fn_kind, sty_static => {} } } - fk_dtor(_, _, self_id, _) => { - fn_maps.add_variable(Arg(self_id, special_idents::self_)); - } fk_item_fn(*) | fk_anon(*) | fk_fn_block(*) => {} } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index f32998281711f..88e201fb5f438 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -438,8 +438,7 @@ pub fn resolve_fn(fk: &visit::fn_kind, cx: ctxt, visitor: visit::vt) { let fn_cx = match *fk { - visit::fk_item_fn(*) | visit::fk_method(*) | - visit::fk_dtor(*) => { + visit::fk_item_fn(*) | visit::fk_method(*) => { // Top-level functions are a root scope. ctxt {parent: Some(id),.. cx} } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 294a21fac2c23..1d2ca59b8aa31 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -47,7 +47,7 @@ use syntax::ast::{named_field, ne, neg, node_id, pat, pat_enum, pat_ident}; use syntax::ast::{Path, pat_lit, pat_range, pat_struct}; use syntax::ast::{prim_ty, private, provided}; use syntax::ast::{public, required, rem, self_ty_, shl, shr, stmt_decl}; -use syntax::ast::{struct_dtor, struct_field, struct_variant_kind}; +use syntax::ast::{struct_field, struct_variant_kind}; use syntax::ast::{sty_static, subtract, trait_ref, tuple_variant_kind, Ty}; use syntax::ast::{ty_bool, ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i}; use syntax::ast::{ty_i16, ty_i32, ty_i64, ty_i8, ty_int, TyParam, ty_path}; @@ -3512,7 +3512,6 @@ pub impl Resolver { self.resolve_struct(item.id, generics, struct_def.fields, - &struct_def.dtor, visitor); } @@ -3770,7 +3769,6 @@ pub impl Resolver { id: node_id, generics: &Generics, fields: &[@struct_field], - optional_destructor: &Option, visitor: ResolveVisitor) { // If applicable, create a rib for the type parameters. do self.with_type_parameter_rib(HasTypeParameters @@ -3784,23 +3782,6 @@ pub impl Resolver { for fields.each |field| { self.resolve_type(field.node.ty, visitor); } - - // Resolve the destructor, if applicable. - match *optional_destructor { - None => { - // Nothing to do. - } - Some(ref destructor) => { - self.resolve_function(NormalRibKind, - None, - NoTypeParameters, - &destructor.node.body, - HasSelfBinding - ((*destructor).node.self_id, - true), - visitor); - } - } } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index efa10dfc2aa34..b3f7ab8b00a0e 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2093,53 +2093,6 @@ pub fn trans_tuple_struct(ccx: @CrateContext, finish_fn(fcx, lltop); } -pub fn trans_struct_dtor(ccx: @CrateContext, - path: path, - body: &ast::blk, - dtor_id: ast::node_id, - psubsts: Option<@param_substs>, - hash_id: Option, - parent_id: ast::def_id) - -> ValueRef { - let tcx = ccx.tcx; - /* Look up the parent class's def_id */ - let mut class_ty = ty::lookup_item_type(tcx, parent_id).ty; - /* Substitute in the class type if necessary */ - for psubsts.each |ss| { - class_ty = ty::subst_tps(tcx, ss.tys, ss.self_ty, class_ty); - } - - /* The dtor takes a (null) output pointer, and a self argument, - and returns () */ - let lldty = type_of_dtor(ccx, class_ty); - - // XXX: Bad copies. - let s = get_dtor_symbol(ccx, copy path, dtor_id, psubsts); - - /* Register the dtor as a function. It has external linkage */ - let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, lldty); - lib::llvm::SetLinkage(lldecl, lib::llvm::ExternalLinkage); - - /* If we're monomorphizing, register the monomorphized decl - for the dtor */ - for hash_id.each |h_id| { - ccx.monomorphized.insert(*h_id, lldecl); - } - /* Translate the dtor body */ - let decl = ast_util::dtor_dec(); - trans_fn(ccx, - path, - &decl, - body, - lldecl, - impl_self(class_ty), - psubsts, - dtor_id, - None, - []); - lldecl -} - pub fn trans_enum_def(ccx: @CrateContext, enum_definition: &ast::enum_def, id: ast::node_id, path: @ast_map::path, vi: @~[ty::VariantInfo], @@ -2158,8 +2111,7 @@ pub fn trans_enum_def(ccx: @CrateContext, enum_definition: &ast::enum_def, // Nothing to do. } ast::struct_variant_kind(struct_def) => { - trans_struct_def(ccx, struct_def, path, - variant.node.id); + trans_struct_def(ccx, struct_def); } } } @@ -2228,22 +2180,14 @@ pub fn trans_item(ccx: @CrateContext, item: &ast::item) { } ast::item_struct(struct_def, ref generics) => { if !generics.is_type_parameterized() { - trans_struct_def(ccx, struct_def, path, item.id); + trans_struct_def(ccx, struct_def); } } _ => {/* fall through */ } } } -pub fn trans_struct_def(ccx: @CrateContext, struct_def: @ast::struct_def, - path: @ast_map::path, - id: ast::node_id) { - // Translate the destructor. - for struct_def.dtor.each |dtor| { - trans_struct_dtor(ccx, /*bad*/copy *path, &dtor.node.body, - dtor.node.id, None, None, local_def(id)); - }; - +pub fn trans_struct_def(ccx: @CrateContext, struct_def: @ast::struct_def) { // If this is a tuple-like struct, translate the constructor. match struct_def.ctor_id { // We only need to translate a constructor if there are fields; @@ -2477,46 +2421,6 @@ pub fn item_path(ccx: @CrateContext, i: @ast::item) -> path { vec::append(/*bad*/copy *base, ~[path_name(i.ident)]) } -/* If there's already a symbol for the dtor with and substs , - return it; otherwise, create one and register it, returning it as well */ -pub fn get_dtor_symbol(ccx: @CrateContext, - path: path, - id: ast::node_id, - substs: Option<@param_substs>) - -> ~str { - let t = ty::node_id_to_type(ccx.tcx, id); - match ccx.item_symbols.find(&id) { - Some(s) => (/*bad*/copy *s), - None if substs.is_none() => { - let s = mangle_exported_name( - ccx, - vec::append(path, ~[path_name((ccx.names)(~"dtor"))]), - t); - // XXX: Bad copy, use `@str`? - ccx.item_symbols.insert(id, copy s); - s - } - None => { - // Monomorphizing, so just make a symbol, don't add - // this to item_symbols - match substs { - Some(ss) => { - let mono_ty = ty::subst_tps(ccx.tcx, ss.tys, ss.self_ty, t); - mangle_exported_name( - ccx, - vec::append(path, - ~[path_name((ccx.names)(~"dtor"))]), - mono_ty) - } - None => { - ccx.sess.bug(fmt!("get_dtor_symbol: not monomorphizing and \ - couldn't find a symbol for dtor %?", path)); - } - } - } - } -} - pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef { debug!("get_item_val(id=`%?`)", id); let tcx = ccx.tcx; @@ -2602,28 +2506,6 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef { } } } - ast_map::node_dtor(_, dt, parent_id, pt) => { - /* - Don't just call register_fn, since we don't want to add - the implicit self argument automatically (we want to make sure - it has the right type) - */ - // Want parent_id and not id, because id is the dtor's type - let class_ty = ty::lookup_item_type(tcx, parent_id).ty; - // This code shouldn't be reached if the class is generic - assert!(!ty::type_has_params(class_ty)); - let lldty = T_fn(~[ - T_ptr(T_i8()), - T_ptr(type_of(ccx, class_ty)) - ], - T_nil()); - let s = get_dtor_symbol(ccx, /*bad*/copy *pt, dt.node.id, None); - - /* Make the declaration for the dtor */ - let llfn = decl_internal_cdecl_fn(ccx.llmod, s, lldty); - lib::llvm::SetLinkage(llfn, lib::llvm::ExternalLinkage); - llfn - } ast_map::node_variant(ref v, enm, pth) => { let llfn; diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 2a2bf7ba4ad68..58fc5ea3be647 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -983,9 +983,6 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata { expected an expr_fn_block here") } } - ast_map::node_dtor(_, _, did, _) => { - ((dbg_cx.names)(~"dtor"), ast_util::dtor_ty(), did.node) - } _ => fcx.ccx.sess.bug(~"create_function: unexpected \ sort of node") }; diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index 7a7f03c2273e1..ad06a9715b4af 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -118,10 +118,6 @@ pub fn maybe_instantiate_inline(ccx: @CrateContext, fn_id: ast::def_id, } local_def(mth.id) } - csearch::found(ast::ii_dtor(ref dtor, _, _, _)) => { - ccx.external.insert(fn_id, Some((*dtor).node.id)); - local_def((*dtor).node.id) - } } } } diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 72ad6dde4f17d..aa49915d1759b 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -13,7 +13,7 @@ use driver::session; use lib::llvm::ValueRef; use middle::trans::base::{get_insn_ctxt}; use middle::trans::base::{set_inline_hint_if_appr, set_inline_hint}; -use middle::trans::base::{trans_enum_variant, trans_struct_dtor}; +use middle::trans::base::{trans_enum_variant}; use middle::trans::base::{trans_fn, decl_internal_cdecl_fn}; use middle::trans::base::{get_item_val, no_self}; use middle::trans::base; @@ -35,7 +35,6 @@ use syntax::ast_map; use syntax::ast_map::path_name; use syntax::ast_util::local_def; use syntax::opt_vec; -use syntax::parse::token::special_idents; use syntax::abi::AbiSet; pub fn monomorphic_fn(ccx: @CrateContext, @@ -116,8 +115,6 @@ pub fn monomorphic_fn(ccx: @CrateContext, // Foreign externs don't have to be monomorphized. return (get_item_val(ccx, fn_id.node), true); } - ast_map::node_dtor(_, dtor, _, pt) => - (pt, special_idents::dtor, dtor.span), ast_map::node_trait_method(@ast::provided(m), _, pt) => { (pt, m.ident, m.span) } @@ -243,16 +240,6 @@ pub fn monomorphic_fn(ccx: @CrateContext, meth::trans_method(ccx, pt, mth, psubsts, None, d, impl_did); d } - ast_map::node_dtor(_, dtor, _, pt) => { - let parent_id = match ty::ty_to_def_id(ty::node_id_to_type(ccx.tcx, - dtor.node.self_id)) { - Some(did) => did, - None => ccx.sess.span_bug(dtor.span, ~"Bad self ty in \ - dtor") - }; - trans_struct_dtor(ccx, /*bad*/copy *pt, &dtor.node.body, - dtor.node.id, psubsts, Some(hash_id), parent_id) - } ast_map::node_trait_method(@ast::provided(mth), _, pt) => { let d = mk_lldecl(); set_inline_hint_if_appr(/*bad*/copy mth.attrs, d); diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs index 3ccef0dbc4aca..234473dd35b60 100644 --- a/src/librustc/middle/trans/reachable.rs +++ b/src/librustc/middle/trans/reachable.rs @@ -124,18 +124,10 @@ fn traverse_public_item(cx: &ctx, item: @item) { } } } - item_struct(ref struct_def, ref generics) => { + item_struct(ref struct_def, _) => { for struct_def.ctor_id.each |&ctor_id| { cx.rmap.insert(ctor_id); } - for struct_def.dtor.each |dtor| { - cx.rmap.insert(dtor.node.id); - if generics.ty_params.len() > 0u || - attr::find_inline_attr(dtor.node.attrs) != attr::ia_none - { - traverse_inline_body(cx, &dtor.node.body); - } - } } item_ty(t, _) => { traverse_ty(t, cx, @@ -239,9 +231,6 @@ fn traverse_all_resources_and_impls(cx: &ctx, crate_mod: &_mod) { visit_item: |i, cx, v| { visit::visit_item(i, cx, v); match i.node { - item_struct(sdef, _) if sdef.dtor.is_some() => { - traverse_public_item(cx, i); - } item_impl(*) => { traverse_public_item(cx, i); } diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 33145dd4334a5..e19eba6ca98f9 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -157,9 +157,6 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint) for uint::range(0u, n_tps) |n| { cx.uses[n] |= flags;} } } - ast_map::node_dtor(_, ref dtor, _, _) => { - handle_body(cx, &dtor.node.body); - } ast_map::node_struct_ctor(*) => { // Similarly to node_variant, this monomorphized function just uses // the representations of all of its type parameters. diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c7fb1e94adf4c..5b8e0e03b628c 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3748,28 +3748,8 @@ pub impl DtorKind { Otherwise return none. */ pub fn ty_dtor(cx: ctxt, struct_id: def_id) -> DtorKind { match cx.destructor_for_type.find(&struct_id) { - Some(&method_def_id) => return TraitDtor(method_def_id), - None => {} // Continue. - } - - if is_local(struct_id) { - match cx.items.find(&struct_id.node) { - Some(&ast_map::node_item(@ast::item { - node: ast::item_struct(@ast::struct_def { dtor: Some(ref dtor), - _ }, - _), - _ - }, _)) => - LegacyDtor(local_def((*dtor).node.id)), - _ => - NoDtor - } - } - else { - match csearch::struct_dtor(cx.sess.cstore, struct_id) { + Some(&method_def_id) => TraitDtor(method_def_id), None => NoDtor, - Some(did) => LegacyDtor(did), - } } } @@ -3819,11 +3799,6 @@ pub fn item_path(cx: ctxt, id: ast::def_id) -> ast_map::path { ast_map::path_name((*variant).node.name)) } - ast_map::node_dtor(_, _, _, path) => { - vec::append_one(/*bad*/copy *path, ast_map::path_name( - syntax::parse::token::special_idents::literally_dtor)) - } - ast_map::node_struct_ctor(_, item, path) => { vec::append_one(/*bad*/copy *path, ast_map::path_name(item.ident)) } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index b9f3de873cf07..d1c5ae18bc30b 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -557,30 +557,7 @@ pub fn check_no_duplicate_fields(tcx: ty::ctxt, } } -pub fn check_struct(ccx: @mut CrateCtxt, - struct_def: @ast::struct_def, - id: ast::node_id, - span: span) { - let tcx = ccx.tcx; - let self_ty = ty::node_id_to_type(tcx, id); - - for struct_def.dtor.each |dtor| { - let class_t = SelfInfo { - self_ty: self_ty, - self_id: dtor.node.self_id, - span: dtor.span, - }; - // typecheck the dtor - let dtor_dec = ast_util::dtor_dec(); - check_bare_fn( - ccx, - &dtor_dec, - &dtor.node.body, - dtor.node.id, - Some(class_t) - ); - }; - +pub fn check_struct(ccx: @mut CrateCtxt, id: ast::node_id, span: span) { // Check that the class is instantiable check_instantiable(ccx.tcx, span, id); } @@ -623,8 +600,8 @@ pub fn check_item(ccx: @mut CrateCtxt, it: @ast::item) { } } } - ast::item_struct(struct_def, _) => { - check_struct(ccx, struct_def, it.id, it.span); + ast::item_struct(*) => { + check_struct(ccx, it.id, it.span); } ast::item_ty(t, ref generics) => { let tpt_ty = ty::node_id_to_type(ccx.tcx, it.id); diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 0ffd398d03c19..10537711b3289 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -49,7 +49,6 @@ use syntax::ast::{RegionTyParamBound, TraitTyParamBound}; use syntax::ast; use syntax::ast_map; use syntax::ast_util::{local_def, split_trait_methods}; -use syntax::ast_util; use syntax::codemap::span; use syntax::codemap; use syntax::print::pprust::{path_to_str, self_ty_to_str}; @@ -897,30 +896,6 @@ pub fn convert_struct(ccx: &CrateCtxt, id: ast::node_id) { let tcx = ccx.tcx; - for struct_def.dtor.each |dtor| { - let region_parameterization = - RegionParameterization::from_variance_and_generics(rp, generics); - - // Write the dtor type - let t_dtor = ty::mk_bare_fn( - tcx, - astconv::ty_of_bare_fn( - ccx, - &type_rscope(region_parameterization), - ast::impure_fn, - AbiSet::Rust(), - &opt_vec::Empty, - &ast_util::dtor_dec())); - write_ty_to_tcx(tcx, dtor.node.id, t_dtor); - tcx.tcache.insert(local_def(dtor.node.id), - ty_param_bounds_and_ty { - generics: ty::Generics { - type_param_defs: tpt.generics.type_param_defs, - region_param: rp - }, - ty: t_dtor}); - }; - // Write the type of each of the members for struct_def.fields.each |f| { convert_field(ccx, rp, tpt.generics.type_param_defs, *f, generics); diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs index 303bdc53b6982..a6fbee81bc8af 100644 --- a/src/librustdoc/tystr_pass.rs +++ b/src/librustdoc/tystr_pass.rs @@ -332,13 +332,7 @@ fn fold_struct( /// what I actually want fn strip_struct_extra_stuff(item: @ast::item) -> @ast::item { let node = match copy item.node { - ast::item_struct(def, tys) => { - let def = @ast::struct_def { - dtor: None, // Remove the drop { } block - .. copy *def - }; - ast::item_struct(def, tys) - } + ast::item_struct(def, tys) => ast::item_struct(def, tys), _ => fail!(~"not a struct") }; diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index ba6fe1cda4f31..71fd506ebede3 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1174,10 +1174,7 @@ pub enum struct_field_kind { #[auto_decode] #[deriving(Eq)] pub struct struct_def { - fields: ~[@struct_field], /* fields */ - /* (not including ctor or dtor) */ - /* dtor is optional */ - dtor: Option, + fields: ~[@struct_field], /* fields, not including ctor */ /* ID of the constructor. This is only used for tuple- or enum-like * structs. */ ctor_id: Option @@ -1230,18 +1227,6 @@ impl to_bytes::IterBytes for struct_mutability { } } -pub type struct_dtor = spanned; - -#[auto_encode] -#[auto_decode] -#[deriving(Eq)] -pub struct struct_dtor_ { - id: node_id, - attrs: ~[attribute], - self_id: node_id, - body: blk, -} - #[auto_encode] #[auto_decode] #[deriving(Eq)] @@ -1272,7 +1257,6 @@ pub enum inlined_item { ii_item(@item), ii_method(def_id /* impl id */, @method), ii_foreign(@foreign_item), - ii_dtor(struct_dtor, ident, Generics, def_id /* parent id */) } /* hold off on tests ... they appear in a later merge. diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index f9828ad2b9e4e..d2125cebb5e48 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -14,7 +14,6 @@ use ast; use ast_util::{inlined_item_utils, stmt_id}; use ast_util; use codemap; -use codemap::spanned; use diagnostic::span_handler; use parse::token::ident_interner; use print::pprust; @@ -93,8 +92,6 @@ pub enum ast_node { // order they are introduced. node_arg(arg, uint), node_local(uint), - // Destructor for a struct - node_dtor(Generics, @struct_dtor, def_id, @path), node_block(blk), node_struct_ctor(@struct_def, @item, @path), } @@ -163,7 +160,7 @@ pub fn map_decoded_item(diag: @span_handler, // don't decode and instantiate the impl, but just the method, we have to // add it to the table now: match *ii { - ii_item(*) | ii_dtor(*) => { /* fallthrough */ } + ii_item(*) => { /* fallthrough */ } ii_foreign(i) => { cx.map.insert(i.id, node_foreign_item(i, AbiSet::Intrinsic(), @@ -193,27 +190,6 @@ pub fn map_fn( node_arg(/* FIXME (#2543) */ copy *a, cx.local_id)); cx.local_id += 1u; } - match *fk { - visit::fk_dtor(generics, ref attrs, self_id, parent_id) => { - let dt = @spanned { - node: ast::struct_dtor_ { - id: id, - attrs: /* FIXME (#2543) */ vec::from_slice(*attrs), - self_id: self_id, - body: /* FIXME (#2543) */ copy *body, - }, - span: sp, - }; - cx.map.insert( - id, - node_dtor( - /* FIXME (#2543) */ copy *generics, - dt, - parent_id, - @/* FIXME (#2543) */ copy cx.path)); - } - _ => () - } visit::visit_fn(fk, decl, body, sp, id, cx, v); } @@ -411,9 +387,6 @@ pub fn node_id_to_str(map: map, id: node_id, itr: @ident_interner) -> ~str { Some(&node_local(_)) => { // add more info here fmt!("local (id=%?)", id) } - Some(&node_dtor(*)) => { // add more info here - fmt!("node_dtor (id=%?)", id) - } Some(&node_block(_)) => { fmt!("block") } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 148b713a4f58f..bf5381831d054 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -302,7 +302,6 @@ impl inlined_item_utils for inlined_item { ii_item(i) => /* FIXME (#2543) */ copy i.ident, ii_foreign(i) => /* FIXME (#2543) */ copy i.ident, ii_method(_, m) => /* FIXME (#2543) */ copy m.ident, - ii_dtor(_, nm, _, _) => /* FIXME (#2543) */ copy nm } } @@ -311,7 +310,6 @@ impl inlined_item_utils for inlined_item { ii_item(i) => i.id, ii_foreign(i) => i.id, ii_method(_, m) => m.id, - ii_dtor(ref dtor, _, _, _) => (*dtor).node.id } } @@ -320,10 +318,6 @@ impl inlined_item_utils for inlined_item { ii_item(i) => (v.visit_item)(i, e, v), ii_foreign(i) => (v.visit_foreign_item)(i, e, v), ii_method(_, m) => visit::visit_method_helper(m, e, v), - ii_dtor(/*bad*/ copy dtor, _, ref generics, parent_id) => { - visit::visit_struct_dtor_helper(dtor, generics, - parent_id, e, v); - } } } } @@ -359,20 +353,6 @@ pub fn operator_prec(op: ast::binop) -> uint { /// not appearing in the prior table. pub static as_prec: uint = 11u; -pub fn dtor_ty() -> @ast::Ty { - @ast::Ty {id: 0, node: ty_nil, span: dummy_sp()} -} - -pub fn dtor_dec() -> fn_decl { - let nil_t = dtor_ty(); - // dtor has no args - ast::fn_decl { - inputs: ~[], - output: nil_t, - cf: return_val, - } -} - pub fn empty_generics() -> Generics { Generics {lifetimes: opt_vec::Empty, ty_params: opt_vec::Empty} @@ -457,12 +437,6 @@ pub fn id_visitor(vfn: @fn(node_id)) -> visit::vt<()> { vfn(id); match *fk { - visit::fk_dtor(generics, _, self_id, parent_id) => { - visit_generics(generics); - vfn(id); - vfn(self_id); - vfn(parent_id.node); - } visit::fk_item_fn(_, generics, _, _) => { visit_generics(generics); } diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs index 3311c61de8b64..3ad94905f7f78 100644 --- a/src/libsyntax/ext/pipes/pipec.rs +++ b/src/libsyntax/ext/pipes/pipec.rs @@ -431,7 +431,6 @@ impl gen_init for protocol { dummy_sp(), ast::struct_def { fields: fields, - dtor: None, ctor_id: None }, cx.strip_bounds(&generics)) diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index d82608846ab98..adfc95f3e94d1 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -290,21 +290,8 @@ pub fn noop_fold_item_underscore(i: &item_, fld: @ast_fold) -> item_ { fn fold_struct_def(struct_def: @ast::struct_def, fld: @ast_fold) -> @ast::struct_def { - let dtor = do struct_def.dtor.map |dtor| { - let dtor_body = fld.fold_block(&dtor.node.body); - let dtor_id = fld.new_id(dtor.node.id); - spanned { - node: ast::struct_dtor_ { - body: dtor_body, - id: dtor_id, - .. copy dtor.node - }, - span: copy dtor.span - } - }; @ast::struct_def { fields: struct_def.fields.map(|f| fold_struct_field(*f, fld)), - dtor: dtor, ctor_id: struct_def.ctor_id.map(|cid| fld.new_id(*cid)), } } @@ -655,22 +642,9 @@ fn noop_fold_variant(v: &variant_, fld: @ast_fold) -> variant_ { }) } struct_variant_kind(struct_def) => { - let dtor = do struct_def.dtor.map |dtor| { - let dtor_body = fld.fold_block(&dtor.node.body); - let dtor_id = fld.new_id(dtor.node.id); - spanned { - node: ast::struct_dtor_ { - body: dtor_body, - id: dtor_id, - .. copy dtor.node - }, - .. copy *dtor - } - }; kind = struct_variant_kind(@ast::struct_def { fields: vec::map(struct_def.fields, |f| fld.fold_struct_field(*f)), - dtor: dtor, ctor_id: struct_def.ctor_id.map(|c| fld.new_id(*c)) }) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1a4a15b3bf522..27a1cde2f9638 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3346,7 +3346,6 @@ pub impl Parser { (class_name, item_struct(@ast::struct_def { fields: fields, - dtor: None, ctor_id: if is_tuple_like { Some(new_id) } else { None } }, generics), None) @@ -3803,7 +3802,6 @@ pub impl Parser { return @ast::struct_def { fields: fields, - dtor: None, ctor_id: None }; } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index d5645ada9294a..f23badd046206 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -693,13 +693,6 @@ pub fn print_struct(s: @ps, nbsp(s); bopen(s); hardbreak_if_not_bol(s); - for struct_def.dtor.each |dtor| { - hardbreak_if_not_bol(s); - maybe_print_comment(s, dtor.span.lo); - print_outer_attributes(s, dtor.node.attrs); - head(s, ~"drop"); - print_block(s, &dtor.node.body); - } for struct_def.fields.each |field| { match field.node.kind { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 80df8fb91a515..71cfbab91089e 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -11,7 +11,6 @@ use abi::AbiSet; use ast::*; use ast; -use ast_util; use codemap::span; use parse; use opt_vec; @@ -39,13 +38,6 @@ pub enum fn_kind<'self> { // |x, y| ... fk_fn_block, - - fk_dtor( // class destructor - &'self Generics, - &'self [attribute], - node_id /* self id */, - def_id /* parent class id */ - ) } pub fn name_of_fn(fk: &fn_kind) -> ident { @@ -54,15 +46,13 @@ pub fn name_of_fn(fk: &fn_kind) -> ident { name } fk_anon(*) | fk_fn_block(*) => parse::token::special_idents::anon, - fk_dtor(*) => parse::token::special_idents::dtor } } pub fn generics_of_fn(fk: &fn_kind) -> Generics { match *fk { fk_item_fn(_, generics, _, _) | - fk_method(_, generics, _) | - fk_dtor(generics, _, _, _) => { + fk_method(_, generics, _) => { copy *generics } fk_anon(*) | fk_fn_block(*) => { @@ -369,25 +359,6 @@ pub fn visit_method_helper(m: &method, e: E, v: vt) { ); } -pub fn visit_struct_dtor_helper(dtor: struct_dtor, generics: &Generics, - parent_id: def_id, e: E, v: vt) { - (v.visit_fn)( - &fk_dtor( - generics, - dtor.node.attrs, - dtor.node.self_id, - parent_id - ), - &ast_util::dtor_dec(), - &dtor.node.body, - dtor.span, - dtor.node.id, - e, - v - ) - -} - pub fn visit_fn(fk: &fn_kind, decl: &fn_decl, body: &blk, _sp: span, _id: node_id, e: E, v: vt) { visit_fn_decl(decl, e, v); @@ -412,23 +383,14 @@ pub fn visit_trait_method(m: &trait_method, e: E, v: vt) { pub fn visit_struct_def( sd: @struct_def, _nm: ast::ident, - generics: &Generics, - id: node_id, + _generics: &Generics, + _id: node_id, e: E, v: vt ) { for sd.fields.each |f| { (v.visit_struct_field)(*f, e, v); } - for sd.dtor.each |dtor| { - visit_struct_dtor_helper( - *dtor, - generics, - ast_util::local_def(id), - e, - v - ) - } } pub fn visit_struct_field(sf: @struct_field, e: E, v: vt) { From 3e3e2f00250d77719598ad052bb2016d46e6a148 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 30 Apr 2013 20:20:08 -0700 Subject: [PATCH 101/215] allow parsing attributes on struct fields --- src/libsyntax/ast.rs | 1 + src/libsyntax/ext/pipes/pipec.rs | 3 ++- src/libsyntax/fold.rs | 7 ++++++- src/libsyntax/parse/obsolete.rs | 6 +++--- src/libsyntax/parse/parser.rs | 30 ++++++++++++++++++------------ src/libsyntax/print/pprust.rs | 1 + 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 71fd506ebede3..a853dbed2f123 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1158,6 +1158,7 @@ pub struct struct_field_ { kind: struct_field_kind, id: node_id, ty: @Ty, + attrs: ~[attribute], } pub type struct_field = spanned; diff --git a/src/libsyntax/ext/pipes/pipec.rs b/src/libsyntax/ext/pipes/pipec.rs index 3ad94905f7f78..e876972fe6878 100644 --- a/src/libsyntax/ext/pipes/pipec.rs +++ b/src/libsyntax/ext/pipes/pipec.rs @@ -415,7 +415,8 @@ impl gen_init for protocol { ast::struct_immutable, ast::inherited), id: cx.next_id(), - ty: fty + ty: fty, + attrs: ~[], }, span: dummy_sp() } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index adfc95f3e94d1..36565395e5988 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -222,9 +222,12 @@ pub fn noop_fold_item(i: @item, fld: @ast_fold) -> Option<@item> { fn noop_fold_struct_field(sf: @struct_field, fld: @ast_fold) -> @struct_field { + let fold_attribute = |x| fold_attribute_(x, fld); + @spanned { node: ast::struct_field_ { kind: copy sf.node.kind, id: sf.node.id, - ty: fld.fold_ty(sf.node.ty) }, + ty: fld.fold_ty(sf.node.ty), + attrs: sf.node.attrs.map(|e| fold_attribute(*e)) }, span: sf.span } } @@ -309,6 +312,7 @@ fn fold_struct_field(f: @struct_field, fld: @ast_fold) -> @struct_field { kind: copy f.node.kind, id: fld.new_id(f.node.id), ty: fld.fold_ty(f.node.ty), + attrs: /* FIXME (#2543) */ copy f.node.attrs, }, span: fld.new_span(f.span), } @@ -757,6 +761,7 @@ impl ast_fold for AstFoldFns { kind: copy sf.node.kind, id: sf.node.id, ty: (self as @ast_fold).fold_ty(sf.node.ty), + attrs: copy sf.node.attrs, }, span: (self.new_span)(sf.span), } diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index ce21e0f672d45..c1afc53def0c2 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -18,7 +18,7 @@ removed. */ -use ast::{expr, expr_lit, lit_nil}; +use ast::{expr, expr_lit, lit_nil, attribute}; use ast; use codemap::{span, respan}; use parse::parser::Parser; @@ -282,13 +282,13 @@ pub impl Parser { } } - fn try_parse_obsolete_priv_section(&self) -> bool { + fn try_parse_obsolete_priv_section(&self, attrs: ~[attribute]) -> bool { if self.is_keyword(&~"priv") && self.look_ahead(1) == token::LBRACE { self.obsolete(copy *self.span, ObsoletePrivSection); self.eat_keyword(&~"priv"); self.bump(); while *self.token != token::RBRACE { - self.parse_single_struct_field(ast::private); + self.parse_single_struct_field(ast::private, attrs); } self.bump(); true diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 27a1cde2f9638..74af745840891 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2520,7 +2520,9 @@ pub impl Parser { } // parse a structure field - fn parse_name_and_ty(&self, pr: visibility) -> @struct_field { + fn parse_name_and_ty(&self, + pr: visibility, + attrs: ~[attribute]) -> @struct_field { let mut is_mutbl = struct_immutable; let lo = self.span.lo; if self.eat_keyword(&~"mut") { @@ -2535,7 +2537,8 @@ pub impl Parser { @spanned(lo, self.last_span.hi, ast::struct_field_ { kind: named_field(name, is_mutbl, pr), id: self.get_id(), - ty: ty + ty: ty, + attrs: attrs, }) } @@ -3318,11 +3321,13 @@ pub impl Parser { &token::RPAREN, seq_sep_trailing_allowed(token::COMMA) ) |p| { + let attrs = self.parse_outer_attributes(); let lo = p.span.lo; let struct_field_ = ast::struct_field_ { kind: unnamed_field, id: self.get_id(), - ty: p.parse_ty(false) + ty: p.parse_ty(false), + attrs: attrs, }; @spanned(lo, p.span.hi, struct_field_) }; @@ -3359,12 +3364,14 @@ pub impl Parser { } // parse a structure field declaration - fn parse_single_struct_field(&self, vis: visibility) -> @struct_field { + fn parse_single_struct_field(&self, + vis: visibility, + attrs: ~[attribute]) -> @struct_field { if self.eat_obsolete_ident("let") { self.obsolete(*self.last_span, ObsoleteLet); } - let a_var = self.parse_name_and_ty(vis); + let a_var = self.parse_name_and_ty(vis, attrs); match *self.token { token::SEMI => { self.obsolete(copy *self.span, ObsoleteFieldTerminator); @@ -3390,26 +3397,25 @@ pub impl Parser { // parse an element of a struct definition fn parse_struct_decl_field(&self) -> ~[@struct_field] { - if self.try_parse_obsolete_priv_section() { + let attrs = self.parse_outer_attributes(); + + if self.try_parse_obsolete_priv_section(attrs) { return ~[]; } - // Need this to parse comments on fields. - let _attrs = self.parse_outer_attributes(); - if self.eat_keyword(&~"priv") { - return ~[self.parse_single_struct_field(private)] + return ~[self.parse_single_struct_field(private, attrs)] } if self.eat_keyword(&~"pub") { - return ~[self.parse_single_struct_field(public)]; + return ~[self.parse_single_struct_field(public, attrs)]; } if self.try_parse_obsolete_struct_ctor() { return ~[]; } - return ~[self.parse_single_struct_field(inherited)]; + return ~[self.parse_single_struct_field(inherited, attrs)]; } // parse visiility: PUB, PRIV, or nothing diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index f23badd046206..ab958d8b5cef5 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -700,6 +700,7 @@ pub fn print_struct(s: @ps, ast::named_field(ident, mutability, visibility) => { hardbreak_if_not_bol(s); maybe_print_comment(s, field.span.lo); + print_outer_attributes(s, field.node.attrs); print_visibility(s, visibility); if mutability == ast::struct_mutable { word_nbsp(s, ~"mut"); From 5fee32457fdb9ad495c9f19fa59e8b9b6c34f48b Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 30 Apr 2013 22:42:36 -0700 Subject: [PATCH 102/215] syntax: remove parse::token::{dtor,literally_dtor} --- src/libsyntax/parse/token.rs | 145 +++++++++++++++++------------------ 1 file changed, 70 insertions(+), 75 deletions(-) diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 0327a3b80da87..4c1a92f898e2d 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -305,50 +305,47 @@ pub fn is_bar(t: &Token) -> bool { pub mod special_idents { use ast::ident; - pub static underscore : ident = ident { repr: 0u, ctxt: 0}; - pub static anon : ident = ident { repr: 1u, ctxt: 0}; - pub static dtor : ident = ident { repr: 2u, ctxt: 0}; // 'drop', but that's - // reserved - pub static invalid : ident = ident { repr: 3u, ctxt: 0}; // '' - pub static unary : ident = ident { repr: 4u, ctxt: 0}; - pub static not_fn : ident = ident { repr: 5u, ctxt: 0}; - pub static idx_fn : ident = ident { repr: 6u, ctxt: 0}; - pub static unary_minus_fn : ident = ident { repr: 7u, ctxt: 0}; - pub static clownshoes_extensions : ident = ident { repr: 8u, ctxt: 0}; - - pub static self_ : ident = ident { repr: 9u, ctxt: 0}; // 'self' + pub static underscore : ident = ident { repr: 0, ctxt: 0}; + pub static anon : ident = ident { repr: 1, ctxt: 0}; + pub static invalid : ident = ident { repr: 2, ctxt: 0}; // '' + pub static unary : ident = ident { repr: 3, ctxt: 0}; + pub static not_fn : ident = ident { repr: 4, ctxt: 0}; + pub static idx_fn : ident = ident { repr: 5, ctxt: 0}; + pub static unary_minus_fn : ident = ident { repr: 6, ctxt: 0}; + pub static clownshoes_extensions : ident = ident { repr: 7, ctxt: 0}; + + pub static self_ : ident = ident { repr: 8, ctxt: 0}; // 'self' /* for matcher NTs */ - pub static item : ident = ident { repr: 10u, ctxt: 0}; - pub static block : ident = ident { repr: 11u, ctxt: 0}; - pub static stmt : ident = ident { repr: 12u, ctxt: 0}; - pub static pat : ident = ident { repr: 13u, ctxt: 0}; - pub static expr : ident = ident { repr: 14u, ctxt: 0}; - pub static ty : ident = ident { repr: 15u, ctxt: 0}; - pub static ident : ident = ident { repr: 16u, ctxt: 0}; - pub static path : ident = ident { repr: 17u, ctxt: 0}; - pub static tt : ident = ident { repr: 18u, ctxt: 0}; - pub static matchers : ident = ident { repr: 19u, ctxt: 0}; - - pub static str : ident = ident { repr: 20u, ctxt: 0}; // for the type + pub static item : ident = ident { repr: 9, ctxt: 0}; + pub static block : ident = ident { repr: 10, ctxt: 0}; + pub static stmt : ident = ident { repr: 11, ctxt: 0}; + pub static pat : ident = ident { repr: 12, ctxt: 0}; + pub static expr : ident = ident { repr: 13, ctxt: 0}; + pub static ty : ident = ident { repr: 14, ctxt: 0}; + pub static ident : ident = ident { repr: 15, ctxt: 0}; + pub static path : ident = ident { repr: 16, ctxt: 0}; + pub static tt : ident = ident { repr: 17, ctxt: 0}; + pub static matchers : ident = ident { repr: 18, ctxt: 0}; + + pub static str : ident = ident { repr: 19, ctxt: 0}; // for the type /* outside of libsyntax */ - pub static ty_visitor : ident = ident { repr: 21u, ctxt: 0}; - pub static arg : ident = ident { repr: 22u, ctxt: 0}; - pub static descrim : ident = ident { repr: 23u, ctxt: 0}; - pub static clownshoe_abi : ident = ident { repr: 24u, ctxt: 0}; - pub static clownshoe_stack_shim : ident = ident { repr: 25u, ctxt: 0}; - pub static tydesc : ident = ident { repr: 26u, ctxt: 0}; - pub static literally_dtor : ident = ident { repr: 27u, ctxt: 0}; - pub static main : ident = ident { repr: 28u, ctxt: 0}; - pub static opaque : ident = ident { repr: 29u, ctxt: 0}; - pub static blk : ident = ident { repr: 30u, ctxt: 0}; - pub static static : ident = ident { repr: 31u, ctxt: 0}; - pub static intrinsic : ident = ident { repr: 32u, ctxt: 0}; - pub static clownshoes_foreign_mod: ident = ident { repr: 33u, ctxt: 0}; - pub static unnamed_field: ident = ident { repr: 34u, ctxt: 0}; - pub static c_abi: ident = ident { repr: 35u, ctxt: 0}; - pub static type_self: ident = ident { repr: 36u, ctxt: 0}; // `Self` + pub static ty_visitor : ident = ident { repr: 20, ctxt: 0}; + pub static arg : ident = ident { repr: 21, ctxt: 0}; + pub static descrim : ident = ident { repr: 22, ctxt: 0}; + pub static clownshoe_abi : ident = ident { repr: 23, ctxt: 0}; + pub static clownshoe_stack_shim : ident = ident { repr: 24, ctxt: 0}; + pub static tydesc : ident = ident { repr: 25, ctxt: 0}; + pub static main : ident = ident { repr: 26, ctxt: 0}; + pub static opaque : ident = ident { repr: 27, ctxt: 0}; + pub static blk : ident = ident { repr: 28, ctxt: 0}; + pub static static : ident = ident { repr: 29, ctxt: 0}; + pub static intrinsic : ident = ident { repr: 30, ctxt: 0}; + pub static clownshoes_foreign_mod: ident = ident { repr: 31, ctxt: 0}; + pub static unnamed_field: ident = ident { repr: 32, ctxt: 0}; + pub static c_abi: ident = ident { repr: 33, ctxt: 0}; + pub static type_self: ident = ident { repr: 34, ctxt: 0}; // `Self` } pub struct StringRef<'self>(&'self str); @@ -426,41 +423,39 @@ pub fn mk_fresh_ident_interner() -> @ident_interner { let init_vec = ~[ @~"_", // 0 @~"anon", // 1 - @~"drop", // 2 - @~"", // 3 - @~"unary", // 4 - @~"!", // 5 - @~"[]", // 6 - @~"unary-", // 7 - @~"__extensions__", // 8 - @~"self", // 9 - @~"item", // 10 - @~"block", // 11 - @~"stmt", // 12 - @~"pat", // 13 - @~"expr", // 14 - @~"ty", // 15 - @~"ident", // 16 - @~"path", // 17 - @~"tt", // 18 - @~"matchers", // 19 - @~"str", // 20 - @~"TyVisitor", // 21 - @~"arg", // 22 - @~"descrim", // 23 - @~"__rust_abi", // 24 - @~"__rust_stack_shim", // 25 - @~"TyDesc", // 26 - @~"dtor", // 27 - @~"main", // 28 - @~"", // 29 - @~"blk", // 30 - @~"static", // 31 - @~"intrinsic", // 32 - @~"__foreign_mod__", // 33 - @~"__field__", // 34 - @~"C", // 35 - @~"Self", // 36 + @~"", // 2 + @~"unary", // 3 + @~"!", // 4 + @~"[]", // 5 + @~"unary-", // 6 + @~"__extensions__", // 7 + @~"self", // 8 + @~"item", // 9 + @~"block", // 10 + @~"stmt", // 11 + @~"pat", // 12 + @~"expr", // 13 + @~"ty", // 14 + @~"ident", // 15 + @~"path", // 16 + @~"tt", // 17 + @~"matchers", // 18 + @~"str", // 19 + @~"TyVisitor", // 20 + @~"arg", // 21 + @~"descrim", // 22 + @~"__rust_abi", // 23 + @~"__rust_stack_shim", // 24 + @~"TyDesc", // 25 + @~"main", // 26 + @~"", // 27 + @~"blk", // 28 + @~"static", // 29 + @~"intrinsic", // 30 + @~"__foreign_mod__", // 31 + @~"__field__", // 32 + @~"C", // 33 + @~"Self", // 34 ]; let rv = @ident_interner { From e9688fcfe3d345ae34e25c3bd51f878be4410d96 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 30 Apr 2013 22:47:09 -0700 Subject: [PATCH 103/215] remove some warnings --- src/compiletest/header.rs | 3 +-- src/compiletest/runtest.rs | 2 +- src/libsyntax/ast_util.rs | 2 +- src/libsyntax/parse/mod.rs | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index b0d04c6739b4a..b29e1c77be35e 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -82,14 +82,13 @@ pub fn load_props(testfile: &Path) -> TestProps { } pub fn is_test_ignored(config: config, testfile: &Path) -> bool { - let mut found = false; for iter_header(testfile) |ln| { if parse_name_directive(ln, ~"xfail-test") { return true; } if parse_name_directive(ln, xfail_target()) { return true; } if config.mode == common::mode_pretty && parse_name_directive(ln, ~"xfail-pretty") { return true; } }; - return found; + return true; fn xfail_target() -> ~str { ~"xfail-" + str::from_slice(os::SYSNAME) diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index fef4cabf7fd6d..5805c1730296c 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -106,7 +106,7 @@ fn run_rpass_test(config: config, props: TestProps, testfile: &Path) { fatal_ProcRes(~"test run failed!", ProcRes); } } else { - let mut ProcRes = jit_test(config, props, testfile); + let ProcRes = jit_test(config, props, testfile); if ProcRes.status != 0 { fatal_ProcRes(~"jit failed!", ProcRes); } } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index bf5381831d054..283c232fb3f0e 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -11,7 +11,7 @@ use ast::*; use ast; use ast_util; -use codemap::{span, dummy_sp, spanned}; +use codemap::{span, spanned}; use parse::token; use visit; use opt_vec; diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 7e7931bbb606b..5d51a54d770b1 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -24,7 +24,7 @@ use parse::token::{ident_interner, mk_ident_interner}; use core::io; use core::option::{None, Option, Some}; use core::path::Path; -use core::result::{Err, Ok, Result}; +use core::result::{Err, Ok}; pub mod lexer; pub mod parser; From e7a3bbd76c77fa7a878ecd86dcb5c772164cbb51 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 30 Apr 2013 23:30:04 -0700 Subject: [PATCH 104/215] rustdoc: Remove a now invalid test --- src/librustdoc/tystr_pass.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/librustdoc/tystr_pass.rs b/src/librustdoc/tystr_pass.rs index a6fbee81bc8af..def32bdfd44d6 100644 --- a/src/librustdoc/tystr_pass.rs +++ b/src/librustdoc/tystr_pass.rs @@ -434,13 +434,6 @@ mod test { "struct S {")); } - #[test] - fn should_not_serialize_struct_drop_blocks() { - // All we care about are the fields - let doc = mk_doc(~"struct S { field: (), drop { } }"); - assert!(!(&doc.cratemod().structs()[0].sig).get().contains("drop")); - } - #[test] fn should_not_serialize_struct_attrs() { // All we care about are the fields From 7c9d089ee732c2930898574d9ecedbb01efe0eb9 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Wed, 1 May 2013 07:49:10 -0700 Subject: [PATCH 105/215] pipes: use finally to fix pipes::try_recv --- src/libcore/pipes.rs | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 82dc598c750eb..145997fcb4bd5 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -88,6 +88,7 @@ use kinds::Owned; use libc; use ops::Drop; use option::{None, Option, Some}; +use unstable::finally::Finally; use unstable::intrinsics; use ptr; use task; @@ -396,28 +397,22 @@ pub fn try_recv(p: RecvPacketBuffered) let p_ = p.unwrap(); let p = unsafe { &*p_ }; - struct DropState<'self> { - p: &'self PacketHeader, - } - - #[unsafe_destructor] - impl<'self> Drop for DropState<'self> { - fn finalize(&self) { - unsafe { - if task::failing() { - self.p.state = Terminated; - let old_task = swap_task(&mut self.p.blocked_task, - ptr::null()); - if !old_task.is_null() { - rustrt::rust_task_deref(old_task); - } + do (|| { + try_recv_(p) + }).finally { + unsafe { + if task::failing() { + p.header.state = Terminated; + let old_task = swap_task(&mut p.header.blocked_task, ptr::null()); + if !old_task.is_null() { + rustrt::rust_task_deref(old_task); } } } } +} - let _drop_state = DropState { p: &p.header }; - +fn try_recv_(p: &Packet) -> Option { // optimistic path match p.header.state { Full => { @@ -454,7 +449,7 @@ pub fn try_recv(p: RecvPacketBuffered) Blocked); match old_state { Empty => { - debug!("no data available on %?, going to sleep.", p_); + debug!("no data available on %?, going to sleep.", p); if count == 0 { wait_event(this); } From 3159335ac308d9e3a2d3ada3b9354bf160debbdc Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2013 10:31:10 -0400 Subject: [PATCH 106/215] avoid broken += operator, bogus use of const --- src/test/run-pass/auto-ref-slice-plus-ref.rs | 2 +- src/test/run-pass/lambda-infer-unresolved.rs | 2 +- src/test/run-pass/reflect-visit-data.rs | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/test/run-pass/auto-ref-slice-plus-ref.rs b/src/test/run-pass/auto-ref-slice-plus-ref.rs index 07629651e5605..58a477900c324 100644 --- a/src/test/run-pass/auto-ref-slice-plus-ref.rs +++ b/src/test/run-pass/auto-ref-slice-plus-ref.rs @@ -23,7 +23,7 @@ impl<'self> MyIter for &'self [int] { impl<'self> MyIter for &'self str { fn test_imm(&self) { assert_eq!(*self, "test") } - fn test_const(&const self) { assert_eq!(self[0], 't') } + fn test_const(&const self) { assert_eq!(self[0], 't' as u8) } } pub fn main() { diff --git a/src/test/run-pass/lambda-infer-unresolved.rs b/src/test/run-pass/lambda-infer-unresolved.rs index 2e70e90038971..4aeeda8312cac 100644 --- a/src/test/run-pass/lambda-infer-unresolved.rs +++ b/src/test/run-pass/lambda-infer-unresolved.rs @@ -17,5 +17,5 @@ struct Refs { refs: ~[int], n: int } pub fn main() { let e = @mut Refs{refs: ~[], n: 0}; let f: @fn() = || error!(copy e.n); - e.refs += ~[1]; + e.refs.push(1); } diff --git a/src/test/run-pass/reflect-visit-data.rs b/src/test/run-pass/reflect-visit-data.rs index e520d221c9935..5b01d24aa8be1 100644 --- a/src/test/run-pass/reflect-visit-data.rs +++ b/src/test/run-pass/reflect-visit-data.rs @@ -513,16 +513,16 @@ impl TyVisitor for my_visitor { fn visit_bot(&self) -> bool { true } fn visit_nil(&self) -> bool { true } fn visit_bool(&self) -> bool { - do self.get::() |b| { - self.vals += ~[bool::to_str(b)]; - }; - true + do self.get::() |b| { + self.vals.push(bool::to_str(b)); + }; + true } fn visit_int(&self) -> bool { - do self.get::() |i| { - self.vals += ~[int::to_str(i)]; - }; - true + do self.get::() |i| { + self.vals.push(int::to_str(i)); + }; + true } fn visit_i8(&self) -> bool { true } fn visit_i16(&self) -> bool { true } From 38f93f2121e111dd9dd149f5bdeaa9a34a4e42f1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2013 13:48:00 -0400 Subject: [PATCH 107/215] wip---work on making rooting work properly --- src/libcore/num/int-template.rs | 4 + src/libcore/num/uint-template.rs | 4 + src/libcore/unstable/lang.rs | 67 ++++++++++++++--- src/librustc/middle/lang_items.rs | 22 ++++-- src/librustc/middle/trans/base.rs | 65 ++++------------- src/librustc/middle/trans/common.rs | 52 ++++++++----- src/librustc/middle/trans/datum.rs | 73 ++++++++++++------- .../borrowck-loan-rcvr-overloaded-op.rs | 5 +- 8 files changed, 175 insertions(+), 117 deletions(-) diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index 85489755fc7a9..77b4eab133865 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -200,6 +200,8 @@ impl Mul for T { #[inline(always)] fn mul(&self, other: &T) -> T { *self * *other } } + +#[cfg(notest)] impl Quot for T { /// /// Returns the integer quotient, truncated towards 0. As this behaviour reflects @@ -222,6 +224,8 @@ impl Quot for T { #[inline(always)] fn quot(&self, other: &T) -> T { *self / *other } } + +#[cfg(notest)] impl Rem for T { /// /// Returns the integer remainder after division, satisfying: diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index f975226cde63b..2d20444946865 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -165,10 +165,14 @@ impl Mul for T { #[inline(always)] fn mul(&self, other: &T) -> T { *self * *other } } + +#[cfg(notest)] impl Quot for T { #[inline(always)] fn quot(&self, other: &T) -> T { *self / *other } } + +#[cfg(notest)] impl Rem for T { #[inline(always)] fn rem(&self, other: &T) -> T { *self % *other } diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 0705be7cdefe5..d0e3c2b06787f 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -10,6 +10,7 @@ //! Runtime calls emitted by the compiler. +use uint; use cast::transmute; use libc::{c_char, c_uchar, c_void, size_t, uintptr_t, c_int, STDERR_FILENO}; use managed::raw::BoxRepr; @@ -22,10 +23,9 @@ use task::rt::rust_get_task; #[allow(non_camel_case_types)] pub type rust_task = c_void; -#[cfg(target_word_size = "32")] -pub static FROZEN_BIT: uint = 0x80000000; -#[cfg(target_word_size = "64")] -pub static FROZEN_BIT: uint = 0x8000000000000000; +pub static FROZEN_BIT: uint = 1 << (uint::bits - 1); +pub static MUT_BIT: uint = 1 << (uint::bits - 2); +static ALL_BITS: uint = FROZEN_BIT | MUT_BIT; pub mod rustrt { use unstable::lang::rust_task; @@ -196,21 +196,51 @@ pub unsafe fn borrow_as_imm(a: *u8) { (*a).header.ref_count |= FROZEN_BIT; } +fn add_borrow_to_task_list(a: *mut BoxRepr, file: *c_char, line: size_t) { + do swap_task_borrow_list |borrow_list| { + let mut borrow_list = borrow_list; + borrow_list.push(BorrowRecord {box: a, file: file, line: line}); + borrow_list + } +} + #[cfg(not(stage0))] #[lang="borrow_as_imm"] #[inline(always)] -pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) { +pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { let a: *mut BoxRepr = transmute(a); - (*a).header.ref_count |= FROZEN_BIT; - if ::rt::env::get().debug_borrows { - do swap_task_borrow_list |borrow_list| { - let mut borrow_list = borrow_list; - borrow_list.push(BorrowRecord {box: a, file: file, line: line}); - borrow_list + + let ref_count = (*a).header.ref_count; + if (ref_count & MUT_BIT) != 0 { + fail_borrowed(a, file, line); + } else { + (*a).header.ref_count |= FROZEN_BIT; + if ::rt::env::get().debug_borrows { + add_borrow_to_list(a, file, line); } } + ref_count } +#[cfg(not(stage0))] +#[lang="borrow_as_mut"] +#[inline(always)] +pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint { + let a: *mut BoxRepr = transmute(a); + + let ref_count = (*a).header.ref_count; + if (ref_count & (MUT_BIT|FROZEN_BIT)) != 0 { + fail_borrowed(a, file, line); + } else { + (*a).header.ref_count |= (MUT_BIT|FROZEN_BIT); + if ::rt::env::get().debug_borrows { + add_borrow_to_list(a, file, line); + } + } + ref_count +} + +#[cfg(stage0)] #[lang="return_to_mut"] #[inline(always)] pub unsafe fn return_to_mut(a: *u8) { @@ -222,6 +252,21 @@ pub unsafe fn return_to_mut(a: *u8) { } } +#[cfg(not(stage0))] +#[lang="return_to_mut"] +#[inline(always)] +pub unsafe fn return_to_mut(a: *u8, old_ref_count: uint) { + // Sometimes the box is null, if it is conditionally frozen. + // See e.g. #4904. + if !a.is_null() { + let a: *mut BoxRepr = transmute(a); + + let ref_count = (*a).header.ref_count & !ALL_BITS; + let old_bits = old_ref_count & ALL_BITS; + (*a).header.ref_count = ref_count | old_bits; + } +} + #[cfg(stage0)] #[lang="check_not_borrowed"] #[inline(always)] diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index e7261d53952a2..0266b77997e7d 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -66,11 +66,12 @@ pub enum LangItem { MallocFnLangItem, // 28 FreeFnLangItem, // 29 BorrowAsImmFnLangItem, // 30 - ReturnToMutFnLangItem, // 31 - CheckNotBorrowedFnLangItem, // 32 - StrDupUniqFnLangItem, // 33 + BorrowAsMutFnLangItem, // 31 + ReturnToMutFnLangItem, // 32 + CheckNotBorrowedFnLangItem, // 33 + StrDupUniqFnLangItem, // 34 - StartFnLangItem, // 34 + StartFnLangItem, // 35 } pub struct LanguageItems { @@ -128,11 +129,12 @@ pub impl LanguageItems { 28 => "malloc", 29 => "free", 30 => "borrow_as_imm", - 31 => "return_to_mut", - 32 => "check_not_borrowed", - 33 => "strdup_uniq", + 31 => "borrow_as_mut", + 32 => "return_to_mut", + 33 => "check_not_borrowed", + 34 => "strdup_uniq", - 34 => "start", + 35 => "start", _ => "???" } @@ -237,6 +239,9 @@ pub impl LanguageItems { pub fn borrow_as_imm_fn(&const self) -> def_id { self.items[BorrowAsImmFnLangItem as uint].get() } + pub fn borrow_as_mut_fn(&const self) -> def_id { + self.items[BorrowAsMutFnLangItem as uint].get() + } pub fn return_to_mut_fn(&const self) -> def_id { self.items[ReturnToMutFnLangItem as uint].get() } @@ -292,6 +297,7 @@ fn LanguageItemCollector(crate: @crate, item_refs.insert(@~"malloc", MallocFnLangItem as uint); item_refs.insert(@~"free", FreeFnLangItem as uint); item_refs.insert(@~"borrow_as_imm", BorrowAsImmFnLangItem as uint); + item_refs.insert(@~"borrow_as_mut", BorrowAsMutFnLangItem as uint); item_refs.insert(@~"return_to_mut", ReturnToMutFnLangItem as uint); item_refs.insert(@~"check_not_borrowed", CheckNotBorrowedFnLangItem as uint); diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 1785feda7790c..7738e97779971 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -991,63 +991,30 @@ pub fn get_landing_pad(bcx: block) -> BasicBlockRef { return pad_bcx.llbb; } -// Arranges for the value found in `*root_loc` to be dropped once the scope -// associated with `scope_id` exits. This is used to keep boxes live when -// there are extant region pointers pointing at the interior. -// -// Note that `root_loc` is not the value itself but rather a pointer to the -// value. Generally it in alloca'd value. The reason for this is that the -// value is initialized in an inner block but may be freed in some outer -// block, so an SSA value that is valid in the inner block may not be valid in -// the outer block. In fact, the inner block may not even execute. Rather -// than generate the full SSA form, we just use an alloca'd value. -pub fn add_root_cleanup(bcx: block, - root_info: RootInfo, - root_loc: ValueRef, - ty: ty::t) { - - debug!("add_root_cleanup(bcx=%s, \ - scope=%d, \ - freezes=%?, \ - root_loc=%s, \ - ty=%s)", - bcx.to_str(), - root_info.scope, - root_info.freeze, - val_str(bcx.ccx().tn, root_loc), - ppaux::ty_to_str(bcx.ccx().tcx, ty)); - - let bcx_scope = find_bcx_for_scope(bcx, root_info.scope); - if root_info.freeze.is_some() { - add_clean_frozen_root(bcx_scope, root_loc, ty); - } else { - add_clean_temp_mem(bcx_scope, root_loc, ty); - } - - fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block { - let mut bcx_sid = bcx; - loop { - bcx_sid = match bcx_sid.node_info { - Some(NodeInfo { id, _ }) if id == scope_id => { +pub fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block { + let mut bcx_sid = bcx; + loop { + bcx_sid = match bcx_sid.node_info { + Some(NodeInfo { id, _ }) if id == scope_id => { return bcx_sid } - // NOTE This is messier than it ought to be and not really right - Some(NodeInfo { callee_id: Some(id), _ }) if id == scope_id => { - return bcx_sid - } + // NOTE This is messier than it ought to be and not really right + Some(NodeInfo { callee_id: Some(id), _ }) if id == scope_id => { + return bcx_sid + } - _ => { - match bcx_sid.parent { - None => bcx.tcx().sess.bug( - fmt!("no enclosing scope with id %d", scope_id)), - Some(bcx_par) => bcx_par + _ => { + match bcx_sid.parent { + None => bcx.tcx().sess.bug( + fmt!("no enclosing scope with id %d", scope_id)), + Some(bcx_par) => bcx_par + } } - } } } } -} + pub fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef { if ty::type_is_bot(t) { diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 2ebd696dbfdef..d0da8a2e1ee74 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -467,28 +467,40 @@ pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { scope_clean_changed(scope_info); } } -pub fn add_clean_frozen_root(bcx: block, val: ValueRef, t: ty::t) { - debug!("add_clean_frozen_root(%s, %s, %s)", - bcx.to_str(), val_str(bcx.ccx().tn, val), - t.repr(bcx.tcx())); - let (root, rooted) = root_for_cleanup(bcx, val, t); - let cleanup_type = cleanup_type(bcx.tcx(), t); +pub fn add_clean_return_to_mut(bcx: block, + frozen_val_ref: ValueRef, + bits_val_ref: ValueRef) { + //! When an `@mut` has been frozen, we have to + //! call the lang-item `return_to_mut` when the + //! freeze goes out of scope. We need to pass + //! in both the value which was frozen (`frozen_val`) and + //! the value (`bits_val_ref`) which was returned when the + //! box was frozen initially. Here, both `frozen_val_ref` and + //! `bits_val_ref` are in fact pointers to stack slots. + + debug!("add_clean_return_to_mut(%s, %s, %s)", + bcx.to_str(), + val_str(bcx.ccx().tn, frozen_val_ref), + val_str(bcx.ccx().tn, bits_val_ref)); do in_scope_cx(bcx) |scope_info| { scope_info.cleanups.push( - clean_temp(val, |bcx| { - let bcx = callee::trans_lang_call( - bcx, - bcx.tcx().lang_items.return_to_mut_fn(), - ~[ - build::Load(bcx, - build::PointerCast(bcx, - root, - T_ptr(T_ptr(T_i8())))) - ], - expr::Ignore - ); - glue::drop_ty_root(bcx, root, rooted, t) - }, cleanup_type)); + clean_temp( + frozen_val_ref, + |bcx| { + callee::trans_lang_call( + bcx, + bcx.tcx().lang_items.return_to_mut_fn(), + ~[ + build::Load(bcx, + build::PointerCast(bcx, + frozen_val_ref, + T_ptr(T_ptr(T_i8())))), + build::Load(bcx, bits_val_ref) + ], + expr::Ignore + ) + }, + normal_exit_only)); scope_clean_changed(scope_info); } } diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index ae71a3e6c22c0..94bff65843b24 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -87,7 +87,7 @@ use lib; use lib::llvm::ValueRef; -use middle::borrowck::{RootInfo, root_map_key}; +use middle::borrowck::{RootInfo, root_map_key, DynaImm, DynaMut}; use middle::trans::adt; use middle::trans::base::*; use middle::trans::build::*; @@ -517,7 +517,7 @@ pub impl Datum { } } - fn root(&self, bcx: block, span: span, root_info: RootInfo) -> block { + fn root(&self, mut bcx: block, span: span, root_info: RootInfo) -> block { /*! * * In some cases, borrowck will decide that an @T/@[]/@str @@ -535,34 +535,53 @@ pub impl Datum { root_info.scope)); } + // First, root the datum. Note that we must zero this value, + // because sometimes we root on one path but not another. + // See e.g. #4904. let scratch = scratch_datum(bcx, self.ty, true); self.copy_to_datum(bcx, INIT, scratch); - add_root_cleanup(bcx, root_info, scratch.val, scratch.ty); - - // If we need to freeze the box, do that now. - if root_info.freeze.is_some() { - // NOTE distinguish the two kinds of freezing here - - let loc = bcx.sess().parse_sess.cm.lookup_char_pos(span.lo); - let line = C_int(bcx.ccx(), loc.line as int); - let filename_cstr = C_cstr(bcx.ccx(), @/*bad*/copy loc.file.name); - let filename = PointerCast(bcx, filename_cstr, T_ptr(T_i8())); - - callee::trans_lang_call( - bcx, - bcx.tcx().lang_items.borrow_as_imm_fn(), - ~[ - Load(bcx, - PointerCast(bcx, - scratch.val, - T_ptr(T_ptr(T_i8())))), - filename, - line - ], - expr::Ignore) - } else { - bcx + let cleanup_bcx = find_bcx_for_scope(bcx, root_info.scope); + add_clean_temp_mem(cleanup_bcx, scratch.val, scratch.ty); + + // Now, consider also freezing it. + match root_info.freeze { + None => {} + Some(freeze_kind) => { + let loc = bcx.sess().parse_sess.cm.lookup_char_pos(span.lo); + let line = C_int(bcx.ccx(), loc.line as int); + let filename_cstr = C_cstr(bcx.ccx(), @/*bad*/copy loc.file.name); + let filename = PointerCast(bcx, filename_cstr, T_ptr(T_i8())); + + // in this case, we don't have to zero, because + // scratch.val will be NULL should the cleanup get + // called without the freezing actually occurring, and + // return_to_mut checks for this condition. + let scratch_bits = scratch_datum(bcx, ty::mk_uint(), false); + + let freeze_did = match freeze_kind { + DynaImm => bcx.tcx().lang_items.borrow_as_imm_fn(), + DynaMut => bcx.tcx().lang_items.borrow_as_mut_fn(), + }; + + bcx = callee::trans_lang_call( + bcx, + freeze_did, + ~[ + Load(bcx, + PointerCast(bcx, + scratch.val, + T_ptr(T_ptr(T_i8())))), + filename, + line + ], + expr::SaveIn(scratch_bits.val)); + + add_clean_return_to_mut( + cleanup_bcx, scratch.val, scratch_bits.val); + } } + + bcx } fn perform_write_guard(&self, bcx: block, span: span) -> block { diff --git a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs index 8c9d3009e5e67..2c4ae242fb483 100644 --- a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs +++ b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs @@ -40,10 +40,11 @@ fn b() { let q = &mut p; - p + 3; // ok for pure fns + p + 3; //~ ERROR cannot borrow `p` p.times(3); //~ ERROR cannot borrow `p` - q.x += 1; + *q + 3; // OK to use the new alias `q` + q.x += 1; // and OK to mutate it } fn c() { From 08dd625d455548c7a5795db930ebfc5e3b1eb9c4 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Wed, 1 May 2013 14:58:21 -0700 Subject: [PATCH 108/215] compiletest: stop ignoring all tests. --- src/compiletest/header.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiletest/header.rs b/src/compiletest/header.rs index b29e1c77be35e..28bbbda966340 100644 --- a/src/compiletest/header.rs +++ b/src/compiletest/header.rs @@ -88,7 +88,7 @@ pub fn is_test_ignored(config: config, testfile: &Path) -> bool { if config.mode == common::mode_pretty && parse_name_directive(ln, ~"xfail-pretty") { return true; } }; - return true; + return false; fn xfail_target() -> ~str { ~"xfail-" + str::from_slice(os::SYSNAME) From 046a285a4b6ae54aa8f8a1d4b0e1e8d22478b4f6 Mon Sep 17 00:00:00 2001 From: gifnksm Date: Tue, 30 Apr 2013 20:01:26 +0900 Subject: [PATCH 109/215] libstd: impl Clone for BigUint/BigInt and replace `copy` with `.clone()` --- src/libstd/num/bigint.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/libstd/num/bigint.rs b/src/libstd/num/bigint.rs index fa9d6318cc947..e2a336027fdef 100644 --- a/src/libstd/num/bigint.rs +++ b/src/libstd/num/bigint.rs @@ -80,6 +80,7 @@ A big unsigned integer type. A BigUint-typed value BigUint { data: @[a, b, c] } represents a number (a + b * BigDigit::base + c * BigDigit::base^2). */ +#[deriving(Clone)] pub struct BigUint { priv data: ~[BigDigit] } @@ -680,7 +681,7 @@ priv fn get_radix_base(radix: uint) -> (uint, uint) { } /// A Sign is a BigInt's composing element. -#[deriving(Eq)] +#[deriving(Eq, Clone)] pub enum Sign { Minus, Zero, Plus } impl Ord for Sign { @@ -726,6 +727,7 @@ impl Neg for Sign { } /// A big signed integer type. +#[deriving(Clone)] pub struct BigInt { priv sign: Sign, priv data: BigUint @@ -825,8 +827,8 @@ impl Signed for BigInt { #[inline(always)] fn abs(&self) -> BigInt { match self.sign { - Plus | Zero => copy *self, - Minus => BigInt::from_biguint(Plus, copy self.data) + Plus | Zero => self.clone(), + Minus => BigInt::from_biguint(Plus, self.data.clone()) } } @@ -850,8 +852,8 @@ impl Add for BigInt { #[inline(always)] fn add(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { - (Zero, _) => copy *other, - (_, Zero) => copy *self, + (Zero, _) => other.clone(), + (_, Zero) => self.clone(), (Plus, Plus) => BigInt::from_biguint(Plus, self.data + other.data), (Plus, Minus) => self - (-*other), @@ -866,7 +868,7 @@ impl Sub for BigInt { fn sub(&self, other: &BigInt) -> BigInt { match (self.sign, other.sign) { (Zero, _) => -other, - (_, Zero) => copy *self, + (_, Zero) => self.clone(), (Plus, Plus) => match self.data.cmp(&other.data) { Less => BigInt::from_biguint(Minus, other.data - self.data), Greater => BigInt::from_biguint(Plus, self.data - other.data), @@ -913,7 +915,7 @@ impl Rem for BigInt { impl Neg for BigInt { #[inline(always)] fn neg(&self) -> BigInt { - BigInt::from_biguint(self.sign.neg(), copy self.data) + BigInt::from_biguint(self.sign.neg(), self.data.clone()) } } @@ -1100,9 +1102,9 @@ pub impl BigInt { #[cfg(test)] mod biguint_tests { + use super::*; use core::num::{IntConvertible, Zero, One, FromStrRadix}; use core::cmp::{Less, Equal, Greater}; - use super::{BigUint, BigDigit}; #[test] fn test_from_slice() { @@ -1390,10 +1392,10 @@ mod biguint_tests { let c = BigUint::from_slice(cVec); if !a.is_zero() { - assert!(c.div_rem(&a) == (copy b, Zero::zero())); + assert!(c.div_rem(&a) == (b.clone(), Zero::zero())); } if !b.is_zero() { - assert!(c.div_rem(&b) == (copy a, Zero::zero())); + assert!(c.div_rem(&b) == (a.clone(), Zero::zero())); } } @@ -1555,7 +1557,7 @@ mod biguint_tests { #[cfg(test)] mod bigint_tests { - use super::{BigInt, BigUint, BigDigit, Sign, Minus, Zero, Plus}; + use super::*; use core::cmp::{Less, Equal, Greater}; use core::num::{IntConvertible, Zero, One, FromStrRadix}; From c64471ab8624e256c745dfd5d5e89ea6aa9e8228 Mon Sep 17 00:00:00 2001 From: Daniel Ralston Date: Wed, 1 May 2013 01:59:36 -0700 Subject: [PATCH 110/215] Add trait object field types to back/abi.rs, and use them I've added trt_field_vtable, trt_field_box, and trt_field_tydesc, and inserted them in place of the "magic numbers" used to access trait object fields through GEPi(). --- src/librustc/back/abi.rs | 7 +++++++ src/librustc/middle/trans/glue.rs | 12 ++++++------ src/librustc/middle/trans/meth.rs | 26 +++++++++++++++----------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/librustc/back/abi.rs b/src/librustc/back/abi.rs index 70a029ede6f8d..6d963d7cfd2cb 100644 --- a/src/librustc/back/abi.rs +++ b/src/librustc/back/abi.rs @@ -57,6 +57,13 @@ pub static n_tydesc_fields: uint = 8u; pub static fn_field_code: uint = 0u; pub static fn_field_box: uint = 1u; +// The three fields of a trait object/trait instance: vtable, box, and type +// description. +pub static trt_field_vtable: uint = 0u; +pub static trt_field_box: uint = 1u; +// This field is only present in unique trait objects, so it comes last. +pub static trt_field_tydesc: uint = 2u; + pub static vec_elt_fill: uint = 0u; pub static vec_elt_alloc: uint = 1u; diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 4c5a17056b2ea..f1888084c0b05 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -549,12 +549,12 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { closure::make_closure_glue(bcx, v0, t, drop_ty) } ty::ty_trait(_, _, ty::BoxTraitStore, _) => { - let llbox = Load(bcx, GEPi(bcx, v0, [0u, 1u])); + let llbox = Load(bcx, GEPi(bcx, v0, [0u, abi::trt_field_box])); decr_refcnt_maybe_free(bcx, llbox, ty::mk_opaque_box(ccx.tcx)) } ty::ty_trait(_, _, ty::UniqTraitStore, _) => { - let lluniquevalue = GEPi(bcx, v0, [0, 1]); - let lltydesc = Load(bcx, GEPi(bcx, v0, [0, 2])); + let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]); + let lltydesc = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_tydesc])); call_tydesc_glue_full(bcx, lluniquevalue, lltydesc, abi::tydesc_field_free_glue, None); bcx @@ -613,13 +613,13 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) { closure::make_closure_glue(bcx, v, t, take_ty) } ty::ty_trait(_, _, ty::BoxTraitStore, _) => { - let llbox = Load(bcx, GEPi(bcx, v, [0u, 1u])); + let llbox = Load(bcx, GEPi(bcx, v, [0u, abi::trt_field_box])); incr_refcnt_of_boxed(bcx, llbox); bcx } ty::ty_trait(_, _, ty::UniqTraitStore, _) => { - let llval = GEPi(bcx, v, [0, 1]); - let lltydesc = Load(bcx, GEPi(bcx, v, [0, 2])); + let llval = GEPi(bcx, v, [0, abi::trt_field_box]); + let lltydesc = Load(bcx, GEPi(bcx, v, [0, abi::trt_field_tydesc])); call_tydesc_glue_full(bcx, llval, lltydesc, abi::tydesc_field_take_glue, None); bcx diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 90f9f93be2b48..a90475d9ed085 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -637,14 +637,15 @@ pub fn trans_trait_callee_from_llval(bcx: block, val_str(bcx.ccx().tn, llpair)); let llvtable = Load(bcx, PointerCast(bcx, - GEPi(bcx, llpair, [0u, 0u]), + GEPi(bcx, llpair, + [0u, abi::trt_field_vtable]), T_ptr(T_ptr(T_vtable())))); // Load the box from the @Trait pair and GEP over the box header if // necessary: let mut llself; debug!("(translating trait callee) loading second index from pair"); - let llbox = Load(bcx, GEPi(bcx, llpair, [0u, 1u])); + let llbox = Load(bcx, GEPi(bcx, llpair, [0u, abi::trt_field_box])); // Munge `llself` appropriately for the type of `self` in the method. let self_mode; @@ -845,27 +846,30 @@ pub fn trans_trait_cast(bcx: block, match store { ty::RegionTraitStore(_) | ty::BoxTraitStore => { - let mut llboxdest = GEPi(bcx, lldest, [0u, 1u]); - // Just store the pointer into the pair. + let mut llboxdest = GEPi(bcx, lldest, [0u, abi::trt_field_box]); + // Just store the pointer into the pair. (Region/borrowed + // and boxed trait objects are represented as pairs, and + // have no type descriptor field.) llboxdest = PointerCast(bcx, llboxdest, T_ptr(type_of(bcx.ccx(), v_ty))); bcx = expr::trans_into(bcx, val, SaveIn(llboxdest)); } ty::UniqTraitStore => { - // Translate the uniquely-owned value into the second element of - // the triple. (The first element is the vtable.) - let mut llvaldest = GEPi(bcx, lldest, [0, 1]); + // Translate the uniquely-owned value in the + // triple. (Unique trait objects are represented as + // triples.) + let mut llvaldest = GEPi(bcx, lldest, [0, abi::trt_field_box]); llvaldest = PointerCast(bcx, llvaldest, T_ptr(type_of(bcx.ccx(), v_ty))); bcx = expr::trans_into(bcx, val, SaveIn(llvaldest)); - // Get the type descriptor of the wrapped value and store it into - // the third element of the triple as well. + // Get the type descriptor of the wrapped value and store + // it in the triple as well. let tydesc = get_tydesc(bcx.ccx(), v_ty); glue::lazily_emit_all_tydesc_glue(bcx.ccx(), tydesc); - let lltydescdest = GEPi(bcx, lldest, [0, 2]); + let lltydescdest = GEPi(bcx, lldest, [0, abi::trt_field_tydesc]); Store(bcx, tydesc.tydesc, lltydescdest); } } @@ -875,7 +879,7 @@ pub fn trans_trait_cast(bcx: block, let orig = resolve_vtable_in_fn_ctxt(bcx.fcx, orig); let vtable = get_vtable(bcx.ccx(), orig); Store(bcx, vtable, PointerCast(bcx, - GEPi(bcx, lldest, [0u, 0u]), + GEPi(bcx, lldest, [0u, abi::trt_field_vtable]), T_ptr(val_ty(vtable)))); bcx From 058346219a48ff6ac4c9c2fd38e8f478599ab078 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Tue, 9 Apr 2013 22:18:23 -0500 Subject: [PATCH 111/215] libc bindings for glob.h only tested on linux/x86_64, but i got the values for other platforms from their system header files. no bindings for win32, because win32 doesn't include glob.h. also, glob() takes a callback for error handling, but i'm just making this a *c_void for now, since i don't know how to represent c calling back into rust (if that's even currently possible). --- src/libcore/libc.rs | 108 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 2 deletions(-) diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs index 44864630f9873..b5c444dedf8a7 100644 --- a/src/libcore/libc.rs +++ b/src/libcore/libc.rs @@ -104,6 +104,7 @@ pub use libc::funcs::posix88::unistd::*; pub use libc::funcs::posix01::stat_::*; pub use libc::funcs::posix01::unistd::*; +pub use libc::funcs::posix01::glob::*; pub use libc::funcs::posix08::unistd::*; pub use libc::funcs::bsd44::*; @@ -210,7 +211,21 @@ pub mod types { #[cfg(target_os = "android")] pub mod os { pub mod common { - pub mod posix01 {} + pub mod posix01 { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_char, size_t}; + pub struct glob_t { + gl_pathc: size_t, + gl_pathv: **c_char, + gl_offs: size_t, + + __unused1: *c_void, + __unused2: *c_void, + __unused3: *c_void, + __unused4: *c_void, + __unused5: *c_void, + } + } } #[cfg(target_arch = "x86")] @@ -369,7 +384,25 @@ pub mod types { #[cfg(target_os = "freebsd")] pub mod os { pub mod common { - pub mod posix01 {} + pub mod posix01 { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_char, c_int, size_t}; + struct glob_t { + gl_pathc: size_t, + __unused1: size_t, + gl_offs: size_t, + __unused2: c_int, + gl_pathv: **c_char, + + __unused3: *c_void, + + __unused4: *c_void, + __unused5: *c_void, + __unused6: *c_void, + __unused7: *c_void, + __unused8: *c_void, + } + } } #[cfg(target_arch = "x86_64")] @@ -571,6 +604,23 @@ pub mod types { pub mod os { pub mod common { pub mod posix01 { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_char, c_int, size_t}; + struct glob_t { + gl_pathc: size_t, + __unused1: c_int, + gl_offs: size_t, + __unused2: c_int, + gl_pathv: **c_char, + + __unused3: *c_void, + + __unused4: *c_void, + __unused5: *c_void, + __unused6: *c_void, + __unused7: *c_void, + __unused8: *c_void, + } } } @@ -877,6 +927,18 @@ pub mod consts { } pub mod posix01 { pub static SIGTRAP : int = 5; + + pub static GLOB_ERR : int = 1 << 0; + pub static GLOB_MARK : int = 1 << 1; + pub static GLOB_NOSORT : int = 1 << 2; + pub static GLOB_DOOFFS : int = 1 << 3; + pub static GLOB_NOCHECK : int = 1 << 4; + pub static GLOB_APPEND : int = 1 << 5; + pub static GLOB_NOESCAPE : int = 1 << 6; + + pub static GLOB_NOSPACE : int = 1; + pub static GLOB_ABORTED : int = 2; + pub static GLOB_NOMATCH : int = 3; } pub mod posix08 { } @@ -956,6 +1018,18 @@ pub mod consts { } pub mod posix01 { pub static SIGTRAP : int = 5; + + pub static GLOB_APPEND : int = 0x0001; + pub static GLOB_DOOFFS : int = 0x0002; + pub static GLOB_ERR : int = 0x0004; + pub static GLOB_MARK : int = 0x0008; + pub static GLOB_NOCHECK : int = 0x0010; + pub static GLOB_NOSORT : int = 0x0020; + pub static GLOB_NOESCAPE : int = 0x2000; + + pub static GLOB_NOSPACE : int = -1; + pub static GLOB_ABORTED : int = -2; + pub static GLOB_NOMATCH : int = -3; } pub mod posix08 { } @@ -1036,6 +1110,18 @@ pub mod consts { } pub mod posix01 { pub static SIGTRAP : int = 5; + + pub static GLOB_APPEND : int = 0x0001; + pub static GLOB_DOOFFS : int = 0x0002; + pub static GLOB_ERR : int = 0x0004; + pub static GLOB_MARK : int = 0x0008; + pub static GLOB_NOCHECK : int = 0x0010; + pub static GLOB_NOSORT : int = 0x0020; + pub static GLOB_NOESCAPE : int = 0x2000; + + pub static GLOB_NOSPACE : int = -1; + pub static GLOB_ABORTED : int = -2; + pub static GLOB_NOMATCH : int = -3; } pub mod posix08 { } @@ -1606,6 +1692,21 @@ pub mod funcs { -> pid_t; } } + + #[nolink] + #[abi = "cdecl"] + pub mod glob { + use libc::types::common::c95::{c_void}; + use libc::types::os::arch::c95::{c_char, c_int}; + use libc::types::os::common::posix01::{glob_t}; + + pub extern { + unsafe fn glob(pattern: *c_char, flags: c_int, + errfunc: *c_void, // XXX callback + pglob: *mut glob_t); + unsafe fn globfree(pglob: *mut glob_t); + } + } } #[cfg(target_os = "win32")] @@ -1615,6 +1716,9 @@ pub mod funcs { pub mod unistd { } + + pub mod glob { + } } From 685baed34ed2d5a94675bb5773c9f968ea133533 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 10 Apr 2013 00:33:21 -0500 Subject: [PATCH 112/215] add a higher level glob() function to os this could probably use expansion - it just uses all of the default options, which is usually what we want, but not always. maybe add a separate function that takes more options? --- src/libcore/os.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/src/libcore/os.rs b/src/libcore/os.rs index 0455dabb7f013..8efae3e0e6890 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -38,6 +38,7 @@ use ptr; use str; use task; use uint; +use unstable::finally::Finally; use vec; pub use libc::fclose; @@ -1183,6 +1184,88 @@ pub fn set_args(new_args: ~[~str]) { } } +// FIXME #6100 we should really use an internal implementation of this - using +// the POSIX glob functions isn't portable to windows, probably has slight +// inconsistencies even where it is implemented, and makes extending +// functionality a lot more difficult +// FIXME #6101 also provide a non-allocating version - each_glob or so? +/// Returns a vector of Path objects that match the given glob pattern +#[cfg(target_os = "linux")] +#[cfg(target_os = "android")] +#[cfg(target_os = "freebsd")] +#[cfg(target_os = "macos")] +pub fn glob(pattern: &str) -> ~[Path] { + #[cfg(target_os = "linux")] + #[cfg(target_os = "android")] + fn default_glob_t () -> libc::glob_t { + libc::glob_t { + gl_pathc: 0, + gl_pathv: ptr::null(), + gl_offs: 0, + __unused1: ptr::null(), + __unused2: ptr::null(), + __unused3: ptr::null(), + __unused4: ptr::null(), + __unused5: ptr::null(), + } + } + + #[cfg(target_os = "freebsd")] + fn default_glob_t () -> libc::glob_t { + libc::glob_t { + gl_pathc: 0, + __unused1: 0, + gl_offs: 0, + __unused2: 0, + gl_pathv: ptr::null(), + __unused3: ptr::null(), + __unused4: ptr::null(), + __unused5: ptr::null(), + __unused6: ptr::null(), + __unused7: ptr::null(), + __unused8: ptr::null(), + } + } + + #[cfg(target_os = "macos")] + fn default_glob_t () -> libc::glob_t { + libc::glob_t { + gl_pathc: 0, + __unused1: 0, + gl_offs: 0, + __unused2: 0, + gl_pathv: ptr::null(), + __unused3: ptr::null(), + __unused4: ptr::null(), + __unused5: ptr::null(), + __unused6: ptr::null(), + __unused7: ptr::null(), + __unused8: ptr::null(), + } + } + + let mut g = default_glob_t(); + do str::as_c_str(pattern) |c_pattern| { + unsafe { libc::glob(c_pattern, 0, ptr::null(), &mut g) } + }; + do(|| { + let paths = unsafe { + vec::raw::from_buf_raw(g.gl_pathv, g.gl_pathc as uint) + }; + do paths.map |&c_str| { + Path(unsafe { str::raw::from_c_str(c_str) }) + } + }).finally { + unsafe { libc::globfree(&mut g) }; + } +} + +/// Returns a vector of Path objects that match the given glob pattern +#[cfg(target_os = "win32")] +pub fn glob(pattern: &str) -> ~[Path] { + fail!(~"glob() is unimplemented on Windows") +} + #[cfg(target_os = "macos")] extern { // These functions are in crt_externs.h. From ed81e3353ea8d92b61669dc8d8692d5e9b01a8f4 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Tue, 30 Apr 2013 22:26:43 -0500 Subject: [PATCH 113/215] glob_t should be public on all platforms --- src/libcore/libc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs index b5c444dedf8a7..999a5d9b350e4 100644 --- a/src/libcore/libc.rs +++ b/src/libcore/libc.rs @@ -387,7 +387,7 @@ pub mod types { pub mod posix01 { use libc::types::common::c95::{c_void}; use libc::types::os::arch::c95::{c_char, c_int, size_t}; - struct glob_t { + pub struct glob_t { gl_pathc: size_t, __unused1: size_t, gl_offs: size_t, @@ -606,7 +606,7 @@ pub mod types { pub mod posix01 { use libc::types::common::c95::{c_void}; use libc::types::os::arch::c95::{c_char, c_int, size_t}; - struct glob_t { + pub struct glob_t { gl_pathc: size_t, __unused1: c_int, gl_offs: size_t, From 1eb5efc5e25303bd72ce18ee3ecf82b109e2f67f Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Mon, 29 Apr 2013 00:18:53 +1000 Subject: [PATCH 114/215] libcore: add N(0,1) and Exp(1) distributions to core::rand. Sample from the normal and exponential distributions using the Ziggurat algorithm. --- src/etc/ziggurat_tables.py | 121 ++++++++ src/libcore/rand.rs | 6 + src/libcore/rand/distributions.rs | 148 ++++++++++ src/libcore/rand/ziggurat_tables.rs | 412 ++++++++++++++++++++++++++++ 4 files changed, 687 insertions(+) create mode 100755 src/etc/ziggurat_tables.py create mode 100644 src/libcore/rand/distributions.rs create mode 100644 src/libcore/rand/ziggurat_tables.rs diff --git a/src/etc/ziggurat_tables.py b/src/etc/ziggurat_tables.py new file mode 100755 index 0000000000000..c8f873037d8cc --- /dev/null +++ b/src/etc/ziggurat_tables.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# xfail-license + +# This creates the tables used for distributions implemented using the +# ziggurat algorithm in `core::rand::distributions;`. They are +# (basically) the tables as used in the ZIGNOR variant (Doornik 2005). +# They are changed rarely, so the generated file should be checked in +# to git. +# +# It creates 3 tables: X as in the paper, F which is f(x_i), and +# F_DIFF which is f(x_i) - f(x_{i-1}). The latter two are just cached +# values which is not done in that paper (but is done in other +# variants). Note that the adZigR table is unnecessary because of +# algebra. +# +# It is designed to be compatible with Python 2 and 3. + +from math import exp, sqrt, log, floor +import random + +# The order should match the return value of `tables` +TABLE_NAMES = ['X', 'F', 'F_DIFF'] + +# The actual length of the table is 1 more, to stop +# index-out-of-bounds errors. This should match the bitwise operation +# to find `i` in `zigurrat` in `libstd/rand/mod.rs`. Also the *_R and +# *_V constants below depend on this value. +TABLE_LEN = 256 + +# equivalent to `zigNorInit` in Doornik2005, but generalised to any +# distribution. r = dR, v = dV, f = probability density function, +# f_inv = inverse of f +def tables(r, v, f, f_inv): + # compute the x_i + xvec = [0]*(TABLE_LEN+1) + + xvec[0] = v / f(r) + xvec[1] = r + + for i in range(2, TABLE_LEN): + last = xvec[i-1] + xvec[i] = f_inv(v / last + f(last)) + + # cache the f's + fvec = [0]*(TABLE_LEN+1) + fdiff = [0]*(TABLE_LEN+1) + for i in range(TABLE_LEN+1): + fvec[i] = f(xvec[i]) + if i > 0: + fdiff[i] = fvec[i] - fvec[i-1] + + return xvec, fvec, fdiff + +# Distributions +# N(0, 1) +def norm_f(x): + return exp(-x*x/2.0) +def norm_f_inv(y): + return sqrt(-2.0*log(y)) + +NORM_R = 3.6541528853610088 +NORM_V = 0.00492867323399 + +NORM = tables(NORM_R, NORM_V, + norm_f, norm_f_inv) + +# Exp(1) +def exp_f(x): + return exp(-x) +def exp_f_inv(y): + return -log(y) + +EXP_R = 7.69711747013104972 +EXP_V = 0.0039496598225815571993 + +EXP = tables(EXP_R, EXP_V, + exp_f, exp_f_inv) + + +# Output the tables/constants/types + +def render_static(name, type, value): + # no space or + return 'pub static %s: %s =%s;\n' % (name, type, value) + +# static `name`: [`type`, .. `len(values)`] = +# [values[0], ..., values[3], +# values[4], ..., values[7], +# ... ]; +def render_table(name, values): + rows = [] + # 4 values on each row + for i in range(0, len(values), 4): + row = values[i:i+4] + rows.append(', '.join('%.18f' % f for f in row)) + + rendered = '\n [%s]' % ',\n '.join(rows) + return render_static(name, '[f64, .. %d]' % len(values), rendered) + + +with open('ziggurat_tables.rs', 'w') as f: + f.write('''// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tables for distributions which are sampled using the ziggurat +// algorithm. Autogenerated by `ziggurat_tables.py`. + +pub type ZigTable = &\'static [f64, .. %d]; +''' % (TABLE_LEN + 1)) + for name, tables, r in [('NORM', NORM, NORM_R), + ('EXP', EXP, EXP_R)]: + f.write(render_static('ZIG_%s_R' % name, 'f64', ' %.18f' % r)) + for (tabname, table) in zip(TABLE_NAMES, tables): + f.write(render_table('ZIG_%s_%s' % (name, tabname), table)) diff --git a/src/libcore/rand.rs b/src/libcore/rand.rs index 9fa099cabbfe9..94ba5ba31b756 100644 --- a/src/libcore/rand.rs +++ b/src/libcore/rand.rs @@ -16,6 +16,9 @@ and so can be used to generate any type that implements `Rand`. Type inference means that often a simple call to `rand::random()` or `rng.gen()` will suffice, but sometimes an annotation is required, e.g. `rand::random::()`. +See the `distributions` submodule for sampling random numbers from +distributions like normal and exponential. + # Examples ~~~ use core::rand::RngUtil; @@ -47,6 +50,9 @@ use util; use vec; use libc::size_t; +#[path="rand/distributions.rs"] +pub mod distributions; + /// A type that can be randomly generated using an Rng pub trait Rand { fn rand(rng: &R) -> Self; diff --git a/src/libcore/rand/distributions.rs b/src/libcore/rand/distributions.rs new file mode 100644 index 0000000000000..a644f60db69fb --- /dev/null +++ b/src/libcore/rand/distributions.rs @@ -0,0 +1,148 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Sampling from random distributions + +// Some implementations use the Ziggurat method +// https://en.wikipedia.org/wiki/Ziggurat_algorithm +// +// The version used here is ZIGNOR [Doornik 2005, "An Improved +// Ziggurat Method to Generate Normal Random Samples"] which is slower +// (about double, it generates an extra random number) than the +// canonical version [Marsaglia & Tsang 2000, "The Ziggurat Method for +// Generating Random Variables"], but more robust. If one wanted, one +// could implement VIZIGNOR the ZIGNOR paper for more speed. + +use prelude::*; +use rand::{Rng,Rand}; + +mod ziggurat_tables; + +// inlining should mean there is no performance penalty for this +#[inline(always)] +fn ziggurat(rng: &R, + center_u: bool, + X: ziggurat_tables::ZigTable, + F: ziggurat_tables::ZigTable, + F_DIFF: ziggurat_tables::ZigTable, + pdf: &'static fn(f64) -> f64, // probability density function + zero_case: &'static fn(&R, f64) -> f64) -> f64 { + loop { + let u = if center_u {2.0 * rng.gen() - 1.0} else {rng.gen()}; + let i: uint = rng.gen::() & 0xff; + let x = u * X[i]; + + let test_x = if center_u {f64::abs(x)} else {x}; + + // algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i]) + if test_x < X[i + 1] { + return x; + } + if i == 0 { + return zero_case(rng, u); + } + // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1 + if F[i+1] + F_DIFF[i+1] * rng.gen() < pdf(x) { + return x; + } + } +} + +/// A wrapper around an `f64` to generate N(0, 1) random numbers (a.k.a. a +/// standard normal, or Gaussian). Multiplying the generated values by the +/// desired standard deviation `sigma` then adding the desired mean `mu` will +/// give N(mu, sigma^2) distributed random numbers. +/// +/// Note that this has to be unwrapped before use as an `f64` (using either +/// `*` or `cast::transmute` is safe). +/// +/// # Example +/// +/// ~~~ +/// use core::rand::distributions::StandardNormal; +/// +/// fn main() { +/// let normal = 2.0 + (*rand::random::()) * 3.0; +/// println(fmt!("%f is from a N(2, 9) distribution", normal)) +/// } +/// ~~~ +pub struct StandardNormal(f64); + +impl Rand for StandardNormal { + fn rand(rng: &R) -> StandardNormal { + #[inline(always)] + fn pdf(x: f64) -> f64 { + f64::exp((-x*x/2.0) as f64) as f64 + } + #[inline(always)] + fn zero_case(rng: &R, u: f64) -> f64 { + // compute a random number in the tail by hand + + // strange initial conditions, because the loop is not + // do-while, so the condition should be true on the first + // run, they get overwritten anyway (0 < 1, so these are + // good). + let mut x = 1.0, y = 0.0; + + // XXX infinities? + while -2.0*y < x * x { + x = f64::ln(rng.gen()) / ziggurat_tables::ZIG_NORM_R; + y = f64::ln(rng.gen()); + } + if u < 0.0 {x-ziggurat_tables::ZIG_NORM_R} else {ziggurat_tables::ZIG_NORM_R-x} + } + + StandardNormal(ziggurat( + rng, + true, // this is symmetric + &ziggurat_tables::ZIG_NORM_X, + &ziggurat_tables::ZIG_NORM_F, &ziggurat_tables::ZIG_NORM_F_DIFF, + pdf, zero_case)) + } +} + +/// A wrapper around an `f64` to generate Exp(1) random numbers. Dividing by +/// the desired rate `lambda` will give Exp(lambda) distributed random +/// numbers. +/// +/// Note that this has to be unwrapped before use as an `f64` (using either +/// `*` or `cast::transmute` is safe). +/// +/// # Example +/// +/// ~~~ +/// use core::rand::distributions::Exp1; +/// +/// fn main() { +/// let exp2 = (*rand::random::()) * 0.5; +/// println(fmt!("%f is from a Exp(2) distribution", exp2)); +/// } +/// ~~~ +pub struct Exp1(f64); + +// This could be done via `-f64::ln(rng.gen::())` but that is slower. +impl Rand for Exp1 { + #[inline] + fn rand(rng: &R) -> Exp1 { + #[inline(always)] + fn pdf(x: f64) -> f64 { + f64::exp(-x) + } + #[inline(always)] + fn zero_case(rng: &R, _u: f64) -> f64 { + ziggurat_tables::ZIG_EXP_R - f64::ln(rng.gen()) + } + + Exp1(ziggurat(rng, false, + &ziggurat_tables::ZIG_EXP_X, + &ziggurat_tables::ZIG_EXP_F, &ziggurat_tables::ZIG_EXP_F_DIFF, + pdf, zero_case)) + } +} diff --git a/src/libcore/rand/ziggurat_tables.rs b/src/libcore/rand/ziggurat_tables.rs new file mode 100644 index 0000000000000..aca2457cac42c --- /dev/null +++ b/src/libcore/rand/ziggurat_tables.rs @@ -0,0 +1,412 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Tables for distributions which are sampled using the ziggurat +// algorithm. Autogenerated by `ziggurat_tables.py`. + +pub type ZigTable = &'static [f64, .. 257]; +pub static ZIG_NORM_R: f64 = 3.654152885361008796; +pub static ZIG_NORM_X: [f64, .. 257] = + [3.910757959537090045, 3.654152885361008796, 3.449278298560964462, 3.320244733839166074, + 3.224575052047029100, 3.147889289517149969, 3.083526132001233044, 3.027837791768635434, + 2.978603279880844834, 2.934366867207854224, 2.894121053612348060, 2.857138730872132548, + 2.822877396825325125, 2.790921174000785765, 2.760944005278822555, 2.732685359042827056, + 2.705933656121858100, 2.680514643284522158, 2.656283037575502437, 2.633116393630324570, + 2.610910518487548515, 2.589575986706995181, 2.569035452680536569, 2.549221550323460761, + 2.530075232158516929, 2.511544441625342294, 2.493583041269680667, 2.476149939669143318, + 2.459208374333311298, 2.442725318198956774, 2.426670984935725972, 2.411018413899685520, + 2.395743119780480601, 2.380822795170626005, 2.366237056715818632, 2.351967227377659952, + 2.337996148795031370, 2.324308018869623016, 2.310888250599850036, 2.297723348901329565, + 2.284800802722946056, 2.272108990226823888, 2.259637095172217780, 2.247375032945807760, + 2.235313384928327984, 2.223443340090905718, 2.211756642882544366, 2.200245546609647995, + 2.188902771624720689, 2.177721467738641614, 2.166695180352645966, 2.155817819875063268, + 2.145083634046203613, 2.134487182844320152, 2.124023315687815661, 2.113687150684933957, + 2.103474055713146829, 2.093379631137050279, 2.083399693996551783, 2.073530263516978778, + 2.063767547809956415, 2.054107931648864849, 2.044547965215732788, 2.035084353727808715, + 2.025713947862032960, 2.016433734904371722, 2.007240830558684852, 1.998132471356564244, + 1.989106007615571325, 1.980158896898598364, 1.971288697931769640, 1.962493064942461896, + 1.953769742382734043, 1.945116560006753925, 1.936531428273758904, 1.928012334050718257, + 1.919557336591228847, 1.911164563769282232, 1.902832208548446369, 1.894558525668710081, + 1.886341828534776388, 1.878180486290977669, 1.870072921069236838, 1.862017605397632281, + 1.854013059758148119, 1.846057850283119750, 1.838150586580728607, 1.830289919680666566, + 1.822474540091783224, 1.814703175964167636, 1.806974591348693426, 1.799287584547580199, + 1.791640986550010028, 1.784033659547276329, 1.776464495522344977, 1.768932414909077933, + 1.761436365316706665, 1.753975320315455111, 1.746548278279492994, 1.739154261283669012, + 1.731792314050707216, 1.724461502945775715, 1.717160915015540690, 1.709889657069006086, + 1.702646854797613907, 1.695431651932238548, 1.688243209434858727, 1.681080704722823338, + 1.673943330923760353, 1.666830296159286684, 1.659740822855789499, 1.652674147080648526, + 1.645629517902360339, 1.638606196773111146, 1.631603456932422036, 1.624620582830568427, + 1.617656869570534228, 1.610711622367333673, 1.603784156023583041, 1.596873794420261339, + 1.589979870021648534, 1.583101723393471438, 1.576238702733332886, 1.569390163412534456, + 1.562555467528439657, 1.555733983466554893, 1.548925085471535512, 1.542128153226347553, + 1.535342571438843118, 1.528567729435024614, 1.521803020758293101, 1.515047842773992404, + 1.508301596278571965, 1.501563685112706548, 1.494833515777718391, 1.488110497054654369, + 1.481394039625375747, 1.474683555695025516, 1.467978458615230908, 1.461278162507407830, + 1.454582081885523293, 1.447889631277669675, 1.441200224845798017, 1.434513276002946425, + 1.427828197027290358, 1.421144398672323117, 1.414461289772464658, 1.407778276843371534, + 1.401094763676202559, 1.394410150925071257, 1.387723835686884621, 1.381035211072741964, + 1.374343665770030531, 1.367648583594317957, 1.360949343030101844, 1.354245316759430606, + 1.347535871177359290, 1.340820365893152122, 1.334098153216083604, 1.327368577624624679, + 1.320630975217730096, 1.313884673146868964, 1.307128989027353860, 1.300363230327433728, + 1.293586693733517645, 1.286798664489786415, 1.279998415710333237, 1.273185207661843732, + 1.266358287014688333, 1.259516886060144225, 1.252660221891297887, 1.245787495544997903, + 1.238897891102027415, 1.231990574742445110, 1.225064693752808020, 1.218119375481726552, + 1.211153726239911244, 1.204166830140560140, 1.197157747875585931, 1.190125515422801650, + 1.183069142678760732, 1.175987612011489825, 1.168879876726833800, 1.161744859441574240, + 1.154581450355851802, 1.147388505416733873, 1.140164844363995789, 1.132909248648336975, + 1.125620459211294389, 1.118297174115062909, 1.110938046009249502, 1.103541679420268151, + 1.096106627847603487, 1.088631390649514197, 1.081114409698889389, 1.073554065787871714, + 1.065948674757506653, 1.058296483326006454, 1.050595664586207123, 1.042844313139370538, + 1.035040439828605274, 1.027181966030751292, 1.019266717460529215, 1.011292417434978441, + 1.003256679539591412, 0.995156999629943084, 0.986990747093846266, 0.978755155288937750, + 0.970447311058864615, 0.962064143217605250, 0.953602409875572654, 0.945058684462571130, + 0.936429340280896860, 0.927710533396234771, 0.918898183643734989, 0.909987953490768997, + 0.900975224455174528, 0.891855070726792376, 0.882622229578910122, 0.873271068082494550, + 0.863795545546826915, 0.854189171001560554, 0.844444954902423661, 0.834555354079518752, + 0.824512208745288633, 0.814306670128064347, 0.803929116982664893, 0.793369058833152785, + 0.782615023299588763, 0.771654424216739354, 0.760473406422083165, 0.749056662009581653, + 0.737387211425838629, 0.725446140901303549, 0.713212285182022732, 0.700661841097584448, + 0.687767892786257717, 0.674499822827436479, 0.660822574234205984, 0.646695714884388928, + 0.632072236375024632, 0.616896989996235545, 0.601104617743940417, 0.584616766093722262, + 0.567338257040473026, 0.549151702313026790, 0.529909720646495108, 0.509423329585933393, + 0.487443966121754335, 0.463634336771763245, 0.437518402186662658, 0.408389134588000746, + 0.375121332850465727, 0.335737519180459465, 0.286174591747260509, 0.215241895913273806, + 0.000000000000000000]; +pub static ZIG_NORM_F: [f64, .. 257] = + [0.000477467764586655, 0.001260285930498598, 0.002609072746106363, 0.004037972593371872, + 0.005522403299264754, 0.007050875471392110, 0.008616582769422917, 0.010214971439731100, + 0.011842757857943104, 0.013497450601780807, 0.015177088307982072, 0.016880083152595839, + 0.018605121275783350, 0.020351096230109354, 0.022117062707379922, 0.023902203305873237, + 0.025705804008632656, 0.027527235669693315, 0.029365939758230111, 0.031221417192023690, + 0.033093219458688698, 0.034980941461833073, 0.036884215688691151, 0.038802707404656918, + 0.040736110656078753, 0.042684144916619378, 0.044646552251446536, 0.046623094902089664, + 0.048613553216035145, 0.050617723861121788, 0.052635418276973649, 0.054666461325077916, + 0.056710690106399467, 0.058767952921137984, 0.060838108349751806, 0.062921024437977854, + 0.065016577971470438, 0.067124653828023989, 0.069245144397250269, 0.071377949059141965, + 0.073522973714240991, 0.075680130359194964, 0.077849336702372207, 0.080030515814947509, + 0.082223595813495684, 0.084428509570654661, 0.086645194450867782, 0.088873592068594229, + 0.091113648066700734, 0.093365311913026619, 0.095628536713353335, 0.097903279039215627, + 0.100189498769172020, 0.102487158942306270, 0.104796225622867056, 0.107116667775072880, + 0.109448457147210021, 0.111791568164245583, 0.114145977828255210, 0.116511665626037014, + 0.118888613443345698, 0.121276805485235437, 0.123676228202051403, 0.126086870220650349, + 0.128508722280473636, 0.130941777174128166, 0.133386029692162844, 0.135841476571757352, + 0.138308116449064322, 0.140785949814968309, 0.143274978974047118, 0.145775208006537926, + 0.148286642733128721, 0.150809290682410169, 0.153343161060837674, 0.155888264725064563, + 0.158444614156520225, 0.161012223438117663, 0.163591108232982951, 0.166181285765110071, + 0.168782774801850333, 0.171395595638155623, 0.174019770082499359, 0.176655321444406654, + 0.179302274523530397, 0.181960655600216487, 0.184630492427504539, 0.187311814224516926, + 0.190004651671193070, 0.192709036904328807, 0.195425003514885592, 0.198152586546538112, + 0.200891822495431333, 0.203642749311121501, 0.206405406398679298, 0.209179834621935651, + 0.211966076307852941, 0.214764175252008499, 0.217574176725178370, 0.220396127481011589, + 0.223230075764789593, 0.226076071323264877, 0.228934165415577484, 0.231804410825248525, + 0.234686861873252689, 0.237581574432173676, 0.240488605941449107, 0.243408015423711988, + 0.246339863502238771, 0.249284212419516704, 0.252241126056943765, 0.255210669955677150, + 0.258192911338648023, 0.261187919133763713, 0.264195763998317568, 0.267216518344631837, + 0.270250256366959984, 0.273297054069675804, 0.276356989296781264, 0.279430141762765316, + 0.282516593084849388, 0.285616426816658109, 0.288729728483353931, 0.291856585618280984, + 0.294997087801162572, 0.298151326697901342, 0.301319396102034120, 0.304501391977896274, + 0.307697412505553769, 0.310907558127563710, 0.314131931597630143, 0.317370638031222396, + 0.320623784958230129, 0.323891482377732021, 0.327173842814958593, 0.330470981380537099, + 0.333783015832108509, 0.337110066638412809, 0.340452257045945450, 0.343809713148291340, + 0.347182563958251478, 0.350570941482881204, 0.353974980801569250, 0.357394820147290515, + 0.360830600991175754, 0.364282468130549597, 0.367750569780596226, 0.371235057669821344, + 0.374736087139491414, 0.378253817247238111, 0.381788410875031348, 0.385340034841733958, + 0.388908860020464597, 0.392495061461010764, 0.396098818517547080, 0.399720314981931668, + 0.403359739222868885, 0.407017284331247953, 0.410693148271983222, 0.414387534042706784, + 0.418100649839684591, 0.421832709231353298, 0.425583931339900579, 0.429354541031341519, + 0.433144769114574058, 0.436954852549929273, 0.440785034667769915, 0.444635565397727750, + 0.448506701509214067, 0.452398706863882505, 0.456311852680773566, 0.460246417814923481, + 0.464202689050278838, 0.468180961407822172, 0.472181538469883255, 0.476204732721683788, + 0.480250865911249714, 0.484320269428911598, 0.488413284707712059, 0.492530263646148658, + 0.496671569054796314, 0.500837575128482149, 0.505028667945828791, 0.509245245998136142, + 0.513487720749743026, 0.517756517232200619, 0.522052074674794864, 0.526374847174186700, + 0.530725304406193921, 0.535103932383019565, 0.539511234259544614, 0.543947731192649941, + 0.548413963257921133, 0.552910490428519918, 0.557437893621486324, 0.561996775817277916, + 0.566587763258951771, 0.571211506738074970, 0.575868682975210544, 0.580559996103683473, + 0.585286179266300333, 0.590047996335791969, 0.594846243770991268, 0.599681752622167719, + 0.604555390700549533, 0.609468064928895381, 0.614420723892076803, 0.619414360609039205, + 0.624450015550274240, 0.629528779928128279, 0.634651799290960050, 0.639820277456438991, + 0.645035480824251883, 0.650298743114294586, 0.655611470583224665, 0.660975147780241357, + 0.666391343912380640, 0.671861719900766374, 0.677388036222513090, 0.682972161648791376, + 0.688616083008527058, 0.694321916130032579, 0.700091918140490099, 0.705928501336797409, + 0.711834248882358467, 0.717811932634901395, 0.723864533472881599, 0.729995264565802437, + 0.736207598131266683, 0.742505296344636245, 0.748892447223726720, 0.755373506511754500, + 0.761953346841546475, 0.768637315803334831, 0.775431304986138326, 0.782341832659861902, + 0.789376143571198563, 0.796542330428254619, 0.803849483176389490, 0.811307874318219935, + 0.818929191609414797, 0.826726833952094231, 0.834716292992930375, 0.842915653118441077, + 0.851346258465123684, 0.860033621203008636, 0.869008688043793165, 0.878309655816146839, + 0.887984660763399880, 0.898095921906304051, 0.908726440060562912, 0.919991505048360247, + 0.932060075968990209, 0.945198953453078028, 0.959879091812415930, 0.977101701282731328, + 1.000000000000000000]; +pub static ZIG_NORM_F_DIFF: [f64, .. 257] = + [0.000000000000000000, 0.000782818165911943, 0.001348786815607765, 0.001428899847265509, + 0.001484430705892882, 0.001528472172127356, 0.001565707298030807, 0.001598388670308183, + 0.001627786418212004, 0.001654692743837703, 0.001679637706201265, 0.001702994844613767, + 0.001725038123187510, 0.001745974954326004, 0.001765966477270568, 0.001785140598493315, + 0.001803600702759419, 0.001821431661060659, 0.001838704088536796, 0.001855477433793579, + 0.001871802266665008, 0.001887722003144375, 0.001903274226858077, 0.001918491715965767, + 0.001933403251421835, 0.001948034260540625, 0.001962407334827158, 0.001976542650643127, + 0.001990458313945481, 0.002004170645086643, 0.002017694415851860, 0.002031043048104267, + 0.002044228781321551, 0.002057262814738517, 0.002070155428613822, 0.002082916088226049, + 0.002095553533492583, 0.002108075856553551, 0.002120490569226280, 0.002132804661891696, + 0.002145024655099026, 0.002157156644953973, 0.002169206343177243, 0.002181179112575302, + 0.002193079998548175, 0.002204913757158977, 0.002216684880213121, 0.002228397617726446, + 0.002240055998106505, 0.002251663846325885, 0.002263224800326716, 0.002274742325862292, + 0.002286219729956393, 0.002297660173134250, 0.002309066680560787, 0.002320442152205823, + 0.002331789372137141, 0.002343111017035562, 0.002354409664009627, 0.002365687797781804, + 0.002376947817308683, 0.002388192041889739, 0.002399422716815966, 0.002410642018598946, + 0.002421852059823287, 0.002433054893654529, 0.002444252518034679, 0.002455446879594508, + 0.002466639877306970, 0.002477833365903986, 0.002489029159078809, 0.002500229032490808, + 0.002511434726590794, 0.002522647949281448, 0.002533870378427505, 0.002545103664226889, + 0.002556349431455662, 0.002567609281597438, 0.002578884794865288, 0.002590177532127119, + 0.002601489036740262, 0.002612820836305291, 0.002624174444343735, 0.002635551361907296, + 0.002646953079123743, 0.002658381076686089, 0.002669836827288052, 0.002681321797012387, + 0.002692837446676144, 0.002704385233135737, 0.002715966610556786, 0.002727583031652520, + 0.002739235948893221, 0.002750926815690169, 0.002762657087557796, 0.002774428223256353, + 0.002786241685917290, 0.002798098944155558, 0.002810001473169871, 0.002821950755833219, + 0.002833948283778004, 0.002845995558475284, 0.002858094092312607, 0.002870245409671041, + 0.002882451048004164, 0.002894712558920987, 0.002907031509275432, 0.002919409482262880, + 0.002931848078526783, 0.002944348917277934, 0.002956913637427061, 0.002969543898733384, + 0.002982241382970874, 0.002995007795115689, 0.003007844864553855, 0.003020754346314269, + 0.003033738022328147, 0.003046797702715820, 0.003059935227105459, 0.003073152465984053, + 0.003086451322084072, 0.003099833731808721, 0.003113301666695822, 0.003126857134927052, + 0.003140502182881588, 0.003154238896738770, 0.003168069404132778, 0.003181995875862154, + 0.003196020527657495, 0.003210145622009941, 0.003224373470066433, 0.003238706433592253, + 0.003253146927007733, 0.003267697419501892, 0.003282360437226572, 0.003297138565578506, + 0.003312034451571411, 0.003327050806304299, 0.003342190407532641, 0.003357456102345890, + 0.003372850809960137, 0.003388377524629727, 0.003404039318688046, 0.003419839345721265, + 0.003435780843885239, 0.003451867139373843, 0.003468101650046629, 0.003484487889225119, + 0.003501029469670069, 0.003517730107746697, 0.003534593627793237, 0.003551623966702611, + 0.003568825178730639, 0.003586201440546166, 0.003603757056536316, 0.003621496464384588, + 0.003639424240937217, 0.003657545108379068, 0.003675863940735269, 0.003694385770723563, + 0.003713115796977806, 0.003732059391668707, 0.003751222108547281, 0.003770609691440940, + 0.003790228083232539, 0.003810083435355216, 0.003830182117840641, 0.003850530729957835, + 0.003871136111486317, 0.003892005354668437, 0.003913145816891062, 0.003934565134149914, + 0.003956271235355358, 0.003978272357543333, 0.004000577062061084, 0.004023194251800533, + 0.004046133189565926, 0.004069403517661885, 0.004093015278800460, 0.004116978938436600, + 0.004141305408647655, 0.004166006073685835, 0.004191092817346642, 0.004216578052307351, + 0.004242474751606884, 0.004268796482457593, 0.004295557442594244, 0.004322772499391836, + 0.004350457232007221, 0.004378627976825644, 0.004407301876525049, 0.004436496933105327, + 0.004466232065271192, 0.004496527170598785, 0.004527403192966406, 0.004558882195791591, + 0.004590987441673855, 0.004623743479123199, 0.004657176237135574, 0.004691313128472929, + 0.004726183162616859, 0.004761817069491636, 0.004798247435199299, 0.004835508851176451, + 0.004873638078381815, 0.004912674228345848, 0.004952658963181422, 0.004993636716962402, + 0.005035654941235035, 0.005078764377854039, 0.005123019362831771, 0.005168478165478940, + 0.005215203367812893, 0.005263262290042703, 0.005312727468930079, 0.005363677197016692, + 0.005416196132139284, 0.005470375988385734, 0.005526316321746716, 0.005584125426278286, + 0.005643921359735682, 0.005705833121505521, 0.005770002010457520, 0.005836583196307310, + 0.005905747545561058, 0.005977683752542928, 0.006052600837980204, 0.006130731092920838, + 0.006212333565464245, 0.006297698213369562, 0.006387150879090475, 0.006481059288027780, + 0.006579840329791975, 0.006683968961788356, 0.006793989182803495, 0.006910527673723577, + 0.007034310911336661, 0.007166186857056056, 0.007307152748134871, 0.007458391141830445, + 0.007621317291194862, 0.007797642342679434, 0.007989459040836144, 0.008199360125510702, + 0.008430605346682607, 0.008687362737884952, 0.008975066840784529, 0.009300967772353674, + 0.009675004947253041, 0.010111261142904171, 0.010630518154258861, 0.011265064987797335, + 0.012068570920629962, 0.013138877484087819, 0.014680138359337902, 0.017222609470315398, + 0.022898298717268672]; +pub static ZIG_EXP_R: f64 = 7.697117470131050077; +pub static ZIG_EXP_X: [f64, .. 257] = + [8.697117470131052741, 7.697117470131050077, 6.941033629377212577, 6.478378493832569696, + 6.144164665772472667, 5.882144315795399869, 5.666410167454033697, 5.482890627526062488, + 5.323090505754398016, 5.181487281301500047, 5.054288489981304089, 4.938777085901250530, + 4.832939741025112035, 4.735242996601741083, 4.644491885420085175, 4.559737061707351380, + 4.480211746528421912, 4.405287693473573185, 4.334443680317273007, 4.267242480277365857, + 4.203313713735184365, 4.142340865664051464, 4.084051310408297830, 4.028208544647936762, + 3.974606066673788796, 3.923062500135489739, 3.873417670399509127, 3.825529418522336744, + 3.779270992411667862, 3.734528894039797375, 3.691201090237418825, 3.649195515760853770, + 3.608428813128909507, 3.568825265648337020, 3.530315889129343354, 3.492837654774059608, + 3.456332821132760191, 3.420748357251119920, 3.386035442460300970, 3.352149030900109405, + 3.319047470970748037, 3.286692171599068679, 3.255047308570449882, 3.224079565286264160, + 3.193757903212240290, 3.164053358025972873, 3.134938858084440394, 3.106389062339824481, + 3.078380215254090224, 3.050890016615455114, 3.023897504455676621, 2.997382949516130601, + 2.971327759921089662, 2.945714394895045718, 2.920526286512740821, 2.895747768600141825, + 2.871364012015536371, 2.847360965635188812, 2.823725302450035279, 2.800444370250737780, + 2.777506146439756574, 2.754899196562344610, 2.732612636194700073, 2.710636095867928752, + 2.688959688741803689, 2.667573980773266573, 2.646469963151809157, 2.625639026797788489, + 2.605072938740835564, 2.584763820214140750, 2.564704126316905253, 2.544886627111869970, + 2.525304390037828028, 2.505950763528594027, 2.486819361740209455, 2.467904050297364815, + 2.449198932978249754, 2.430698339264419694, 2.412396812688870629, 2.394289099921457886, + 2.376370140536140596, 2.358635057409337321, 2.341079147703034380, 2.323697874390196372, + 2.306486858283579799, 2.289441870532269441, 2.272558825553154804, 2.255833774367219213, + 2.239262898312909034, 2.222842503111036816, 2.206569013257663858, 2.190438966723220027, + 2.174449009937774679, 2.158595893043885994, 2.142876465399842001, 2.127287671317368289, + 2.111826546019042183, 2.096490211801715020, 2.081275874393225145, 2.066180819490575526, + 2.051202409468584786, 2.036338080248769611, 2.021585338318926173, 2.006941757894518563, + 1.992404978213576650, 1.977972700957360441, 1.963642687789548313, 1.949412758007184943, + 1.935280786297051359, 1.921244700591528076, 1.907302480018387536, 1.893452152939308242, + 1.879691795072211180, 1.866019527692827973, 1.852433515911175554, 1.838931967018879954, + 1.825513128903519799, 1.812175288526390649, 1.798916770460290859, 1.785735935484126014, + 1.772631179231305643, 1.759600930889074766, 1.746643651946074405, 1.733757834985571566, + 1.720942002521935299, 1.708194705878057773, 1.695514524101537912, 1.682900062917553896, + 1.670349953716452118, 1.657862852574172763, 1.645437439303723659, 1.633072416535991334, + 1.620766508828257901, 1.608518461798858379, 1.596327041286483395, 1.584191032532688892, + 1.572109239386229707, 1.560080483527888084, 1.548103603714513499, 1.536177455041032092, + 1.524300908219226258, 1.512472848872117082, 1.500692176842816750, 1.488957805516746058, + 1.477268661156133867, 1.465623682245745352, 1.454021818848793446, 1.442462031972012504, + 1.430943292938879674, 1.419464582769983219, 1.408024891569535697, 1.396623217917042137, + 1.385258568263121992, 1.373929956328490576, 1.362636402505086775, 1.351376933258335189, + 1.340150580529504643, 1.328956381137116560, 1.317793376176324749, 1.306660610415174117, + 1.295557131686601027, 1.284481990275012642, 1.273434238296241139, 1.262412929069615330, + 1.251417116480852521, 1.240445854334406572, 1.229498195693849105, 1.218573192208790124, + 1.207669893426761121, 1.196787346088403092, 1.185924593404202199, 1.175080674310911677, + 1.164254622705678921, 1.153445466655774743, 1.142652227581672841, 1.131873919411078511, + 1.121109547701330200, 1.110358108727411031, 1.099618588532597308, 1.088889961938546813, + 1.078171191511372307, 1.067461226479967662, 1.056759001602551429, 1.046063435977044209, + 1.035373431790528542, 1.024687873002617211, 1.014005623957096480, 1.003325527915696735, + 0.992646405507275897, 0.981967053085062602, 0.971286240983903260, 0.960602711668666509, + 0.949915177764075969, 0.939222319955262286, 0.928522784747210395, 0.917815182070044311, + 0.907098082715690257, 0.896370015589889935, 0.885629464761751528, 0.874874866291025066, + 0.864104604811004484, 0.853317009842373353, 0.842510351810368485, 0.831682837734273206, + 0.820832606554411814, 0.809957724057418282, 0.799056177355487174, 0.788125868869492430, + 0.777164609759129710, 0.766170112735434672, 0.755139984181982249, 0.744071715500508102, + 0.732962673584365398, 0.721810090308756203, 0.710611050909655040, 0.699362481103231959, + 0.688061132773747808, 0.676703568029522584, 0.665286141392677943, 0.653804979847664947, + 0.642255960424536365, 0.630634684933490286, 0.618936451394876075, 0.607156221620300030, + 0.595288584291502887, 0.583327712748769489, 0.571267316532588332, 0.559100585511540626, + 0.546820125163310577, 0.534417881237165604, 0.521885051592135052, 0.509211982443654398, + 0.496388045518671162, 0.483401491653461857, 0.470239275082169006, 0.456886840931420235, + 0.443327866073552401, 0.429543940225410703, 0.415514169600356364, 0.401214678896277765, + 0.386617977941119573, 0.371692145329917234, 0.356399760258393816, 0.340696481064849122, + 0.324529117016909452, 0.307832954674932158, 0.290527955491230394, 0.272513185478464703, + 0.253658363385912022, 0.233790483059674731, 0.212671510630966620, 0.189958689622431842, + 0.165127622564187282, 0.137304980940012589, 0.104838507565818778, 0.063852163815001570, + 0.000000000000000000]; +pub static ZIG_EXP_F: [f64, .. 257] = + [0.000167066692307963, 0.000454134353841497, 0.000967269282327174, 0.001536299780301573, + 0.002145967743718907, 0.002788798793574076, 0.003460264777836904, 0.004157295120833797, + 0.004877655983542396, 0.005619642207205489, 0.006381905937319183, 0.007163353183634991, + 0.007963077438017043, 0.008780314985808977, 0.009614413642502212, 0.010464810181029981, + 0.011331013597834600, 0.012212592426255378, 0.013109164931254991, 0.014020391403181943, + 0.014945968011691148, 0.015885621839973156, 0.016839106826039941, 0.017806200410911355, + 0.018786700744696024, 0.019780424338009740, 0.020787204072578114, 0.021806887504283581, + 0.022839335406385240, 0.023884420511558174, 0.024942026419731787, 0.026012046645134221, + 0.027094383780955803, 0.028188948763978646, 0.029295660224637411, 0.030414443910466622, + 0.031545232172893622, 0.032687963508959555, 0.033842582150874358, 0.035009037697397431, + 0.036187284781931443, 0.037377282772959382, 0.038578995503074871, 0.039792391023374139, + 0.041017441380414840, 0.042254122413316254, 0.043502413568888197, 0.044762297732943289, + 0.046033761076175184, 0.047316792913181561, 0.048611385573379504, 0.049917534282706379, + 0.051235237055126281, 0.052564494593071685, 0.053905310196046080, 0.055257689676697030, + 0.056621641283742870, 0.057997175631200659, 0.059384305633420280, 0.060783046445479660, + 0.062193415408541036, 0.063615431999807376, 0.065049117786753805, 0.066494496385339816, + 0.067951593421936643, 0.069420436498728783, 0.070901055162371843, 0.072393480875708752, + 0.073897746992364746, 0.075413888734058410, 0.076941943170480517, 0.078481949201606435, + 0.080033947542319905, 0.081597980709237419, 0.083174093009632397, 0.084762330532368146, + 0.086362741140756927, 0.087975374467270231, 0.089600281910032886, 0.091237516631040197, + 0.092887133556043569, 0.094549189376055873, 0.096223742550432825, 0.097910853311492213, + 0.099610583670637132, 0.101322997425953631, 0.103048160171257702, 0.104786139306570145, + 0.106537004050001632, 0.108300825451033755, 0.110077676405185357, 0.111867631670056283, + 0.113670767882744286, 0.115487163578633506, 0.117316899211555525, 0.119160057175327641, + 0.121016721826674792, 0.122886979509545108, 0.124770918580830933, 0.126668629437510671, + 0.128580204545228199, 0.130505738468330773, 0.132445327901387494, 0.134399071702213602, + 0.136367070926428829, 0.138349428863580176, 0.140346251074862399, 0.142357645432472146, + 0.144383722160634720, 0.146424593878344889, 0.148480375643866735, 0.150551185001039839, + 0.152637142027442801, 0.154738369384468027, 0.156854992369365148, 0.158987138969314129, + 0.161134939917591952, 0.163298528751901734, 0.165478041874935922, 0.167673618617250081, + 0.169885401302527550, 0.172113535315319977, 0.174358169171353411, 0.176619454590494829, + 0.178897546572478278, 0.181192603475496261, 0.183504787097767436, 0.185834262762197083, + 0.188181199404254262, 0.190545769663195363, 0.192928149976771296, 0.195328520679563189, + 0.197747066105098818, 0.200183974691911210, 0.202639439093708962, 0.205113656293837654, + 0.207606827724221982, 0.210119159388988230, 0.212650861992978224, 0.215202151075378628, + 0.217773247148700472, 0.220364375843359439, 0.222975768058120111, 0.225607660116683956, + 0.228260293930716618, 0.230933917169627356, 0.233628783437433291, 0.236345152457059560, + 0.239083290262449094, 0.241843469398877131, 0.244625969131892024, 0.247431075665327543, + 0.250259082368862240, 0.253110290015629402, 0.255985007030415324, 0.258883549749016173, + 0.261806242689362922, 0.264753418835062149, 0.267725419932044739, 0.270722596799059967, + 0.273745309652802915, 0.276793928448517301, 0.279868833236972869, 0.282970414538780746, + 0.286099073737076826, 0.289255223489677693, 0.292439288161892630, 0.295651704281261252, + 0.298892921015581847, 0.302163400675693528, 0.305463619244590256, 0.308794066934560185, + 0.312155248774179606, 0.315547685227128949, 0.318971912844957239, 0.322428484956089223, + 0.325917972393556354, 0.329440964264136438, 0.332998068761809096, 0.336589914028677717, + 0.340217149066780189, 0.343880444704502575, 0.347580494621637148, 0.351318016437483449, + 0.355093752866787626, 0.358908472948750001, 0.362762973354817997, 0.366658079781514379, + 0.370594648435146223, 0.374573567615902381, 0.378595759409581067, 0.382662181496010056, + 0.386773829084137932, 0.390931736984797384, 0.395136981833290435, 0.399390684475231350, + 0.403694012530530555, 0.408048183152032673, 0.412454465997161457, 0.416914186433003209, + 0.421428728997616908, 0.425999541143034677, 0.430628137288459167, 0.435316103215636907, + 0.440065100842354173, 0.444876873414548846, 0.449753251162755330, 0.454696157474615836, + 0.459707615642138023, 0.464789756250426511, 0.469944825283960310, 0.475175193037377708, + 0.480483363930454543, 0.485871987341885248, 0.491343869594032867, 0.496901987241549881, + 0.502549501841348056, 0.508289776410643213, 0.514126393814748894, 0.520063177368233931, + 0.526104213983620062, 0.532253880263043655, 0.538516872002862246, 0.544898237672440056, + 0.551403416540641733, 0.558038282262587892, 0.564809192912400615, 0.571723048664826150, + 0.578787358602845359, 0.586010318477268366, 0.593400901691733762, 0.600968966365232560, + 0.608725382079622346, 0.616682180915207878, 0.624852738703666200, 0.633251994214366398, + 0.641896716427266423, 0.650805833414571433, 0.660000841079000145, 0.669506316731925177, + 0.679350572264765806, 0.689566496117078431, 0.700192655082788606, 0.711274760805076456, + 0.722867659593572465, 0.735038092431424039, 0.747868621985195658, 0.761463388849896838, + 0.775956852040116218, 0.791527636972496285, 0.808421651523009044, 0.826993296643051101, + 0.847785500623990496, 0.871704332381204705, 0.900469929925747703, 0.938143680862176477, + 1.000000000000000000]; +pub static ZIG_EXP_F_DIFF: [f64, .. 257] = + [0.000000000000000000, 0.000287067661533533, 0.000513134928485678, 0.000569030497974398, + 0.000609667963417335, 0.000642831049855169, 0.000671465984262828, 0.000697030342996893, + 0.000720360862708599, 0.000741986223663093, 0.000762263730113694, 0.000781447246315807, + 0.000799724254382053, 0.000817237547791934, 0.000834098656693235, 0.000850396538527769, + 0.000866203416804620, 0.000881578828420777, 0.000896572504999613, 0.000911226471926952, + 0.000925576608509206, 0.000939653828282008, 0.000953484986066785, 0.000967093584871414, + 0.000980500333784669, 0.000993723593313716, 0.001006779734568374, 0.001019683431705467, + 0.001032447902101660, 0.001045085105172934, 0.001057605908173612, 0.001070020225402434, + 0.001082337135821582, 0.001094564983022843, 0.001106711460658764, 0.001118783685829211, + 0.001130788262427001, 0.001142731336065933, 0.001154618641914802, 0.001166455546523074, + 0.001178247084534012, 0.001189997991027938, 0.001201712730115490, 0.001213395520299268, + 0.001225050357040701, 0.001236681032901414, 0.001248291155571943, 0.001259884164055092, + 0.001271463343231895, 0.001283031837006378, 0.001294592660197942, 0.001306148709326875, + 0.001317702772419903, 0.001329257537945404, 0.001340815602974395, 0.001352379480650950, + 0.001363951607045839, 0.001375534347457789, 0.001387130002219621, 0.001398740812059381, + 0.001410368963061376, 0.001422016591266340, 0.001433685786946429, 0.001445378598586011, + 0.001457097036596827, 0.001468843076792140, 0.001480618663643060, 0.001492425713336909, + 0.001504266116655995, 0.001516141741693663, 0.001528054436422108, 0.001540006031125918, + 0.001551998340713470, 0.001564033166917514, 0.001576112300394977, 0.001588237522735750, + 0.001600410608388780, 0.001612633326513305, 0.001624907442762655, 0.001637234721007311, + 0.001649616925003372, 0.001662055820012304, 0.001674553174376953, 0.001687110761059388, + 0.001699730359144919, 0.001712413755316500, 0.001725162745304071, 0.001737979135312442, + 0.001750864743431488, 0.001763821401032123, 0.001776850954151601, 0.001789955264870927, + 0.001803136212688003, 0.001816395695889220, 0.001829735632922019, 0.001843157963772116, + 0.001856664651347151, 0.001870257682870316, 0.001883939071285826, 0.001897710856679738, + 0.001911575107717528, 0.001925533923102574, 0.001939589433056721, 0.001953743800826108, + 0.001967999224215228, 0.001982357937151347, 0.001996822211282223, 0.002011394357609747, + 0.002026076728162574, 0.002040871717710169, 0.002055781765521847, 0.002070809357173103, + 0.002085957026402963, 0.002101227357025226, 0.002116622984897121, 0.002132146599948981, + 0.002147800948277823, 0.002163588834309782, 0.002179513123034188, 0.002195576742314159, + 0.002211782685277469, 0.002228134012792427, 0.002244633856033434, 0.002261285419141418, + 0.002278091981983449, 0.002295056903017983, 0.002312183622271174, 0.002329475664429648, + 0.002346936642057179, 0.002364570258941101, 0.002382380313575932, 0.002400370702791893, + 0.002418545425535629, 0.002436908586812392, 0.002455464401797752, 0.002474217200128692, + 0.002493171430384328, 0.002512331664766249, 0.002531702603989994, 0.002551289082400404, + 0.002571096073321844, 0.002591128694658967, 0.002611392214760672, 0.002631892058563845, + 0.002652633814032662, 0.002673623238910738, 0.002694866267805934, 0.002716369019626269, + 0.002738137805389534, 0.002760179136428037, 0.002782499733014893, 0.002805106533435520, + 0.002828006703534697, 0.002851207646767162, 0.002874717014785921, 0.002898542718600849, + 0.002922692940346749, 0.002947176145699226, 0.002972001096982591, 0.002997176867015228, + 0.003022712853742948, 0.003048618795714386, 0.003074904788455568, 0.003101581301807876, + 0.003128659198296080, 0.003156149752600867, 0.003184064672214937, 0.003212416119368622, + 0.003241216734320596, 0.003270479660111680, 0.003300218568896729, 0.003330447689969929, + 0.003361181839619420, 0.003392436452949343, 0.003424227617828290, 0.003456572111131984, + 0.003489487437467131, 0.003522991870580083, 0.003557104497672658, 0.003591845266868621, + 0.003627235038102472, 0.003663295637722386, 0.003700049917134574, 0.003737521815846301, + 0.003775736429304177, 0.003814720081962375, 0.003854500406067995, 0.003895106426696382, + 0.003936568653631844, 0.003978919180756157, 0.004022191793678687, 0.004066422086428989, + 0.004111647588127876, 0.004157907900659452, 0.004205244848493050, 0.004253702641940915, + 0.004303328055299205, 0.004354170621502118, 0.004406282845128784, 0.004459720435841752, + 0.004514542564613699, 0.004570812145417769, 0.004628596145424491, 0.004687965927177740, + 0.004748997626717266, 0.004811772572194672, 0.004876377748206484, 0.004942906311860507, + 0.005011458167522187, 0.005082140608288488, 0.005155069033533799, 0.005230367753417398, + 0.005308170893076836, 0.005388623411430704, 0.005471882252147620, 0.005558117647517014, + 0.005647514599798176, 0.005740274569295156, 0.005836617404105682, 0.005936783553485037, + 0.006041036615386131, 0.006149666279423593, 0.006262991739818591, 0.006381365669577810, + 0.006505178868201678, 0.006634865721946159, 0.006770910649812723, 0.006913855752425535, + 0.007064309938019209, 0.007222959874423007, 0.007390583214465396, 0.007568064673498798, + 0.007756415714389786, 0.007956798835585532, 0.008170557788458321, 0.008399255510700199, + 0.008644722212900025, 0.008909116987305010, 0.009195007664428712, 0.009505475652925033, + 0.009844255532840629, 0.010215923852312625, 0.010626158965710175, 0.011082105722287849, + 0.011592898788496009, 0.012170432837851575, 0.012830529553771619, 0.013594766864701180, + 0.014493463190219380, 0.015570784932380066, 0.016894014550512759, 0.018571645120042057, + 0.020792203980939394, 0.023918831757214210, 0.028765597544542998, 0.037673750936428774, + 0.061856319137823523]; From 3afd708e2acd767f1af90de52c139c1b6b877311 Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Thu, 2 May 2013 08:58:24 +0900 Subject: [PATCH 115/215] mk: minor fix for test.mk to support mutiple target test --- mk/tests.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index 9b01c4af80fdd..21754a9f51d0a 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -505,7 +505,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ --aux-base $$(S)src/test/auxiliary/ \ --stage-id stage$(1)-$(2) \ - --host $(3) \ + --host $(CFG_BUILD_TRIPLE) \ --target $(2) \ --adb-path=$(CFG_ADB_PATH) \ --rustcflags "$(RUSTC_FLAGS_$(2)) $$(CFG_RUSTC_FLAGS) --target=$(2)" \ @@ -519,7 +519,7 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ --aux-base $$(S)src/test/auxiliary/ \ --stage-id stage$(1)-$(2) \ - --host $(3) \ + --host $(CFG_BUILD_TRIPLE) \ --target $(2) \ --rustcflags "$(RUSTC_FLAGS_$(2)) $$(CFG_RUSTC_FLAGS) --target=$(2)" \ $$(CTEST_TESTARGS) From 14bf5c4fe7eb110fc124a710b40bc7c5a7801e25 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2013 20:19:28 -0400 Subject: [PATCH 116/215] rustc: adjust total number of lang items --- src/librustc/middle/lang_items.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 0266b77997e7d..314b58d13e147 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -75,13 +75,13 @@ pub enum LangItem { } pub struct LanguageItems { - items: [Option, ..35] + items: [Option, ..36] } pub impl LanguageItems { pub fn new() -> LanguageItems { LanguageItems { - items: [ None, ..35 ] + items: [ None, ..36 ] } } From ef6b24d1350ad658faee68f7eddd2c05a56900ce Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2013 20:22:08 -0400 Subject: [PATCH 117/215] rustc: fix the fact that trans_lvalue rooted twice --- src/librustc/middle/trans/_match.rs | 2 +- src/librustc/middle/trans/datum.rs | 9 ++-- src/librustc/middle/trans/expr.rs | 73 +++++++++-------------------- 3 files changed, 29 insertions(+), 55 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index d7f9567c333d0..be39edd2d9b78 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -966,7 +966,7 @@ pub fn root_pats_as_necessary(bcx: block, let datum = Datum {val: val, ty: node_id_type(bcx, pat_id), mode: ByRef, source: ZeroMem}; - bcx = datum.root(bcx, br.pats[col].span, root_info); + bcx = datum.root(bcx, br.pats[col].span, key, root_info); // If we kept going, we'd only re-root the same value, so // return now. return bcx; diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 94bff65843b24..f4fb3b6c6f5d5 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -517,7 +517,8 @@ pub impl Datum { } } - fn root(&self, mut bcx: block, span: span, root_info: RootInfo) -> block { + fn root(&self, mut bcx: block, span: span, + root_key: root_map_key, root_info: RootInfo) -> block { /*! * * In some cases, borrowck will decide that an @T/@[]/@str @@ -525,8 +526,8 @@ pub impl Datum { * case, we will call this function, which will stash a copy * away until we exit the scope `scope_id`. */ - debug!("root(root_info=%?, self=%?)", - root_info, self.to_str(bcx.ccx())); + debug!("root(root_map_key=%?, root_info=%?, self=%?)", + root_key, root_info, self.to_str(bcx.ccx())); if bcx.sess().trace() { trans_trace( @@ -674,7 +675,7 @@ pub impl Datum { let key = root_map_key { id: expr_id, derefs: derefs }; let bcx = match ccx.maps.root_map.find(&key) { None => bcx, - Some(&root_info) => self.root(bcx, span, root_info) + Some(&root_info) => self.root(bcx, span, key, root_info) }; // Perform the write guard, if necessary. diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 166b8bc01f856..a993f781cdb18 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -821,57 +821,30 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { trace_span!(bcx, expr.span, @shorten(bcx.expr_to_str(expr))); - let unrooted_datum = unpack_datum!(bcx, unrooted(bcx, expr)); - - // If the lvalue must remain rooted, create a scratch datum, copy - // the lvalue in there, and then arrange for it to be cleaned up - // at the end of the scope with id `scope_id`: - let root_key = root_map_key { id: expr.id, derefs: 0u }; - for bcx.ccx().maps.root_map.find(&root_key).each |&root_info| { - bcx = unrooted_datum.root(bcx, expr.span, *root_info); - } - - return DatumBlock {bcx: bcx, datum: unrooted_datum}; - - fn unrooted(bcx: block, expr: @ast::expr) -> DatumBlock { - /*! - * - * Translates `expr`. Note that this version generally - * yields an unrooted, unmoved version. Rooting and possible - * moves are dealt with above in trans_lvalue_unadjusted(). - * - * One exception is if `expr` refers to a local variable, - * in which case the source may already be FromMovedLvalue - * if appropriate. - */ - - let mut bcx = bcx; - - match expr.node { - ast::expr_paren(e) => { - return unrooted(bcx, e); - } - ast::expr_path(_) => { - return trans_def_lvalue(bcx, expr, bcx.def(expr.id)); - } - ast::expr_field(base, ident, _) => { - return trans_rec_field(bcx, base, ident); - } - ast::expr_index(base, idx) => { - return trans_index(bcx, expr, base, idx); - } - ast::expr_unary(ast::deref, base) => { - let basedatum = unpack_datum!(bcx, trans_to_datum(bcx, base)); - return basedatum.deref(bcx, base, 0); - } - _ => { - bcx.tcx().sess.span_bug( - expr.span, - fmt!("trans_lvalue reached fall-through case: %?", - expr.node)); - } + return match expr.node { + ast::expr_paren(e) => { + unrooted(bcx, e) } - } + ast::expr_path(_) => { + trans_def_lvalue(bcx, expr, bcx.def(expr.id)) + } + ast::expr_field(base, ident, _) => { + trans_rec_field(bcx, base, ident) + } + ast::expr_index(base, idx) => { + trans_index(bcx, expr, base, idx) + } + ast::expr_unary(ast::deref, base) => { + let basedatum = unpack_datum!(bcx, trans_to_datum(bcx, base)); + basedatum.deref(bcx, base, 0) + } + _ => { + bcx.tcx().sess.span_bug( + expr.span, + fmt!("trans_lvalue reached fall-through case: %?", + expr.node)); + } + }; fn trans_rec_field(bcx: block, base: @ast::expr, From d231c427e655b7164571a1a712563ba5fd2e4a3c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2013 20:23:07 -0400 Subject: [PATCH 118/215] core: add more debugging printouts to borrowing --- src/libcore/unstable/lang.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index d0e3c2b06787f..283f232964963 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -51,6 +51,8 @@ pub mod rustrt { #[rust_stack] fn rust_set_task_borrow_list(task: *rust_task, map: *c_void); + + fn rust_dbg_breakpoint(); } } @@ -88,6 +90,8 @@ fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { } pub fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { + debug_ptr("fail_borrowed: ", box); + if !::rt::env::get().debug_borrows { let msg = "borrowed"; do str::as_buf(msg) |msg_p, _| { @@ -130,7 +134,7 @@ pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { static ENABLE_DEBUG_PTR: bool = false; #[inline] -pub fn debug_ptr(tag: &'static str, p: *T) { +pub fn debug_ptr(tag: &'static str, p: *const T) { //! A useful debugging function that prints a pointer + tag + newline //! without allocating memory. @@ -138,7 +142,7 @@ pub fn debug_ptr(tag: &'static str, p: *T) { debug_ptr_slow(tag, p); } - fn debug_ptr_slow(tag: &'static str, p: *T) { + fn debug_ptr_slow(tag: &'static str, p: *const T) { use io; let dbg = STDERR_FILENO as io::fd_t; let letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', @@ -209,14 +213,17 @@ fn add_borrow_to_task_list(a: *mut BoxRepr, file: *c_char, line: size_t) { #[inline(always)] pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { let a: *mut BoxRepr = transmute(a); - let ref_count = (*a).header.ref_count; + + debug_ptr("borrow_as_imm (ptr): ", a); + debug_ptr("borrow_as_imm (ref): ", ref_count as *()); + if (ref_count & MUT_BIT) != 0 { fail_borrowed(a, file, line); } else { (*a).header.ref_count |= FROZEN_BIT; if ::rt::env::get().debug_borrows { - add_borrow_to_list(a, file, line); + add_borrow_to_task_list(a, file, line); } } ref_count @@ -228,13 +235,16 @@ pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint { let a: *mut BoxRepr = transmute(a); + debug_ptr("borrow_as_mut (ptr): ", a); + debug_ptr("borrow_as_mut (line): ", line as *()); + let ref_count = (*a).header.ref_count; if (ref_count & (MUT_BIT|FROZEN_BIT)) != 0 { fail_borrowed(a, file, line); } else { (*a).header.ref_count |= (MUT_BIT|FROZEN_BIT); if ::rt::env::get().debug_borrows { - add_borrow_to_list(a, file, line); + add_borrow_to_task_list(a, file, line); } } ref_count @@ -261,6 +271,9 @@ pub unsafe fn return_to_mut(a: *u8, old_ref_count: uint) { if !a.is_null() { let a: *mut BoxRepr = transmute(a); + debug_ptr("return_to_mut (ptr): ", a); + debug_ptr("return_to_mut (ref): ", old_ref_count as *()); + let ref_count = (*a).header.ref_count & !ALL_BITS; let old_bits = old_ref_count & ALL_BITS; (*a).header.ref_count = ref_count | old_bits; From 0c34cab3db76d100ea7bbe4cd776f27b5f971d2c Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Wed, 1 May 2013 00:53:20 +0900 Subject: [PATCH 119/215] Take string slices --- src/librustc/driver/session.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index ff623049f758d..970ee20bfcb76 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -175,16 +175,16 @@ pub struct Session_ { pub type Session = @Session_; pub impl Session_ { - fn span_fatal(@self, sp: span, msg: ~str) -> ! { + fn span_fatal(@self, sp: span, msg: &str) -> ! { self.span_diagnostic.span_fatal(sp, msg) } - fn fatal(@self, msg: ~str) -> ! { + fn fatal(@self, msg: &str) -> ! { self.span_diagnostic.handler().fatal(msg) } - fn span_err(@self, sp: span, msg: ~str) { + fn span_err(@self, sp: span, msg: &str) { self.span_diagnostic.span_err(sp, msg) } - fn err(@self, msg: ~str) { + fn err(@self, msg: &str) { self.span_diagnostic.handler().err(msg) } fn has_errors(@self) -> bool { @@ -193,31 +193,31 @@ pub impl Session_ { fn abort_if_errors(@self) { self.span_diagnostic.handler().abort_if_errors() } - fn span_warn(@self, sp: span, msg: ~str) { + fn span_warn(@self, sp: span, msg: &str) { self.span_diagnostic.span_warn(sp, msg) } - fn warn(@self, msg: ~str) { + fn warn(@self, msg: &str) { self.span_diagnostic.handler().warn(msg) } - fn span_note(@self, sp: span, msg: ~str) { + fn span_note(@self, sp: span, msg: &str) { self.span_diagnostic.span_note(sp, msg) } - fn note(@self, msg: ~str) { + fn note(@self, msg: &str) { self.span_diagnostic.handler().note(msg) } - fn span_bug(@self, sp: span, msg: ~str) -> ! { + fn span_bug(@self, sp: span, msg: &str) -> ! { self.span_diagnostic.span_bug(sp, msg) } - fn bug(@self, msg: ~str) -> ! { + fn bug(@self, msg: &str) -> ! { self.span_diagnostic.handler().bug(msg) } - fn span_unimpl(@self, sp: span, msg: ~str) -> ! { + fn span_unimpl(@self, sp: span, msg: &str) -> ! { self.span_diagnostic.span_unimpl(sp, msg) } - fn unimpl(@self, msg: ~str) -> ! { + fn unimpl(@self, msg: &str) -> ! { self.span_diagnostic.handler().unimpl(msg) } - fn span_lint_level(@self, level: lint::level, sp: span, msg: ~str) { + fn span_lint_level(@self, level: lint::level, sp: span, msg: &str) { match level { lint::allow => { }, lint::warn => self.span_warn(sp, msg), @@ -230,7 +230,7 @@ pub impl Session_ { expr_id: ast::node_id, item_id: ast::node_id, span: span, - msg: ~str) { + msg: &str) { let level = lint::get_lint_settings_level( self.lint_settings, lint_mode, expr_id, item_id); self.span_lint_level(level, span, msg); From 4294aed01ba4836cf0d40d5422e5a404b467dcca Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Wed, 1 May 2013 01:47:52 +0900 Subject: [PATCH 120/215] Use static strings --- src/librustc/middle/check_const.rs | 30 ++++----- src/librustc/middle/check_loop.rs | 6 +- src/librustc/middle/check_match.rs | 28 ++++----- src/librustc/middle/kind.rs | 42 ++++++------- src/librustc/middle/lint.rs | 30 ++++----- src/librustc/middle/liveness.rs | 26 ++++---- src/librustc/middle/mem_categorization.rs | 2 +- src/librustc/middle/moves.rs | 4 +- src/librustc/middle/privacy.rs | 76 +++++++++++------------ src/librustc/middle/region.rs | 2 +- src/librustc/middle/ty.rs | 18 +++--- 11 files changed, 132 insertions(+), 132 deletions(-) diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 6a47eedcea8c3..fdb0d40139411 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -92,13 +92,13 @@ pub fn check_expr(sess: Session, expr_unary(deref, _) => { } expr_unary(box(_), _) | expr_unary(uniq(_), _) => { sess.span_err(e.span, - ~"disallowed operator in constant expression"); + "disallowed operator in constant expression"); return; } expr_lit(@codemap::spanned {node: lit_str(_), _}) => { } expr_binary(_, _, _) | expr_unary(_, _) => { if method_map.contains_key(&e.id) { - sess.span_err(e.span, ~"user-defined operators are not \ + sess.span_err(e.span, "user-defined operators are not \ allowed in constant expressions"); } } @@ -118,8 +118,8 @@ pub fn check_expr(sess: Session, // a path in trans::callee that only works in block contexts. if pth.types.len() != 0 { sess.span_err( - e.span, ~"paths in constants may only refer to \ - items without type parameters"); + e.span, "paths in constants may only refer to \ + items without type parameters"); } match def_map.find(&e.id) { Some(&def_const(_)) | @@ -131,11 +131,11 @@ pub fn check_expr(sess: Session, debug!("(checking const) found bad def: %?", def); sess.span_err( e.span, - fmt!("paths in constants may only refer to \ - constants or functions")); + "paths in constants may only refer to \ + constants or functions"); } None => { - sess.span_bug(e.span, ~"unbound path in const?!"); + sess.span_bug(e.span, "unbound path in const?!"); } } } @@ -146,8 +146,8 @@ pub fn check_expr(sess: Session, _ => { sess.span_err( e.span, - ~"function calls in constants are limited to \ - struct and enum constructors"); + "function calls in constants are limited to \ + struct and enum constructors"); } } } @@ -163,12 +163,12 @@ pub fn check_expr(sess: Session, expr_addr_of(*) => { sess.span_err( e.span, - ~"borrowed pointers in constants may only refer to \ - immutable values"); + "borrowed pointers in constants may only refer to \ + immutable values"); } _ => { sess.span_err(e.span, - ~"constant contains unimplemented expression type"); + "constant contains unimplemented expression type"); return; } } @@ -178,14 +178,14 @@ pub fn check_expr(sess: Session, if t != ty_char { if (v as u64) > ast_util::int_ty_max( if t == ty_i { sess.targ_cfg.int_type } else { t }) { - sess.span_err(e.span, ~"literal out of range for its type"); + sess.span_err(e.span, "literal out of range for its type"); } } } expr_lit(@codemap::spanned {node: lit_uint(v, t), _}) => { if v > ast_util::uint_ty_max( if t == ty_u { sess.targ_cfg.uint_type } else { t }) { - sess.span_err(e.span, ~"literal out of range for its type"); + sess.span_err(e.span, "literal out of range for its type"); } } _ => () @@ -224,7 +224,7 @@ pub fn check_item_recursion(sess: Session, fn visit_item(it: @item, env: env, v: visit::vt) { if env.idstack.contains(&(it.id)) { - env.sess.span_fatal(env.root_it.span, ~"recursive constant"); + env.sess.span_fatal(env.root_it.span, "recursive constant"); } env.idstack.push(it.id); visit::visit_item(it, env, v); diff --git a/src/librustc/middle/check_loop.rs b/src/librustc/middle/check_loop.rs index 9f26f7f83724f..e3b816fceb8bb 100644 --- a/src/librustc/middle/check_loop.rs +++ b/src/librustc/middle/check_loop.rs @@ -54,17 +54,17 @@ pub fn check_crate(tcx: ty::ctxt, crate: @crate) { } expr_break(_) => { if !cx.in_loop { - tcx.sess.span_err(e.span, ~"`break` outside of loop"); + tcx.sess.span_err(e.span, "`break` outside of loop"); } } expr_again(_) => { if !cx.in_loop { - tcx.sess.span_err(e.span, ~"`again` outside of loop"); + tcx.sess.span_err(e.span, "`again` outside of loop"); } } expr_ret(oe) => { if !cx.can_ret { - tcx.sess.span_err(e.span, ~"`return` in block function"); + tcx.sess.span_err(e.span, "`return` in block function"); } visit::visit_expr_opt(oe, cx, v); } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 852eb1b50a499..f6c65b3744a6c 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -94,7 +94,7 @@ pub fn check_expr(cx: @MatchCheckCtxt, ex: @expr, s: (), v: visit::vt<()>) { } let arms = vec::concat(arms.filter_mapped(unguarded_pat)); if arms.is_empty() { - cx.tcx.sess.span_err(ex.span, ~"non-exhaustive patterns"); + cx.tcx.sess.span_err(ex.span, "non-exhaustive patterns"); } else { check_exhaustive(cx, ex.span, arms); } @@ -111,7 +111,7 @@ pub fn check_arms(cx: @MatchCheckCtxt, arms: &[arm]) { let v = ~[*pat]; match is_useful(cx, &seen, v) { not_useful => { - cx.tcx.sess.span_err(pat.span, ~"unreachable pattern"); + cx.tcx.sess.span_err(pat.span, "unreachable pattern"); } _ => () } @@ -685,7 +685,7 @@ pub fn check_local(cx: @MatchCheckCtxt, visit::visit_local(loc, s, v); if is_refutable(cx, loc.node.pat) { cx.tcx.sess.span_err(loc.node.pat.span, - ~"refutable pattern in local binding"); + "refutable pattern in local binding"); } // Check legality of move bindings. @@ -708,7 +708,7 @@ pub fn check_fn(cx: @MatchCheckCtxt, for decl.inputs.each |input| { if is_refutable(cx, input.pat) { cx.tcx.sess.span_err(input.pat.span, - ~"refutable pattern in function argument"); + "refutable pattern in function argument"); } } } @@ -780,24 +780,24 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt, if sub.is_some() { tcx.sess.span_err( p.span, - ~"cannot bind by-move with sub-bindings"); + "cannot bind by-move with sub-bindings"); } else if has_guard { tcx.sess.span_err( p.span, - ~"cannot bind by-move into a pattern guard"); + "cannot bind by-move into a pattern guard"); } else if by_ref_span.is_some() { tcx.sess.span_err( p.span, - ~"cannot bind by-move and by-ref \ - in the same pattern"); + "cannot bind by-move and by-ref \ + in the same pattern"); tcx.sess.span_note( by_ref_span.get(), - ~"by-ref binding occurs here"); + "by-ref binding occurs here"); } else if is_lvalue { tcx.sess.span_err( p.span, - ~"cannot bind by-move when \ - matching an lvalue"); + "cannot bind by-move when \ + matching an lvalue"); } }; @@ -837,9 +837,9 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt, { cx.tcx.sess.span_err( pat.span, - ~"by-move pattern \ - bindings may not occur \ - behind @ or & bindings"); + "by-move pattern \ + bindings may not occur \ + behind @ or & bindings"); } match sub { diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 0925e8cdd6375..a1d5f3f3c9faf 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -97,21 +97,21 @@ fn check_struct_safe_for_destructor(cx: Context, }); if !ty::type_is_owned(cx.tcx, struct_ty) { cx.tcx.sess.span_err(span, - ~"cannot implement a destructor on a struct \ - that is not Owned"); + "cannot implement a destructor on a struct \ + that is not Owned"); cx.tcx.sess.span_note(span, - ~"use \"#[unsafe_destructor]\" on the \ - implementation to force the compiler to \ - allow this"); + "use \"#[unsafe_destructor]\" on the \ + implementation to force the compiler to \ + allow this"); } } else { cx.tcx.sess.span_err(span, - ~"cannot implement a destructor on a struct \ - with type parameters"); + "cannot implement a destructor on a struct \ + with type parameters"); cx.tcx.sess.span_note(span, - ~"use \"#[unsafe_destructor]\" on the \ - implementation to force the compiler to \ - allow this"); + "use \"#[unsafe_destructor]\" on the \ + implementation to force the compiler to \ + allow this"); } } @@ -143,10 +143,10 @@ fn check_item(item: @item, cx: Context, visitor: visit::vt) { } _ => { cx.tcx.sess.span_bug(self_type.span, - ~"the self type for \ - the Drop trait \ - impl is not a \ - path"); + "the self type for \ + the Drop trait \ + impl is not a \ + path"); } } } @@ -193,7 +193,7 @@ fn with_appropriate_checker(cx: Context, id: node_id, b: &fn(check_fn)) { fn check_for_bare(cx: Context, fv: @freevar_entry) { cx.tcx.sess.span_err( fv.span, - ~"attempted dynamic environment capture"); + "attempted dynamic environment capture"); } let fty = ty::node_id_to_type(cx.tcx, id); @@ -409,7 +409,7 @@ fn check_imm_free_var(cx: Context, def: def, sp: span) { if is_mutbl { cx.tcx.sess.span_err( sp, - ~"mutable variables cannot be implicitly captured"); + "mutable variables cannot be implicitly captured"); } } def_arg(*) => { /* ok */ } @@ -451,12 +451,12 @@ pub fn check_durable(tcx: ty::ctxt, ty: ty::t, sp: span) -> bool { if !ty::type_is_durable(tcx, ty) { match ty::get(ty).sty { ty::ty_param(*) => { - tcx.sess.span_err(sp, ~"value may contain borrowed \ - pointers; use `'static` bound"); + tcx.sess.span_err(sp, "value may contain borrowed \ + pointers; use `'static` bound"); } _ => { - tcx.sess.span_err(sp, ~"value may contain borrowed \ - pointers"); + tcx.sess.span_err(sp, "value may contain borrowed \ + pointers"); } } false @@ -581,7 +581,7 @@ pub fn check_kind_bounds_of_cast(cx: Context, source: @expr, target: @expr) { if !ty::type_is_owned(cx.tcx, source_ty) { cx.tcx.sess.span_err( target.span, - ~"uniquely-owned trait objects must be sendable"); + "uniquely-owned trait objects must be sendable"); } } _ => {} // Nothing to do. diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index b67d74bc272b6..2b4d029c59328 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -338,14 +338,14 @@ pub impl Context { _ => { self.sess.span_err( meta.span, - ~"malformed lint attribute"); + "malformed lint attribute"); } } } } _ => { self.sess.span_err(meta.span, - ~"malformed lint attribute"); + "malformed lint attribute"); } } } @@ -485,8 +485,8 @@ fn check_item_while_true(cx: ty::ctxt, it: @ast::item) { cx.sess.span_lint( while_true, e.id, it.id, e.span, - ~"denote infinite loops \ - with loop { ... }"); + "denote infinite loops \ + with loop { ... }"); } _ => () } @@ -603,7 +603,7 @@ fn check_item_type_limits(cx: ty::ctxt, it: @ast::item) { && !check_limits(cx, *binop, l, r) { cx.sess.span_lint( type_limits, e.id, it.id, e.span, - ~"comparison is useless due to type limits"); + "comparison is useless due to type limits"); } } _ => () @@ -630,7 +630,7 @@ fn check_item_default_methods(cx: ty::ctxt, item: @ast::item) { item.id, item.id, item.span, - ~"default methods are experimental"); + "default methods are experimental"); } } } @@ -649,7 +649,7 @@ fn check_item_deprecated_mutable_fields(cx: ty::ctxt, item: @ast::item) { item.id, item.id, field.span, - ~"mutable fields are deprecated"); + "mutable fields are deprecated"); } ast::named_field(*) | ast::unnamed_field => {} } @@ -672,14 +672,14 @@ fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) { cx.sess.span_lint( ctypes, id, fn_id, ty.span, - ~"found rust type `int` in foreign module, while \ + "found rust type `int` in foreign module, while \ libc::c_int or libc::c_long should be used"); } ast::def_prim_ty(ast::ty_uint(ast::ty_u)) => { cx.sess.span_lint( ctypes, id, fn_id, ty.span, - ~"found rust type `uint` in foreign module, while \ + "found rust type `uint` in foreign module, while \ libc::c_uint or libc::c_ulong should be used"); } _ => () @@ -795,7 +795,7 @@ fn check_item_path_statement(cx: ty::ctxt, it: @ast::item) { cx.sess.span_lint( path_statement, id, it.id, s.span, - ~"path statement with no effect"); + "path statement with no effect"); } _ => () } @@ -835,8 +835,8 @@ fn check_item_non_camel_case_types(cx: ty::ctxt, it: @ast::item) { if !is_camel_case(cx, ident) { cx.sess.span_lint( non_camel_case_types, expr_id, item_id, span, - ~"type, variant, or trait should have \ - a camel case identifier"); + "type, variant, or trait should have \ + a camel case identifier"); } } @@ -863,7 +863,7 @@ fn check_item_unused_unsafe(cx: ty::ctxt, it: @ast::item) { if !cx.used_unsafe.contains(&blk.node.id) { cx.sess.span_lint(unused_unsafe, blk.node.id, it.id, blk.span, - ~"unnecessary `unsafe` block"); + "unnecessary `unsafe` block"); } } _ => () @@ -888,9 +888,9 @@ fn check_item_unused_mut(tcx: ty::ctxt, it: @ast::item) { } if !used { let msg = if bindings == 1 { - ~"variable does not need to be mutable" + "variable does not need to be mutable" } else { - ~"variables do not need to be mutable" + "variables do not need to be mutable" }; tcx.sess.span_lint(unused_mut, p.id, it.id, p.span, msg); } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 0df10c59a8aac..40d62cac3572d 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -359,7 +359,7 @@ pub impl IrMaps { match self.capture_info_map.find(&expr.id) { Some(&caps) => caps, None => { - self.tcx.sess.span_bug(expr.span, ~"no registered caps"); + self.tcx.sess.span_bug(expr.span, "no registered caps"); } } } @@ -687,7 +687,7 @@ pub impl Liveness { } None => { self.tcx.sess.span_bug( - span, ~"Not present in def map") + span, "Not present in def map") } } } @@ -804,15 +804,15 @@ pub impl Liveness { // to find with one match self.tcx.def_map.find(&id) { Some(&def_label(loop_id)) => loop_id, - _ => self.tcx.sess.span_bug(sp, ~"Label on break/loop \ - doesn't refer to a loop") + _ => self.tcx.sess.span_bug(sp, "Label on break/loop \ + doesn't refer to a loop") }, None => { // Vanilla 'break' or 'loop', so use the enclosing // loop scope let loop_scope = &mut *self.loop_scope; if loop_scope.len() == 0 { - self.tcx.sess.span_bug(sp, ~"break outside loop"); + self.tcx.sess.span_bug(sp, "break outside loop"); } else { // FIXME(#5275): this shouldn't have to be a method... @@ -994,7 +994,7 @@ pub impl Liveness { } stmt_mac(*) => { - self.tcx.sess.span_bug(stmt.span, ~"unexpanded macro"); + self.tcx.sess.span_bug(stmt.span, "unexpanded macro"); } } } @@ -1164,7 +1164,7 @@ pub impl Liveness { match self.break_ln.find(&sc) { Some(&b) => b, None => self.tcx.sess.span_bug(expr.span, - ~"Break to unknown label") + "Break to unknown label") } } @@ -1178,7 +1178,7 @@ pub impl Liveness { match self.cont_ln.find(&sc) { Some(&b) => b, None => self.tcx.sess.span_bug(expr.span, - ~"Loop to unknown label") + "Loop to unknown label") } } @@ -1304,7 +1304,7 @@ pub impl Liveness { } expr_mac(*) => { - self.tcx.sess.span_bug(expr.span, ~"unexpanded macro"); + self.tcx.sess.span_bug(expr.span, "unexpanded macro"); } } } @@ -1618,10 +1618,10 @@ pub impl Liveness { } else if ty::type_is_bot(t_ret) { // for bot return types, not ok. Function should fail. self.tcx.sess.span_err( - sp, ~"some control paths may return"); + sp, "some control paths may return"); } else { self.tcx.sess.span_err( - sp, ~"not all control paths return a value"); + sp, "not all control paths return a value"); } } } @@ -1712,10 +1712,10 @@ pub impl Liveness { None => { self.tcx.sess.span_err( span, - ~"re-assignment of immutable variable"); + "re-assignment of immutable variable"); self.tcx.sess.span_note( orig_span, - ~"prior assignment occurs here"); + "prior assignment occurs here"); } } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 7fa198be1d47f..866bd5377b9ba 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -928,7 +928,7 @@ pub impl mem_categorization_ctxt { _ => { self.tcx.sess.span_bug( pat.span, - ~"enum pattern didn't resolve to enum or struct"); + "enum pattern didn't resolve to enum or struct"); } } } diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index fe1466bf808a3..ecee2ea1a2fb2 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -424,7 +424,7 @@ pub impl VisitContext { MoveInWhole => { self.tcx.sess.span_bug( expr.span, - fmt!("Component mode can never be MoveInWhole")); + "Component mode can never be MoveInWhole"); } } } @@ -647,7 +647,7 @@ pub impl VisitContext { expr_mac(*) => { self.tcx.sess.span_bug( expr.span, - ~"macro expression remains after expansion"); + "macro expression remains after expansion"); } } } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index a37ebdcfaa263..be98195621902 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -99,8 +99,8 @@ pub fn check_crate(tcx: ty::ctxt, parental_privacy == Public) == Private { tcx.sess.span_err(span, - ~"can only dereference enums \ - with a single, public variant"); + "can only dereference enums \ + with a single, public variant"); } }; @@ -121,8 +121,8 @@ pub fn check_crate(tcx: ty::ctxt, tcx.sess.parse_sess.interner))); } None => { - tcx.sess.span_bug(span, ~"method not found in \ - AST map?!"); + tcx.sess.span_bug(span, "method not found in \ + AST map?!"); } } }; @@ -140,8 +140,8 @@ pub fn check_crate(tcx: ty::ctxt, // Look up the enclosing impl. if container_id.crate != local_crate { tcx.sess.span_bug(span, - ~"local method isn't in local \ - impl?!"); + "local method isn't in local \ + impl?!"); } match tcx.items.find(&container_id.node) { @@ -155,10 +155,10 @@ pub fn check_crate(tcx: ty::ctxt, } } Some(_) => { - tcx.sess.span_bug(span, ~"impl wasn't an item?!"); + tcx.sess.span_bug(span, "impl wasn't an item?!"); } None => { - tcx.sess.span_bug(span, ~"impl wasn't in AST map?!"); + tcx.sess.span_bug(span, "impl wasn't in AST map?!"); } } } @@ -185,8 +185,8 @@ pub fn check_crate(tcx: ty::ctxt, tcx.sess.parse_sess.interner))); } None => { - tcx.sess.span_bug(span, ~"method not found in \ - AST map?!"); + tcx.sess.span_bug(span, "method not found in \ + AST map?!"); } } }; @@ -219,7 +219,7 @@ pub fn check_crate(tcx: ty::ctxt, .interner))); } None => { - tcx.sess.span_bug(span, ~"item not found in AST map?!"); + tcx.sess.span_bug(span, "item not found in AST map?!"); } } }; @@ -333,10 +333,10 @@ pub fn check_crate(tcx: ty::ctxt, match item.node { item_trait(_, _, ref methods) => { if method_num >= (*methods).len() { - tcx.sess.span_bug(span, ~"method \ - number \ - out of \ - range?!"); + tcx.sess.span_bug(span, "method \ + number \ + out of \ + range?!"); } match (*methods)[method_num] { provided(method) @@ -363,20 +363,20 @@ pub fn check_crate(tcx: ty::ctxt, } } _ => { - tcx.sess.span_bug(span, ~"trait wasn't \ - actually a \ - trait?!"); + tcx.sess.span_bug(span, "trait wasn't \ + actually a \ + trait?!"); } } } Some(_) => { - tcx.sess.span_bug(span, ~"trait wasn't an \ - item?!"); + tcx.sess.span_bug(span, "trait wasn't an \ + item?!"); } None => { - tcx.sess.span_bug(span, ~"trait item wasn't \ - found in the AST \ - map?!"); + tcx.sess.span_bug(span, "trait item wasn't \ + found in the AST \ + map?!"); } } } else { @@ -465,8 +465,8 @@ pub fn check_crate(tcx: ty::ctxt, match method_map.find(&expr.id) { None => { tcx.sess.span_bug(expr.span, - ~"method call not in \ - method map"); + "method call not in \ + method map"); } Some(ref entry) => { debug!("(privacy checking) checking \ @@ -512,18 +512,18 @@ pub fn check_crate(tcx: ty::ctxt, } _ => { tcx.sess.span_bug(expr.span, - ~"resolve didn't \ - map enum struct \ - constructor to a \ - variant def"); + "resolve didn't \ + map enum struct \ + constructor to a \ + variant def"); } } } } _ => { - tcx.sess.span_bug(expr.span, ~"struct expr \ - didn't have \ - struct type?!"); + tcx.sess.span_bug(expr.span, "struct expr \ + didn't have \ + struct type?!"); } } } @@ -579,18 +579,18 @@ pub fn check_crate(tcx: ty::ctxt, } _ => { tcx.sess.span_bug(pattern.span, - ~"resolve didn't \ - map enum struct \ - pattern to a \ - variant def"); + "resolve didn't \ + map enum struct \ + pattern to a \ + variant def"); } } } } _ => { tcx.sess.span_bug(pattern.span, - ~"struct pattern didn't have \ - struct type?!"); + "struct pattern didn't have \ + struct type?!"); } } } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 88e201fb5f438..4faa2150003f0 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -320,7 +320,7 @@ pub impl RegionMaps { pub fn parent_id(cx: ctxt, span: span) -> ast::node_id { match cx.parent { None => { - cx.sess.span_bug(span, ~"crate should not be parent here"); + cx.sess.span_bug(span, "crate should not be parent here"); } Some(parent_id) => { parent_id diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ccd7cc6a8ab98..f93097f3ce85d 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3261,7 +3261,7 @@ pub fn expr_kind(tcx: ctxt, ast::expr_mac(*) => { tcx.sess.span_bug( expr.span, - ~"macro expression remains after expansion"); + "macro expression remains after expansion"); } } } @@ -4242,27 +4242,27 @@ pub fn eval_repeat_count(tcx: ctxt, count_expr: @ast::expr) -> uint { const_eval::const_uint(count) => return count as uint, const_eval::const_float(count) => { tcx.sess.span_err(count_expr.span, - ~"expected signed or unsigned integer for \ - repeat count but found float"); + "expected signed or unsigned integer for \ + repeat count but found float"); return count as uint; } const_eval::const_str(_) => { tcx.sess.span_err(count_expr.span, - ~"expected signed or unsigned integer for \ - repeat count but found string"); + "expected signed or unsigned integer for \ + repeat count but found string"); return 0; } const_eval::const_bool(_) => { tcx.sess.span_err(count_expr.span, - ~"expected signed or unsigned integer for \ - repeat count but found boolean"); + "expected signed or unsigned integer for \ + repeat count but found boolean"); return 0; } }, Err(*) => { tcx.sess.span_err(count_expr.span, - ~"expected constant integer for repeat count \ - but found variable"); + "expected constant integer for repeat count \ + but found variable"); return 0; } } From 6210de9529f37bb4ff51050bca19dfd6f28026c9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2013 21:46:34 -0400 Subject: [PATCH 121/215] lang: fix code for maintaining borrow list --- src/libcore/unstable/lang.rs | 50 +++++++++++++++++++++++------ src/librustc/middle/trans/common.rs | 8 +++-- src/librustc/middle/trans/datum.rs | 3 +- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 283f232964963..017fc4b7b63a0 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -19,6 +19,7 @@ use sys; use unstable::exchange_alloc; use cast::transmute; use task::rt::rust_get_task; +use option::{Some, None}; #[allow(non_camel_case_types)] pub type rust_task = c_void; @@ -71,6 +72,7 @@ pub fn fail_bounds_check(file: *c_char, line: size_t, } } +#[deriving(Eq)] struct BorrowRecord { box: *mut BoxRepr, file: *c_char, @@ -108,7 +110,7 @@ pub fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { str::raw::from_c_str(entry.file) }; str::push_str(&mut msg, filename); - str::push_str(&mut msg, fmt!(":%u", line as uint)); + str::push_str(&mut msg, fmt!(":%u", entry.line as uint)); sep = " and at "; } } @@ -208,6 +210,26 @@ fn add_borrow_to_task_list(a: *mut BoxRepr, file: *c_char, line: size_t) { } } +fn remove_borrow_from_task_list(a: *mut BoxRepr, file: *c_char, line: size_t) { + do swap_task_borrow_list |borrow_list| { + let mut borrow_list = borrow_list; + let br = BorrowRecord {box: a, file: file, line: line}; + match borrow_list.rposition_elem(&br) { + Some(idx) => { + borrow_list.remove(idx); + borrow_list + } + None => { + let err = fmt!("no borrow found, br=%?, borrow_list=%?", + br, borrow_list); + do str::as_buf(err) |msg_p, _| { + fail_(msg_p as *c_char, file, line) + } + } + } + } +} + #[cfg(not(stage0))] #[lang="borrow_as_imm"] #[inline(always)] @@ -215,8 +237,9 @@ pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { let a: *mut BoxRepr = transmute(a); let ref_count = (*a).header.ref_count; - debug_ptr("borrow_as_imm (ptr): ", a); - debug_ptr("borrow_as_imm (ref): ", ref_count as *()); + debug_ptr("borrow_as_imm (ptr) :", a); + debug_ptr(" (ref) :", ref_count as *()); + debug_ptr(" (line): ", line as *()); if (ref_count & MUT_BIT) != 0 { fail_borrowed(a, file, line); @@ -236,7 +259,7 @@ pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint { let a: *mut BoxRepr = transmute(a); debug_ptr("borrow_as_mut (ptr): ", a); - debug_ptr("borrow_as_mut (line): ", line as *()); + debug_ptr(" (line): ", line as *()); let ref_count = (*a).header.ref_count; if (ref_count & (MUT_BIT|FROZEN_BIT)) != 0 { @@ -265,18 +288,25 @@ pub unsafe fn return_to_mut(a: *u8) { #[cfg(not(stage0))] #[lang="return_to_mut"] #[inline(always)] -pub unsafe fn return_to_mut(a: *u8, old_ref_count: uint) { +pub unsafe fn return_to_mut(a: *u8, old_ref_count: uint, + file: *c_char, line: size_t) { // Sometimes the box is null, if it is conditionally frozen. // See e.g. #4904. if !a.is_null() { let a: *mut BoxRepr = transmute(a); + let ref_count = (*a).header.ref_count; + let combined = (ref_count & !ALL_BITS) | (old_ref_count & ALL_BITS); + (*a).header.ref_count = combined; - debug_ptr("return_to_mut (ptr): ", a); - debug_ptr("return_to_mut (ref): ", old_ref_count as *()); + debug_ptr("return_to_mut (ptr) : ", a); + debug_ptr(" (line): ", line as *()); + debug_ptr(" (old) : ", old_ref_count as *()); + debug_ptr(" (new) : ", ref_count as *()); + debug_ptr(" (comb): ", combined as *()); - let ref_count = (*a).header.ref_count & !ALL_BITS; - let old_bits = old_ref_count & ALL_BITS; - (*a).header.ref_count = ref_count | old_bits; + if ::rt::env::get().debug_borrows { + remove_borrow_from_task_list(a, file, line); + } } } diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index d0da8a2e1ee74..dba9ddd2b1d1a 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -469,7 +469,9 @@ pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { } pub fn add_clean_return_to_mut(bcx: block, frozen_val_ref: ValueRef, - bits_val_ref: ValueRef) { + bits_val_ref: ValueRef, + filename_val: ValueRef, + line_val: ValueRef) { //! When an `@mut` has been frozen, we have to //! call the lang-item `return_to_mut` when the //! freeze goes out of scope. We need to pass @@ -495,7 +497,9 @@ pub fn add_clean_return_to_mut(bcx: block, build::PointerCast(bcx, frozen_val_ref, T_ptr(T_ptr(T_i8())))), - build::Load(bcx, bits_val_ref) + build::Load(bcx, bits_val_ref), + filename_val, + line_val ], expr::Ignore ) diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index f4fb3b6c6f5d5..d6df6c87dec43 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -578,7 +578,8 @@ pub impl Datum { expr::SaveIn(scratch_bits.val)); add_clean_return_to_mut( - cleanup_bcx, scratch.val, scratch_bits.val); + cleanup_bcx, scratch.val, scratch_bits.val, + filename, line); } } From fbaf8399c8d4670b16684a7d94c8ed70839ffc8e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2013 21:50:09 -0400 Subject: [PATCH 122/215] rustc: more fix for trans_lvalue rooted twice --- src/librustc/middle/trans/expr.rs | 25 ++++--------------------- 1 file changed, 4 insertions(+), 21 deletions(-) diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index a993f781cdb18..30c541c0c055b 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -823,7 +823,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { return match expr.node { ast::expr_paren(e) => { - unrooted(bcx, e) + trans_lvalue_unadjusted(bcx, e) } ast::expr_path(_) => { trans_def_lvalue(bcx, expr, bcx.def(expr.id)) @@ -849,12 +849,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { fn trans_rec_field(bcx: block, base: @ast::expr, field: ast::ident) -> DatumBlock { - /*! - * - * Translates `base.field`. Note that this version always - * yields an unrooted, unmoved version. Rooting and possible - * moves are dealt with above in trans_lvalue_unadjusted(). - */ + //! Translates `base.field`. let mut bcx = bcx; let _icx = bcx.insn_ctxt("trans_rec_field"); @@ -878,12 +873,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { index_expr: @ast::expr, base: @ast::expr, idx: @ast::expr) -> DatumBlock { - /*! - * - * Translates `base[idx]`. Note that this version always - * yields an unrooted, unmoved version. Rooting and possible - * moves are dealt with above in trans_lvalue_unadjusted(). - */ + //! Translates `base[idx]`. let _icx = bcx.insn_ctxt("trans_index"); let ccx = bcx.ccx(); @@ -946,14 +936,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { def: ast::def) -> DatumBlock { - /*! - * - * Translates a reference to a path. Note that this version - * generally yields an unrooted, unmoved version. Rooting and - * possible moves are dealt with above in - * trans_lvalue_unadjusted(), with the caveat that local variables - * may already be in move mode. - */ + //! Translates a reference to a path. let _icx = bcx.insn_ctxt("trans_def_lvalue"); let ccx = bcx.ccx(); From 5f886342be75ef465a8e0ffe6f4e7c237fb8fd67 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 1 May 2013 21:50:32 -0400 Subject: [PATCH 123/215] syntax: fix up dynamic borrow errors in libsyntax --- src/libsyntax/parse/lexer.rs | 4 ++-- src/libsyntax/parse/parser.rs | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 60d6ce504fd9a..163c7852132a5 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -163,7 +163,7 @@ fn string_advance_token(r: @mut StringReader) { } } -fn byte_offset(rdr: @mut StringReader) -> BytePos { +fn byte_offset(rdr: &StringReader) -> BytePos { (rdr.pos - rdr.filemap.start_pos) } @@ -176,7 +176,7 @@ pub fn get_str_from(rdr: @mut StringReader, start: BytePos) -> ~str { // EFFECT: advance the StringReader by one character. If a newline is // discovered, add it to the FileMap's list of line start offsets. -pub fn bump(rdr: @mut StringReader) { +pub fn bump(rdr: &mut StringReader) { rdr.last_pos = rdr.pos; let current_byte_offset = byte_offset(rdr).to_uint();; if current_byte_offset < (*rdr.src).len() { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 1ee651ede7510..457c6df8db254 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1607,9 +1607,9 @@ pub impl Parser { token::LBRACE | token::LPAREN | token::LBRACKET => { self.parse_matcher_subseq( name_idx, - &*self.token, + *self.token, // tjc: not sure why we need a copy - &token::flip_delimiter(&*self.token) + token::flip_delimiter(&*self.token) ) } _ => self.fatal(~"expected open delimiter") @@ -1623,15 +1623,15 @@ pub impl Parser { fn parse_matcher_subseq( &self, name_idx: @mut uint, - bra: &token::Token, - ket: &token::Token + bra: token::Token, + ket: token::Token ) -> ~[matcher] { let mut ret_val = ~[]; let mut lparens = 0u; - self.expect(bra); + self.expect(&bra); - while *self.token != *ket || lparens > 0u { + while *self.token != ket || lparens > 0u { if *self.token == token::LPAREN { lparens += 1u; } if *self.token == token::RPAREN { lparens -= 1u; } ret_val.push(self.parse_matcher(name_idx)); @@ -1651,8 +1651,8 @@ pub impl Parser { let name_idx_lo = *name_idx; let ms = self.parse_matcher_subseq( name_idx, - &token::LPAREN, - &token::RPAREN + token::LPAREN, + token::RPAREN ); if ms.len() == 0u { self.fatal(~"repetition body must be nonempty"); From 1bd318421e4fb4252074f2963ab77dddec7949ac Mon Sep 17 00:00:00 2001 From: James Miller Date: Thu, 2 May 2013 14:04:43 +1200 Subject: [PATCH 124/215] Add error if RED_ZONE_SIZE doesn't get defined --- src/rt/rust_task.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/rt/rust_task.h b/src/rt/rust_task.h index 4aa1199cabc3f..fd4e8451b642a 100644 --- a/src/rt/rust_task.h +++ b/src/rt/rust_task.h @@ -175,6 +175,10 @@ #define RED_ZONE_SIZE RZ_MAC_32 #endif +#ifndef RED_ZONE_SIZE +# error "Red zone not defined for this platform" +#endif + struct frame_glue_fns { uintptr_t mark_glue_off; uintptr_t drop_glue_off; From 8a28970ed36a9259b6cab2ad464f358c2d0bbb6f Mon Sep 17 00:00:00 2001 From: gifnksm Date: Thu, 2 May 2013 11:08:33 +0900 Subject: [PATCH 125/215] libcore: Make `ChainIterator` take two different-typed `Iterator`s. --- src/libcore/iterator.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/libcore/iterator.rs b/src/libcore/iterator.rs index 8bbf843085809..5e95485b27360 100644 --- a/src/libcore/iterator.rs +++ b/src/libcore/iterator.rs @@ -29,7 +29,7 @@ pub trait Iterator { /// /// In the future these will be default methods instead of a utility trait. pub trait IteratorUtil { - fn chain(self, other: Self) -> ChainIterator; + fn chain>(self, other: U) -> ChainIterator; fn zip>(self, other: U) -> ZipIterator; // FIXME: #5898: should be called map fn transform<'r, B>(self, f: &'r fn(A) -> B) -> MapIterator<'r, A, B, Self>; @@ -50,7 +50,7 @@ pub trait IteratorUtil { /// In the future these will be default methods instead of a utility trait. impl> IteratorUtil for T { #[inline(always)] - fn chain(self, other: T) -> ChainIterator { + fn chain>(self, other: U) -> ChainIterator { ChainIterator{a: self, b: other, flag: false} } @@ -115,13 +115,13 @@ impl> IteratorUtil for T { } } -pub struct ChainIterator { +pub struct ChainIterator { priv a: T, - priv b: T, + priv b: U, priv flag: bool } -impl> Iterator for ChainIterator { +impl, U: Iterator> Iterator for ChainIterator { #[inline] fn next(&mut self) -> Option { if self.flag { @@ -385,7 +385,7 @@ mod tests { #[test] fn test_iterator_chain() { let xs = [0u, 1, 2, 3, 4, 5]; - let ys = [30, 40, 50, 60]; + let ys = [30u, 40, 50, 60]; let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60]; let mut it = xs.iter().chain(ys.iter()); let mut i = 0; @@ -394,6 +394,15 @@ mod tests { i += 1; } assert_eq!(i, expected.len()); + + let ys = Counter::new(30u, 10).take(4); + let mut it = xs.iter().transform(|&x| x).chain(ys); + let mut i = 0; + for it.advance |x: uint| { + assert_eq!(x, expected[i]); + i += 1; + } + assert_eq!(i, expected.len()); } #[test] From d6697e702774c422871499826e7d346320610242 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 1 May 2013 21:54:02 -0400 Subject: [PATCH 126/215] pass along CFLAGS/LINK_FLAGS to libuv Closes #6142 --- mk/rt.mk | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mk/rt.mk b/mk/rt.mk index 015992abf7821..c4c80b99fc085 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -163,14 +163,16 @@ endif ifdef CFG_WINDOWSY_$(1) $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) $$(Q)$$(MAKE) -C $$(S)src/libuv/ \ + CFLAGS="$$(CFG_GCCISH_CFLAGS)" \ + LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS)" \ builddir_name="$$(CFG_BUILD_DIR)/rt/$(1)/libuv" \ OS=mingw \ V=$$(VERBOSE) else ifeq ($(OSTYPE_$(1)), linux-androideabi) $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) $$(Q)$$(MAKE) -C $$(S)src/libuv/ \ - CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \ - LDFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1)))" \ + CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \ + LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \ CC="$$(CC_$(1))" \ CXX="$$(CXX_$(1))" \ AR="$$(AR_$(1))" \ @@ -181,8 +183,8 @@ $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) else $$(LIBUV_LIB_$(1)): $$(LIBUV_DEPS) $$(Q)$$(MAKE) -C $$(S)src/libuv/ \ - CFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \ - LDFLAGS="$$(LIBUV_FLAGS_$$(HOST_$(1)))" \ + CFLAGS="$$(CFG_GCCISH_CFLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1))) $$(SNAP_DEFINES)" \ + LDFLAGS="$$(CFG_GCCISH_LINK_FLAGS) $$(LIBUV_FLAGS_$$(HOST_$(1)))" \ CC="$$(CC_$(1))" \ CXX="$$(CXX_$(1))" \ AR="$$(AR_$(1))" \ From e596128bd87b978fb163235bcf5eb0ef7d446218 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Wed, 1 May 2013 20:52:09 +1000 Subject: [PATCH 127/215] Remove 'Local Variable' comments --- src/compiletest/compiletest.rc | 7 ------- src/libcore/core.rc | 9 --------- src/libcore/either.rs | 10 ---------- src/libcore/io.rs | 10 ---------- src/libcore/libc.rs | 9 --------- src/libcore/num/cmath.rs | 11 ----------- src/libcore/num/f32.rs | 10 ---------- src/libcore/num/f64.rs | 10 ---------- src/libcore/num/float.rs | 10 ---------- src/libcore/option.rs | 8 -------- src/libcore/rand.rs | 9 --------- src/libcore/run.rs | 8 -------- src/libcore/sys.rs | 8 -------- src/libcore/unstable/extfmt.rs | 8 -------- src/libcore/unstable/lang.rs | 8 -------- src/libfuzzer/fuzzer.rc | 7 ------- src/librustc/back/abi.rs | 9 --------- src/librustc/back/arm.rs | 11 ----------- src/librustc/back/link.rs | 10 ---------- src/librustc/back/mips.rs | 11 ----------- src/librustc/back/upcall.rs | 9 --------- src/librustc/back/x86.rs | 10 ---------- src/librustc/back/x86_64.rs | 10 ---------- src/librustc/driver/driver.rs | 8 -------- src/librustc/driver/session.rs | 7 ------- src/librustc/front/config.rs | 8 -------- src/librustc/front/test.rs | 8 -------- src/librustc/lib/llvm.rs | 10 ---------- src/librustc/metadata/creader.rs | 8 -------- src/librustc/metadata/csearch.rs | 8 -------- src/librustc/metadata/cstore.rs | 8 -------- src/librustc/metadata/decoder.rs | 8 -------- src/librustc/metadata/encoder.rs | 9 --------- src/librustc/metadata/tydecode.rs | 10 ---------- src/librustc/metadata/tyencode.rs | 10 ---------- src/librustc/middle/check_const.rs | 8 -------- src/librustc/middle/check_match.rs | 8 -------- src/librustc/middle/const_eval.rs | 9 --------- src/librustc/middle/freevars.rs | 8 -------- src/librustc/middle/kind.rs | 10 ---------- src/librustc/middle/lint.rs | 10 ---------- src/librustc/middle/trans/_match.rs | 8 -------- src/librustc/middle/trans/base.rs | 9 --------- src/librustc/middle/trans/build.rs | 10 ---------- src/librustc/middle/trans/common.rs | 10 ---------- src/librustc/middle/trans/tvec.rs | 10 ---------- src/librustc/middle/ty.rs | 8 -------- src/librustc/middle/typeck/mod.rs | 9 --------- src/librustc/rustc.rc | 8 -------- src/librustc/util/common.rs | 10 ---------- src/librustc/util/ppaux.rs | 8 -------- src/libstd/bitv.rs | 10 ---------- src/libstd/dbg.rs | 8 -------- src/libstd/getopts.rs | 8 -------- src/libstd/list.rs | 8 -------- src/libstd/sha1.rs | 8 -------- src/libstd/sort.rs | 8 -------- src/libstd/std.rc | 8 -------- src/libstd/term.rs | 7 ------- src/libstd/test.rs | 9 --------- src/libsyntax/ast.rs | 9 --------- src/libsyntax/ast_map.rs | 8 -------- src/libsyntax/ast_util.rs | 8 -------- src/libsyntax/attr.rs | 10 ---------- src/libsyntax/codemap.rs | 12 ------------ src/libsyntax/ext/asm.rs | 12 ------------ src/libsyntax/ext/base.rs | 10 ---------- src/libsyntax/ext/env.rs | 10 ---------- src/libsyntax/ext/expand.rs | 8 -------- src/libsyntax/ext/fmt.rs | 9 --------- src/libsyntax/ext/source_util.rs | 10 ---------- src/libsyntax/ext/tt/macro_parser.rs | 8 -------- src/libsyntax/fold.rs | 10 ---------- src/libsyntax/parse/attr.rs | 10 ---------- src/libsyntax/parse/lexer.rs | 10 ---------- src/libsyntax/parse/mod.rs | 10 ---------- src/libsyntax/parse/parser.rs | 11 ----------- src/libsyntax/parse/token.rs | 8 -------- src/libsyntax/print/pp.rs | 11 ----------- src/libsyntax/print/pprust.rs | 10 ---------- src/libsyntax/visit.rs | 8 -------- src/test/run-pass/item-attributes.rs | 10 ---------- src/test/run-pass/spawn.rs | 8 -------- src/test/run-pass/spawn2.rs | 8 -------- src/test/run-pass/task-killjoin-rsrc.rs | 8 -------- src/test/run-pass/task-killjoin.rs | 8 -------- 86 files changed, 775 deletions(-) diff --git a/src/compiletest/compiletest.rc b/src/compiletest/compiletest.rc index 4392ce7ba2891..b6d690f83076f 100644 --- a/src/compiletest/compiletest.rc +++ b/src/compiletest/compiletest.rc @@ -223,10 +223,3 @@ pub fn make_test_closure(config: config, testfile: &Path) -> test::TestFn { let testfile = testfile.to_str(); test::DynTestFn(|| runtest::run(config, testfile)) } - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 9a0419ebfc6b2..f410591fdc7a3 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -263,12 +263,3 @@ mod core { pub use sys; pub use pipes; } - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/either.rs b/src/libcore/either.rs index 92f850cddd6d1..33b7e81ee85fb 100644 --- a/src/libcore/either.rs +++ b/src/libcore/either.rs @@ -263,13 +263,3 @@ fn test_partition_empty() { assert_eq!(vec::len(lefts), 0u); assert_eq!(vec::len(rights), 0u); } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/io.rs b/src/libcore/io.rs index 35ffd88c8f477..185b84a09c518 100644 --- a/src/libcore/io.rs +++ b/src/libcore/io.rs @@ -1954,13 +1954,3 @@ mod tests { } } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs index 999a5d9b350e4..53aaf5726dd0b 100644 --- a/src/libcore/libc.rs +++ b/src/libcore/libc.rs @@ -1846,12 +1846,3 @@ pub mod funcs { } } } - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/num/cmath.rs b/src/libcore/num/cmath.rs index 30b0c54dc2dc2..8a0a88235d20c 100644 --- a/src/libcore/num/cmath.rs +++ b/src/libcore/num/cmath.rs @@ -267,14 +267,3 @@ pub mod c_double_targ_consts { } */ - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// - diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 04ddd63a177e7..a00225e85bc49 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -986,13 +986,3 @@ mod tests { assert_eq!(Primitive::bytes::(), sys::size_of::()); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 9f1944e3fad7f..c3bd89b0e0361 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -1033,13 +1033,3 @@ mod tests { assert_eq!(Primitive::bytes::(), sys::size_of::()); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index f163d67a69ccb..b487fa48782b8 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -1139,13 +1139,3 @@ mod tests { assert_eq!(to_str_digits(-infinity, 10u), ~"-inf"); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 17192b4257b16..47ec1fabcb822 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -565,11 +565,3 @@ fn test_get_or_zero() { let no_stuff: Option = None; assert!(no_stuff.get_or_zero() == 0); } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/rand.rs b/src/libcore/rand.rs index 94ba5ba31b756..80f69f067eb54 100644 --- a/src/libcore/rand.rs +++ b/src/libcore/rand.rs @@ -1073,12 +1073,3 @@ mod tests { } } } - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 37401788ca2d1..d0c495dd19e44 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -639,11 +639,3 @@ mod tests { test_destroy_actually_kills(true); } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs index 8cad0a2288642..c0c1ad6d89615 100644 --- a/src/libcore/sys.rs +++ b/src/libcore/sys.rs @@ -343,11 +343,3 @@ mod tests { #[should_fail] fn fail_owned() { FailWithCause::fail_with(~"cause", file!(), line!()) } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/unstable/extfmt.rs b/src/libcore/unstable/extfmt.rs index b812be5575a4a..f65b1e6726ed4 100644 --- a/src/libcore/unstable/extfmt.rs +++ b/src/libcore/unstable/extfmt.rs @@ -688,11 +688,3 @@ mod test { let _s = fmt!("%s", s); } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 611862a79e7e0..a6599e03d6b72 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -183,11 +183,3 @@ pub fn start(main: *u8, argc: int, argv: **c_char, crate_map: *c_void) -> c_int; } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libfuzzer/fuzzer.rc b/src/libfuzzer/fuzzer.rc index fc1efd3313cbc..7c93d867f5040 100644 --- a/src/libfuzzer/fuzzer.rc +++ b/src/libfuzzer/fuzzer.rc @@ -693,10 +693,3 @@ pub fn main() { error!("Fuzzer done"); } - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/back/abi.rs b/src/librustc/back/abi.rs index 70a029ede6f8d..842dd89a7cd49 100644 --- a/src/librustc/back/abi.rs +++ b/src/librustc/back/abi.rs @@ -77,12 +77,3 @@ pub fn bzero_glue_name() -> ~str { return ~"rust_bzero_glue"; } pub fn yield_glue_name() -> ~str { return ~"rust_yield_glue"; } pub fn no_op_type_glue_name() -> ~str { return ~"rust_no_op_type_glue"; } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/back/arm.rs b/src/librustc/back/arm.rs index 97c3a588a7fc8..dfe5751f21b83 100644 --- a/src/librustc/back/arm.rs +++ b/src/librustc/back/arm.rs @@ -72,14 +72,3 @@ pub fn get_target_strs(target_os: session::os) -> target_strs::t { cc_args: ~[~"-marm"] }; } - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index adaffe5873dab..87e08a73fcb1c 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -949,13 +949,3 @@ pub fn link_args(sess: Session, return args; } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/back/mips.rs b/src/librustc/back/mips.rs index 93c1879eb0f4b..b15306a56b0b9 100644 --- a/src/librustc/back/mips.rs +++ b/src/librustc/back/mips.rs @@ -72,14 +72,3 @@ pub fn get_target_strs(target_os: session::os) -> target_strs::t { cc_args: ~[] }; } - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/back/upcall.rs b/src/librustc/back/upcall.rs index 4cdd279e2fc25..8fcc5234e8b51 100644 --- a/src/librustc/back/upcall.rs +++ b/src/librustc/back/upcall.rs @@ -59,12 +59,3 @@ pub fn declare_upcalls(targ_cfg: @session::config, nothrow(dv(~"reset_stack_limit", ~[])) } } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/back/x86.rs b/src/librustc/back/x86.rs index 2cc812c3d4105..759f5f63c9ec2 100644 --- a/src/librustc/back/x86.rs +++ b/src/librustc/back/x86.rs @@ -55,13 +55,3 @@ pub fn get_target_strs(target_os: session::os) -> target_strs::t { cc_args: ~[~"-m32"] }; } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/back/x86_64.rs b/src/librustc/back/x86_64.rs index b68073974dcf9..ed6f1d285147e 100644 --- a/src/librustc/back/x86_64.rs +++ b/src/librustc/back/x86_64.rs @@ -63,13 +63,3 @@ pub fn get_target_strs(target_os: session::os) -> target_strs::t { cc_args: ~[~"-m64"] }; } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 8c053c265fa21..afd0e0acfe910 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -951,11 +951,3 @@ mod test { assert!((vec::len(test_items) == 1u)); } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index ff623049f758d..b9e0eeb346669 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -430,10 +430,3 @@ mod test { assert!(building_library(lib_crate, crate, true)); } } - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/front/config.rs b/src/librustc/front/config.rs index 75ae8724d720b..2246dd9d2f0aa 100644 --- a/src/librustc/front/config.rs +++ b/src/librustc/front/config.rs @@ -194,11 +194,3 @@ pub fn metas_in_cfg(cfg: ast::crate_cfg, }) }) } - - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 02e2a4c8734f8..4506feece2b8f 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -456,11 +456,3 @@ fn mk_test_desc_and_fn_rec(cx: &TestCtxt, test: &Test) -> @ast::expr { ); e } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 31050448e7552..fbb3380554d9e 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -2196,13 +2196,3 @@ pub fn mk_section_iter(llof: ObjectFileRef) -> SectionIter { } } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index 0d0f0d7ab69f3..da7a2c15f30be 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -328,11 +328,3 @@ fn resolve_crate_deps(e: @mut Env, cdata: @~[u8]) -> cstore::cnum_map { } return @mut cnum_map; } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index f8dc34f9cee3a..375989b0ebe61 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -243,11 +243,3 @@ pub fn get_link_args_for_crate(cstore: @mut cstore::CStore, let cdata = cstore::get_crate_data(cstore, crate_num); decoder::get_link_args_for_crate(cdata) } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/metadata/cstore.rs b/src/librustc/metadata/cstore.rs index 05275a4c66558..21815a9ed4718 100644 --- a/src/librustc/metadata/cstore.rs +++ b/src/librustc/metadata/cstore.rs @@ -161,11 +161,3 @@ pub fn get_dep_hashes(cstore: &CStore) -> ~[~str] { sorted.map(|ch| /*bad*/copy *ch.hash) } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index fb7b3f9c8b129..61454c802cc9a 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -1176,11 +1176,3 @@ pub fn get_link_args_for_crate(cdata: cmd) -> ~[~str] { } result } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index ba6a4f30857eb..2a4334781e4dc 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -1420,12 +1420,3 @@ pub fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str { tyencode::enc_ty(wr, cx, t); } } - - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs index 011ee115e8c15..b12db430afc31 100644 --- a/src/librustc/metadata/tydecode.rs +++ b/src/librustc/metadata/tydecode.rs @@ -567,13 +567,3 @@ fn parse_bounds(st: @mut PState, conv: conv_did) -> @~[ty::param_bound] { } @bounds } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs index 763b1984b81c8..0548204b154e0 100644 --- a/src/librustc/metadata/tyencode.rs +++ b/src/librustc/metadata/tyencode.rs @@ -416,13 +416,3 @@ pub fn enc_type_param_def(w: @io::Writer, cx: @ctxt, v: &ty::TypeParameterDef) { w.write_char('|'); enc_bounds(w, cx, v.bounds); } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 6a47eedcea8c3..36be65ed63f5b 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -253,11 +253,3 @@ pub fn check_item_recursion(sess: Session, visit::visit_expr(e, env, v); } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 852eb1b50a499..e412a0e51027c 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -862,11 +862,3 @@ pub fn check_legality_of_move_bindings(cx: @MatchCheckCtxt, (vt.visit_pat)(*pat, false, vt); } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/middle/const_eval.rs b/src/librustc/middle/const_eval.rs index 86b7379bb698d..63b9fcf7096d0 100644 --- a/src/librustc/middle/const_eval.rs +++ b/src/librustc/middle/const_eval.rs @@ -484,12 +484,3 @@ pub fn lit_expr_eq(tcx: middle::ty::ctxt, a: @expr, b: @expr) -> bool { pub fn lit_eq(a: @lit, b: @lit) -> bool { compare_const_vals(&lit_to_const(a), &lit_to_const(b)) == 0 } - - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/middle/freevars.rs b/src/librustc/middle/freevars.rs index 4c8d36f93f4b2..419b75a2ad9d8 100644 --- a/src/librustc/middle/freevars.rs +++ b/src/librustc/middle/freevars.rs @@ -119,11 +119,3 @@ pub fn get_freevars(tcx: ty::ctxt, fid: ast::node_id) -> freevar_info { pub fn has_freevars(tcx: ty::ctxt, fid: ast::node_id) -> bool { return vec::len(*get_freevars(tcx, fid)) != 0u; } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 0925e8cdd6375..90e6f7c6af92b 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -587,13 +587,3 @@ pub fn check_kind_bounds_of_cast(cx: Context, source: @expr, target: @expr) { _ => {} // Nothing to do. } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index b67d74bc272b6..f6db25065b7a8 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -946,13 +946,3 @@ pub fn check_crate(tcx: ty::ctxt, crate: @ast::crate) { tcx.sess.abort_if_errors(); } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 3755cca8c35e9..197b537fe9003 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1862,11 +1862,3 @@ pub fn bind_irrefutable_pat(bcx: block, } return bcx; } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 2090e50000b01..0c3e3ba3cb672 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -3172,12 +3172,3 @@ pub fn trans_crate(sess: session::Session, return (llmod, link_meta); } } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index f5c496484a037..a02ac96e520bd 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -1086,13 +1086,3 @@ pub fn AtomicRMW(cx: block, op: AtomicBinOp, llvm::LLVMBuildAtomicRMW(B(cx), op, dst, src, order) } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index f8fb0f4b7cf31..d31caffe77a14 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -1521,13 +1521,3 @@ pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs { pub fn bool_to_i1(bcx: block, llval: ValueRef) -> ValueRef { build::ICmp(bcx, lib::llvm::IntNE, llval, C_bool(false)) } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 30a7648e7eafb..da1cdfa4db103 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -594,13 +594,3 @@ pub fn iter_vec_unboxed(bcx: block, body_ptr: ValueRef, vec_ty: ty::t, let dataptr = get_dataptr(bcx, body_ptr); return iter_vec_raw(bcx, dataptr, vec_ty, fill, f); } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ccd7cc6a8ab98..1546c885a6d62 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -4370,11 +4370,3 @@ pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) { (trait_ref, mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs, BoxTraitStore, ast::m_imm)) } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 646b6412f5507..b0e0b7319ac84 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -426,12 +426,3 @@ pub fn check_crate(tcx: ty::ctxt, tcx.sess.abort_if_errors(); (ccx.method_map, ccx.vtable_map) } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 54c51cf2e487a..adb1c2fcc4171 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -357,11 +357,3 @@ pub fn main() { run_compiler(&args, demitter); } } - - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 38f55b2b6e423..b4a479fc5970f 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -112,13 +112,3 @@ pub fn pluralize(n: uint, s: ~str) -> ~str { // A set of node IDs (used to keep track of which node IDs are for statements) pub type stmt_set = @mut HashSet; - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index aa8c3f8fd1b7e..69849a8d51b83 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -739,11 +739,3 @@ impl Repr for ty::vstore { vstore_to_str(tcx, *self) } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End diff --git a/src/libstd/bitv.rs b/src/libstd/bitv.rs index 5314c35419cc5..078ed6af5a02a 100644 --- a/src/libstd/bitv.rs +++ b/src/libstd/bitv.rs @@ -1507,13 +1507,3 @@ mod tests { } } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libstd/dbg.rs b/src/libstd/dbg.rs index 34dd6390ecc12..4b2d2a60a68ef 100644 --- a/src/libstd/dbg.rs +++ b/src/libstd/dbg.rs @@ -76,11 +76,3 @@ fn test_breakpoint_should_not_abort_process_when_not_under_gdb() { // the process under normal circumstances breakpoint(); } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/getopts.rs b/src/libstd/getopts.rs index fda5c105da5f7..c03042fe9c2bf 100644 --- a/src/libstd/getopts.rs +++ b/src/libstd/getopts.rs @@ -1374,11 +1374,3 @@ Options: assert!(usage == expected) } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/list.rs b/src/libstd/list.rs index 401cc121a62a8..2b6fa0bc05691 100644 --- a/src/libstd/list.rs +++ b/src/libstd/list.rs @@ -242,11 +242,3 @@ mod tests { == list::append(list::from_vec(~[1,2]), list::from_vec(~[3,4]))); } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/sha1.rs b/src/libstd/sha1.rs index 7371250b38a91..a8e0f7d062a58 100644 --- a/src/libstd/sha1.rs +++ b/src/libstd/sha1.rs @@ -412,11 +412,3 @@ mod tests { } } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/sort.rs b/src/libstd/sort.rs index 3e6011e80df81..172532a2e5b6b 100644 --- a/src/libstd/sort.rs +++ b/src/libstd/sort.rs @@ -1202,11 +1202,3 @@ mod big_tests { } } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 0a5348d79760e..ea099090ebaba 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -121,11 +121,3 @@ pub mod std { pub use serialize; pub use test; } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/term.rs b/src/libstd/term.rs index 022f1f8564ece..a79b9f4c84980 100644 --- a/src/libstd/term.rs +++ b/src/libstd/term.rs @@ -76,10 +76,3 @@ pub fn fg(writer: @io::Writer, color: u8) { pub fn bg(writer: @io::Writer, color: u8) { return set_color(writer, '4' as u8, color); } - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libstd/test.rs b/src/libstd/test.rs index 278a326d1de95..65fb0c7426a4e 100644 --- a/src/libstd/test.rs +++ b/src/libstd/test.rs @@ -960,12 +960,3 @@ mod tests { } } } - - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 4bb2d220ad669..a295952439fba 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -1346,12 +1346,3 @@ mod test { } */ -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs index d2125cebb5e48..69397276c4f54 100644 --- a/src/libsyntax/ast_map.rs +++ b/src/libsyntax/ast_map.rs @@ -404,11 +404,3 @@ pub fn node_item_query(items: map, id: node_id, _ => fail!(error_msg) } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 2b3793e45e9c8..47ef7227842e2 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -832,11 +832,3 @@ mod test { } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs index 2f8405c6e9689..f4f0def284327 100644 --- a/src/libsyntax/attr.rs +++ b/src/libsyntax/attr.rs @@ -341,13 +341,3 @@ pub fn require_unique_names(diagnostic: @span_handler, } } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 1194506a8876f..5f4967351e11b 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -522,15 +522,3 @@ mod test { fm.next_line(BytePos(2)); } } - - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index dfebf6f786a28..53f40113532b2 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -187,15 +187,3 @@ pub fn expand_asm(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) span: sp }) } - - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 2d6d74b5c1e32..1c03ad1375919 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -543,13 +543,3 @@ mod test { assert_eq!(*(m.find(&@~"def").get()),16); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs index 5e5fd7d97b19f..5b1e3737b236b 100644 --- a/src/libsyntax/ext/env.rs +++ b/src/libsyntax/ext/env.rs @@ -34,13 +34,3 @@ pub fn expand_syntax_ext(cx: @ext_ctxt, sp: span, tts: &[ast::token_tree]) }; MRExpr(e) } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index fde5a2594226e..02a698b283d39 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -721,11 +721,3 @@ mod test { } } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index 9bbe617eb070b..62641279f883a 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.rs @@ -322,12 +322,3 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span, return mk_block(cx, fmt_sp, ~[], stms, Some(buf())); } -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs index 70aa9472c855b..ab22b3152f477 100644 --- a/src/libsyntax/ext/source_util.rs +++ b/src/libsyntax/ext/source_util.rs @@ -150,13 +150,3 @@ fn res_rel_file(cx: @ext_ctxt, sp: codemap::span, arg: &Path) -> Path { copy *arg } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/ext/tt/macro_parser.rs b/src/libsyntax/ext/tt/macro_parser.rs index e4e033e0ffff7..0c1e619985d26 100644 --- a/src/libsyntax/ext/tt/macro_parser.rs +++ b/src/libsyntax/ext/tt/macro_parser.rs @@ -438,11 +438,3 @@ pub fn parse_nt(p: &Parser, name: ~str) -> nonterminal { _ => p.fatal(~"Unsupported builtin nonterminal parser: " + name) } } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 36565395e5988..229a8664d0c35 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -859,13 +859,3 @@ impl AstFoldExtensions for @ast_fold { pub fn make_fold(afp: ast_fold_fns) -> @ast_fold { afp as @ast_fold } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index cc580155d70cf..037b2c089f46a 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -179,13 +179,3 @@ impl parser_attr for Parser { } } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 60d6ce504fd9a..16a7ef71317ef 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -892,13 +892,3 @@ mod test { assert_eq!(tok, token::LIFETIME(id)); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 5d51a54d770b1..74e4f562ce5c5 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -674,13 +674,3 @@ mod test { string_to_expr(@~"a::z.froob(b,@(987+3))"); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index a582748edb39c..8459fc8c6273d 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -4509,14 +4509,3 @@ pub impl Parser { } } } - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index 338b7c99d9730..fe7bd5b3bc17d 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -556,11 +556,3 @@ pub fn reserved_keyword_table() -> HashSet<~str> { } return words; } - - -// Local Variables: -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/libsyntax/print/pp.rs b/src/libsyntax/print/pp.rs index e2ad5becb123b..3fa615939b77e 100644 --- a/src/libsyntax/print/pp.rs +++ b/src/libsyntax/print/pp.rs @@ -587,14 +587,3 @@ pub fn hardbreak_tok_offset(off: int) -> token { } pub fn hardbreak_tok() -> token { return hardbreak_tok_offset(0); } - - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index ab958d8b5cef5..76de109eebd30 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -2280,13 +2280,3 @@ mod test { assert_eq!(&varstr,&~"pub principal_skinner"); } } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 71cfbab91089e..9a0c97d76162b 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -757,11 +757,3 @@ pub fn mk_simple_visitor(v: simple_visitor) -> vt<()> { v_struct_method(v.visit_struct_method, a, b, c) }); } - -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/test/run-pass/item-attributes.rs b/src/test/run-pass/item-attributes.rs index 24fe671337287..c616d46a8336c 100644 --- a/src/test/run-pass/item-attributes.rs +++ b/src/test/run-pass/item-attributes.rs @@ -195,13 +195,3 @@ fn test_fn_inner() { } pub fn main() { } - -// -// Local Variables: -// mode: rust -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: -// diff --git a/src/test/run-pass/spawn.rs b/src/test/run-pass/spawn.rs index db4ca7b3ed863..63c2b7da38f2f 100644 --- a/src/test/run-pass/spawn.rs +++ b/src/test/run-pass/spawn.rs @@ -18,11 +18,3 @@ pub fn main() { } fn child(&&i: int) { error!(i); assert!((i == 10)); } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/test/run-pass/spawn2.rs b/src/test/run-pass/spawn2.rs index f9350746349b3..e748a1636ea80 100644 --- a/src/test/run-pass/spawn2.rs +++ b/src/test/run-pass/spawn2.rs @@ -32,11 +32,3 @@ fn child(&&args: (int, int, int, int, int, int, int, int, int)) { assert!((i8 == 80)); assert!((i9 == 90)); } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/test/run-pass/task-killjoin-rsrc.rs b/src/test/run-pass/task-killjoin-rsrc.rs index 7cd08695da0f0..879f668577f86 100644 --- a/src/test/run-pass/task-killjoin-rsrc.rs +++ b/src/test/run-pass/task-killjoin-rsrc.rs @@ -83,11 +83,3 @@ fn supervisor() { pub fn main() { join(joinable(supervisor)); } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: diff --git a/src/test/run-pass/task-killjoin.rs b/src/test/run-pass/task-killjoin.rs index 563e35be3d63b..73c069e560cd0 100644 --- a/src/test/run-pass/task-killjoin.rs +++ b/src/test/run-pass/task-killjoin.rs @@ -33,11 +33,3 @@ fn supervisor() { pub fn main() { task::spawn_unlinked(supervisor) } - -// Local Variables: -// mode: rust; -// fill-column: 78; -// indent-tabs-mode: nil -// c-basic-offset: 4 -// buffer-file-coding-system: utf-8-unix -// End: From c1de90cdb255c476cc6b08ba9b2031e259dabfab Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Wed, 1 May 2013 20:30:05 -0700 Subject: [PATCH 128/215] rustc: remove ty::LegacyDtor --- src/librustc/middle/trans/glue.rs | 26 +++++++------------------- src/librustc/middle/ty.rs | 1 - 2 files changed, 7 insertions(+), 20 deletions(-) diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 4c5a17056b2ea..1f90b009ec656 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -443,11 +443,8 @@ pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) { // Call the dtor if there is one match ty::ty_dtor(bcx.tcx(), did) { ty::NoDtor => bcx, - ty::LegacyDtor(ref dt_id) => { - trans_struct_drop(bcx, t, v, *dt_id, did, substs, false) - } ty::TraitDtor(ref dt_id) => { - trans_struct_drop(bcx, t, v, *dt_id, did, substs, true) + trans_struct_drop(bcx, t, v, *dt_id, did, substs) } } } @@ -461,8 +458,7 @@ pub fn trans_struct_drop(bcx: block, v0: ValueRef, dtor_did: ast::def_id, class_did: ast::def_id, - substs: &ty::substs, - take_ref: bool) + substs: &ty::substs) -> block { let repr = adt::represent_type(bcx.ccx(), t); let drop_flag = adt::trans_drop_flag_ptr(bcx, repr, v0); @@ -484,15 +480,10 @@ pub fn trans_struct_drop(bcx: block, // (self) assert!((params.len() == 2)); - // If we need to take a reference to the class (because it's using - // the Drop trait), do so now. - let llval; - if take_ref { - llval = alloca(bcx, val_ty(v0)); - Store(bcx, v0, llval); - } else { - llval = v0; - } + // Take a reference to the class (because it's using the Drop trait), + // do so now. + let llval = alloca(bcx, val_ty(v0)); + Store(bcx, v0, llval); let self_arg = PointerCast(bcx, llval, params[1]); let args = ~[C_null(T_ptr(T_i8())), self_arg]; @@ -534,10 +525,7 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) { let tcx = bcx.tcx(); match ty::ty_dtor(tcx, did) { ty::TraitDtor(dtor) => { - trans_struct_drop(bcx, t, v0, dtor, did, substs, true) - } - ty::LegacyDtor(dtor) => { - trans_struct_drop(bcx, t, v0, dtor, did, substs, false) + trans_struct_drop(bcx, t, v0, dtor, did, substs) } ty::NoDtor => { // No dtor? Just the default case diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index ccd7cc6a8ab98..e5f9dcb263a80 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3728,7 +3728,6 @@ pub fn item_path_str(cx: ctxt, id: ast::def_id) -> ~str { pub enum DtorKind { NoDtor, - LegacyDtor(def_id), TraitDtor(def_id) } From 6f6dd86248d5c3ece0e668537e78a71198f36ddd Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Thu, 2 May 2013 13:16:01 +0900 Subject: [PATCH 129/215] compiletest: configurable test dir for ARM --- mk/tests.mk | 7 ++++--- src/compiletest/common.rs | 5 ++++- src/compiletest/compiletest.rc | 5 ++++- src/compiletest/runtest.rs | 21 +++++++++------------ 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index 21754a9f51d0a..310dec8de7977 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -502,12 +502,13 @@ ifeq ($(CFG_ADB_DEVICE),true) CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --compile-lib-path $$(HLIB$(1)_H_$(3)) \ --run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \ - --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ - --aux-base $$(S)src/test/auxiliary/ \ + --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ + --aux-base $$(S)src/test/auxiliary/ \ --stage-id stage$(1)-$(2) \ --host $(CFG_BUILD_TRIPLE) \ --target $(2) \ --adb-path=$(CFG_ADB_PATH) \ + --adb-test-dir=$(CFG_ADB_TEST_DIR) \ --rustcflags "$(RUSTC_FLAGS_$(2)) $$(CFG_RUSTC_FLAGS) --target=$(2)" \ $$(CTEST_TESTARGS) @@ -516,7 +517,7 @@ else CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --compile-lib-path $$(HLIB$(1)_H_$(3)) \ --run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \ - --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ + --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ --aux-base $$(S)src/test/auxiliary/ \ --stage-id stage$(1)-$(2) \ --host $(CFG_BUILD_TRIPLE) \ diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs index 73322fe1bdeac..87a7dae5a7f6e 100644 --- a/src/compiletest/common.rs +++ b/src/compiletest/common.rs @@ -70,9 +70,12 @@ pub struct config { // Target System to be executed target: ~str, - // Extra parameter to run arm-linux-androideabi + // Extra parameter to run adb on arm-linux-androideabi adb_path: ~str, + // Extra parameter to run test sute on arm-linux-androideabi + adb_test_dir: ~str, + // check if can be run or not flag_runnable: bool, diff --git a/src/compiletest/compiletest.rc b/src/compiletest/compiletest.rc index 70e09fc7bab7e..5575c01a9065b 100644 --- a/src/compiletest/compiletest.rc +++ b/src/compiletest/compiletest.rc @@ -63,7 +63,8 @@ pub fn parse_config(args: ~[~str]) -> config { getopts::optflag(~"newrt"), getopts::optopt(~"host"), getopts::optopt(~"target"), - getopts::optopt(~"adb-path") + getopts::optopt(~"adb-path"), + getopts::optopt(~"adb-test-dir") ]; assert!(!args.is_empty()); @@ -100,6 +101,7 @@ pub fn parse_config(args: ~[~str]) -> config { host: opt_str(getopts::opt_maybe_str(matches, ~"host")), target: opt_str(getopts::opt_maybe_str(matches, ~"target")), adb_path: opt_str(getopts::opt_maybe_str(matches, ~"adb-path")), + adb_test_dir: opt_str(getopts::opt_maybe_str(matches, ~"adb-test-dir")), flag_runnable: if (getopts::opt_maybe_str(matches, ~"host") == getopts::opt_maybe_str(matches, ~"target")) { true } @@ -136,6 +138,7 @@ pub fn log_config(config: config) { logv(c, fmt!("host: %s", config.host)); logv(c, fmt!("target: %s", config.target)); logv(c, fmt!("adb_path: %s", config.adb_path)); + logv(c, fmt!("adb_test_dir: %s", config.adb_test_dir)); logv(c, fmt!("flag_runnable: %b", config.flag_runnable)); logv(c, fmt!("verbose: %b", config.verbose)); logv(c, fmt!("\n")); diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index ad128f4529c66..142460fe0dc09 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -512,7 +512,7 @@ fn exec_compiled_test(config: config, props: TestProps, // copy to target let copy_result = procsrv::run(~"", config.adb_path, - ~[~"push", args.prog, ~"/system/tmp"], + ~[~"push", args.prog, config.adb_test_dir], ~[(~"",~"")], Some(~"")); if config.verbose { @@ -534,16 +534,13 @@ fn exec_compiled_test(config: config, props: TestProps, let mut newcmd_out = ~""; let mut newcmd_err = ~""; - newcmd_out.push_str(~"LD_LIBRARY_PATH=/system/tmp; "); - newcmd_err.push_str(~"LD_LIBRARY_PATH=/system/tmp; "); - newcmd_out.push_str(~"export LD_LIBRARY_PATH; "); - newcmd_err.push_str(~"export LD_LIBRARY_PATH; "); - newcmd_out.push_str(~"cd /system/tmp; "); - newcmd_err.push_str(~"cd /system/tmp; "); - newcmd_out.push_str("./"); - newcmd_err.push_str("./"); - newcmd_out.push_str(prog_short); - newcmd_err.push_str(prog_short); + newcmd_out.push_str(fmt!( + "LD_LIBRARY_PATH=%s; export LD_LIBRARY_PATH; cd %s; ./%s", + config.adb_test_dir, config.adb_test_dir, prog_short)); + + newcmd_err.push_str(fmt!( + "LD_LIBRARY_PATH=%s; export LD_LIBRARY_PATH; cd %s; ./%s", + config.adb_test_dir, config.adb_test_dir, prog_short)); for vec::each(subargs) |tv| { newcmd_out.push_str(" "); @@ -617,7 +614,7 @@ fn compose_and_run_compiler( if (file.filetype() == Some(~".so")) { let copy_result = procsrv::run(~"", config.adb_path, - ~[~"push", file.to_str(), ~"/system/tmp"], + ~[~"push", file.to_str(), config.adb_test_dir], ~[(~"",~"")], Some(~"")); if config.verbose { From 5f1a90ebe7ea3d3102dbffcaabaf8803d650db80 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 29 Apr 2013 16:25:40 +0200 Subject: [PATCH 130/215] Issue 4391: rustc should not silently skip tests with erroneous signature. --- src/librustc/front/test.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 4506feece2b8f..94eade675e7a7 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -141,7 +141,7 @@ fn fold_item(cx: @mut TestCtxt, i: @ast::item, fld: @fold::ast_fold) debug!("current path: %s", ast_util::path_name_i(copy cx.path, cx.sess.parse_sess.interner)); - if is_test_fn(i) || is_bench_fn(i) { + if is_test_fn(cx, i) || is_bench_fn(i) { match i.node { ast::item_fn(_, purity, _, _, _) if purity == ast::unsafe_fn => { let sess = cx.sess; @@ -169,7 +169,7 @@ fn fold_item(cx: @mut TestCtxt, i: @ast::item, fld: @fold::ast_fold) return res; } -fn is_test_fn(i: @ast::item) -> bool { +fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool { let has_test_attr = !attr::find_attrs_by_name(i.attrs, ~"test").is_empty(); @@ -188,6 +188,13 @@ fn is_test_fn(i: @ast::item) -> bool { } } + if has_test_attr && !has_test_signature(i) { + let sess = cx.sess; + sess.span_fatal( + i.span, + ~"functions used as tests must have signature fn() -> ()." + ); + } return has_test_attr && has_test_signature(i); } From c14aa7eba88a3d0a26513dbb2a3acdcdcfc5072d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 30 Apr 2013 13:02:29 +0200 Subject: [PATCH 131/215] mod items need to be marked with `cfg(test)` not `test`. --- src/libcore/hashmap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index 41f4f34dc1971..9b82a8dad059e 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -833,7 +833,7 @@ pub impl HashSet { } } -#[test] +#[cfg(test)] mod test_map { use container::{Container, Map, Set}; use option::{None, Some}; @@ -1009,7 +1009,7 @@ mod test_map { } } -#[test] +#[cfg(test)] mod test_set { use super::*; use container::{Container, Map, Set}; From 880e300ed7a35de9ecff489d7fc0d24f2e975109 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 30 Apr 2013 14:36:18 +0200 Subject: [PATCH 132/215] mod items need to be marked with `cfg(test)` not `test`. --- src/libcore/task/mod.rs | 2 +- src/libstd/cmp.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index 2a4817727f4cf..0e97c101dc651 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -797,7 +797,7 @@ fn test_run_basic() { po.recv(); } -#[test] +#[cfg(test)] struct Wrapper { mut f: Option> } diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs index 5d7f64a7c8fa0..ea3793c137483 100644 --- a/src/libstd/cmp.rs +++ b/src/libstd/cmp.rs @@ -64,7 +64,7 @@ fn test_fuzzy_eq_eps() { assert!(!(&1.5f).fuzzy_eq_eps(&0.9, &0.5)); } -#[test] +#[cfg(test)] mod test_complex{ use cmp::*; From 46c2b5b0458b4c7dc7b28486c2721719fa729996 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 2 May 2013 01:31:58 +0200 Subject: [PATCH 133/215] Lets see if changing `span_fatal` to `span_err` gets me further through make check. --- src/librustc/front/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/front/test.rs b/src/librustc/front/test.rs index 94eade675e7a7..ddd702e7d697d 100644 --- a/src/librustc/front/test.rs +++ b/src/librustc/front/test.rs @@ -190,7 +190,7 @@ fn is_test_fn(cx: @mut TestCtxt, i: @ast::item) -> bool { if has_test_attr && !has_test_signature(i) { let sess = cx.sess; - sess.span_fatal( + sess.span_err( i.span, ~"functions used as tests must have signature fn() -> ()." ); From a636f5160a0f186d218e135924b321bb6d4f1ad7 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 2 May 2013 01:32:37 +0200 Subject: [PATCH 134/215] More cases of [cfg(test)] instead of [test]. --- src/libcore/repr.rs | 2 +- src/libstd/deque.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs index 03e44e00d8831..29b8400706ce0 100644 --- a/src/libcore/repr.rs +++ b/src/libcore/repr.rs @@ -673,7 +673,7 @@ pub fn write_repr(writer: @Writer, object: &T) { } } -#[test] +#[cfg(test)] struct P {a: int, b: float} #[test] diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs index 5d52bb7c0810b..8a310a9f52b5e 100644 --- a/src/libstd/deque.rs +++ b/src/libstd/deque.rs @@ -353,7 +353,7 @@ mod tests { assert!(*deq.get(3) == d); } - #[test] + #[cfg(test)] fn test_parameterized(a: T, b: T, c: T, d: T) { let mut deq = Deque::new(); assert!(deq.len() == 0); From 9862cf703b8a867b13e674f892f7059b09fe59e0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 2 May 2013 08:50:19 +0200 Subject: [PATCH 135/215] More cases of [cfg(test)] instead of [test]. --- src/libsyntax/parse/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 74e4f562ce5c5..4f1d41a4a7a17 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -418,7 +418,7 @@ mod test { new_parser_from_source_str(ps,~[],~"bogofile",source_str) } - #[test] fn to_json_str>(val: @E) -> ~str { + #[cfg(test)] fn to_json_str>(val: @E) -> ~str { do io::with_str_writer |writer| { val.encode(~std::json::Encoder(writer)); } From afcb9e9d868238accfdff2089684470bf89a92f8 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 2 May 2013 17:49:11 +1000 Subject: [PATCH 136/215] core: inlining on common functions --- src/libcore/str.rs | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 064bffa00561f..1ddebf8332069 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -77,6 +77,7 @@ pub fn from_bytes_slice<'a>(vector: &'a [u8]) -> &'a str { } /// Copy a slice into a new unique str +#[inline(always)] pub fn from_slice(s: &str) -> ~str { unsafe { raw::slice_bytes_owned(s, 0, len(s)) } } @@ -820,6 +821,7 @@ Section: Comparing strings /// Bytewise slice equality #[cfg(notest)] #[lang="str_eq"] +#[inline] pub fn eq_slice(a: &str, b: &str) -> bool { do as_buf(a) |ap, alen| { do as_buf(b) |bp, blen| { @@ -836,6 +838,7 @@ pub fn eq_slice(a: &str, b: &str) -> bool { } #[cfg(test)] +#[inline] pub fn eq_slice(a: &str, b: &str) -> bool { do as_buf(a) |ap, alen| { do as_buf(b) |bp, blen| { @@ -854,15 +857,18 @@ pub fn eq_slice(a: &str, b: &str) -> bool { /// Bytewise string equality #[cfg(notest)] #[lang="uniq_str_eq"] +#[inline] pub fn eq(a: &~str, b: &~str) -> bool { eq_slice(*a, *b) } #[cfg(test)] +#[inline] pub fn eq(a: &~str, b: &~str) -> bool { eq_slice(*a, *b) } +#[inline] fn cmp(a: &str, b: &str) -> Ordering { let low = uint::min(a.len(), b.len()); @@ -879,20 +885,24 @@ fn cmp(a: &str, b: &str) -> Ordering { #[cfg(notest)] impl<'self> TotalOrd for &'self str { + #[inline] fn cmp(&self, other: & &'self str) -> Ordering { cmp(*self, *other) } } #[cfg(notest)] impl TotalOrd for ~str { + #[inline] fn cmp(&self, other: &~str) -> Ordering { cmp(*self, *other) } } #[cfg(notest)] impl TotalOrd for @str { + #[inline] fn cmp(&self, other: &@str) -> Ordering { cmp(*self, *other) } } /// Bytewise slice less than +#[inline] fn lt(a: &str, b: &str) -> bool { let (a_len, b_len) = (a.len(), b.len()); let end = uint::min(a_len, b_len); @@ -909,16 +919,19 @@ fn lt(a: &str, b: &str) -> bool { } /// Bytewise less than or equal +#[inline] pub fn le(a: &str, b: &str) -> bool { !lt(b, a) } /// Bytewise greater than or equal +#[inline] fn ge(a: &str, b: &str) -> bool { !lt(a, b) } /// Bytewise greater than +#[inline] fn gt(a: &str, b: &str) -> bool { !le(a, b) } @@ -1595,6 +1608,7 @@ Section: String properties */ /// Returns true if the string has length 0 +#[inline(always)] pub fn is_empty(s: &str) -> bool { len(s) == 0u } /** @@ -1616,11 +1630,13 @@ fn is_alphanumeric(s: &str) -> bool { } /// Returns the string length/size in bytes not counting the null terminator +#[inline(always)] pub fn len(s: &str) -> uint { do as_buf(s) |_p, n| { n - 1u } } /// Returns the number of characters that a string holds +#[inline(always)] pub fn char_len(s: &str) -> uint { count_chars(s, 0u, len(s)) } /* @@ -1752,7 +1768,8 @@ pub fn count_chars(s: &str, start: uint, end: uint) -> uint { return len; } -/// Counts the number of bytes taken by the `n` in `s` starting from `start`. +/// Counts the number of bytes taken by the first `n` chars in `s` +/// starting from `start`. pub fn count_bytes<'b>(s: &'b str, start: uint, n: uint) -> uint { assert!(is_char_boundary(s, start)); let mut end = start, cnt = n; @@ -1988,6 +2005,7 @@ static tag_six_b: uint = 252u; * let i = str::as_bytes("Hello World") { |bytes| vec::len(bytes) }; * ~~~ */ +#[inline] pub fn as_bytes(s: &const ~str, f: &fn(&~[u8]) -> T) -> T { unsafe { let v: *~[u8] = cast::transmute(copy s); @@ -2023,6 +2041,7 @@ pub fn as_bytes_slice<'a>(s: &'a str) -> &'a [u8] { * let s = str::as_c_str("PATH", { |path| libc::getenv(path) }); * ~~~ */ +#[inline] pub fn as_c_str(s: &str, f: &fn(*libc::c_char) -> T) -> T { do as_buf(s) |buf, len| { // NB: len includes the trailing null. @@ -2099,6 +2118,7 @@ pub fn subslice_offset(outer: &str, inner: &str) -> uint { * * s - A string * * n - The number of bytes to reserve space for */ +#[inline(always)] pub fn reserve(s: &mut ~str, n: uint) { unsafe { let v: *mut ~[u8] = cast::transmute(s); @@ -2126,6 +2146,7 @@ pub fn reserve(s: &mut ~str, n: uint) { * * s - A string * * n - The number of bytes to reserve space for */ +#[inline(always)] pub fn reserve_at_least(s: &mut ~str, n: uint) { reserve(s, uint::next_power_of_two(n + 1u) - 1u) } @@ -2314,6 +2335,7 @@ pub mod raw { } /// Sets the length of the string and adds the null terminator + #[inline] pub unsafe fn set_len(v: &mut ~str, new_len: uint) { let v: **mut vec::raw::VecRepr = cast::transmute(v); let repr: *mut vec::raw::VecRepr = *v; @@ -2489,7 +2511,7 @@ impl<'self> StrSlice<'self> for &'self str { #[inline] fn is_alphanumeric(&self) -> bool { is_alphanumeric(*self) } /// Returns the size in bytes not counting the null terminator - #[inline] + #[inline(always)] fn len(&self) -> uint { len(*self) } /// Returns the number of characters that a string holds #[inline] @@ -2599,10 +2621,11 @@ pub trait OwnedStr { } impl OwnedStr for ~str { + #[inline] fn push_str(&mut self, v: &str) { push_str(self, v); } - + #[inline] fn push_char(&mut self, c: char) { push_char(self, c); } From 5714e2c11b939628247dd0107545e2feb8b74b47 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 2 May 2013 19:24:41 +1000 Subject: [PATCH 137/215] libcore: optimize string joining routines. This makes concat/connect/connect_slices about 20% faster, and takes `repeat` from O(n^2) to O(n), and lowers the constant factor. --- src/libcore/str.rs | 118 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 106 insertions(+), 12 deletions(-) diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 1ddebf8332069..f3181b26bd7e0 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -241,38 +241,132 @@ pub fn append(lhs: ~str, rhs: &str) -> ~str { /// Concatenate a vector of strings pub fn concat(v: &[~str]) -> ~str { - let mut s: ~str = ~""; - for vec::each(v) |ss| { - push_str(&mut s, *ss); + if v.is_empty() { return ~""; } + + let mut len = 0; + for v.each |ss| { + len += ss.len(); + } + let mut s = ~""; + + reserve(&mut s, len); + + unsafe { + do as_buf(s) |buf, _len| { + let mut buf = ::cast::transmute_mut_unsafe(buf); + for v.each |ss| { + do as_buf(*ss) |ssbuf, sslen| { + let sslen = sslen - 1; + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen); + } + } + } + raw::set_len(&mut s, len); } s } /// Concatenate a vector of strings, placing a given separator between each pub fn connect(v: &[~str], sep: &str) -> ~str { + if v.is_empty() { return ~""; } + + // concat is faster + if sep.is_empty() { return concat(v); } + + // this is wrong without the guarantee that v is non-empty + let mut len = sep.len() * (v.len() - 1); + for v.each |ss| { + len += ss.len(); + } let mut s = ~"", first = true; - for vec::each(v) |ss| { - if first { first = false; } else { push_str(&mut s, sep); } - push_str(&mut s, *ss); + + reserve(&mut s, len); + + unsafe { + do as_buf(s) |buf, _len| { + do as_buf(sep) |sepbuf, seplen| { + let seplen = seplen - 1; + let mut buf = ::cast::transmute_mut_unsafe(buf); + for v.each |ss| { + do as_buf(*ss) |ssbuf, sslen| { + let sslen = sslen - 1; + if first { + first = false; + } else { + ptr::copy_memory(buf, sepbuf, seplen); + buf = buf.offset(seplen); + } + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen); + } + } + } + } + raw::set_len(&mut s, len); } s } /// Concatenate a vector of strings, placing a given separator between each pub fn connect_slices(v: &[&str], sep: &str) -> ~str { + if v.is_empty() { return ~""; } + + // this is wrong without the guarantee that v is non-empty + let mut len = sep.len() * (v.len() - 1); + for v.each |ss| { + len += ss.len(); + } let mut s = ~"", first = true; - for vec::each(v) |ss| { - if first { first = false; } else { push_str(&mut s, sep); } - push_str(&mut s, *ss); + + reserve(&mut s, len); + + unsafe { + do as_buf(s) |buf, _len| { + do as_buf(sep) |sepbuf, seplen| { + let seplen = seplen - 1; + let mut buf = ::cast::transmute_mut_unsafe(buf); + for vec::each(v) |ss| { + do as_buf(*ss) |ssbuf, sslen| { + let sslen = sslen - 1; + if first { + first = false; + } else if seplen > 0 { + ptr::copy_memory(buf, sepbuf, seplen); + buf = buf.offset(seplen); + } + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen); + } + } + } + } + raw::set_len(&mut s, len); } s } /// Given a string, make a new string with repeated copies of it pub fn repeat(ss: &str, nn: uint) -> ~str { - let mut acc = ~""; - for nn.times { acc += ss; } - acc + do as_buf(ss) |buf, len| { + let mut ret = ~""; + // ignore the NULL terminator + let len = len - 1; + reserve(&mut ret, nn * len); + + unsafe { + do as_buf(ret) |rbuf, _len| { + let mut rbuf = ::cast::transmute_mut_unsafe(rbuf); + + for nn.times { + ptr::copy_memory(rbuf, buf, len); + rbuf = rbuf.offset(len); + } + } + raw::set_len(&mut ret, nn * len); + } + ret + } } /* From 6487cb221bcf7820a9d8458f18080c8f3ef1c2dc Mon Sep 17 00:00:00 2001 From: kud1ing Date: Thu, 2 May 2013 13:37:57 +0300 Subject: [PATCH 138/215] Explain that the source code was generated by this script --- src/etc/unicode.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/etc/unicode.py b/src/etc/unicode.py index 864cf3daee07e..afb3d16848085 100755 --- a/src/etc/unicode.py +++ b/src/etc/unicode.py @@ -235,6 +235,10 @@ def emit_decomp_module(f, canon, compat): rf = open(r, "w") (canon_decomp, compat_decomp, gencats) = load_unicode_data("UnicodeData.txt") + +# Explain that the source code was generated by this script. +rf.write('// The following code was generated by "src/etc/unicode.py"\n\n') + emit_property_module(rf, "general_category", gencats) #emit_decomp_module(rf, canon_decomp, compat_decomp) From 18c46b8fd4029bdcc2836298cca2df05b5c5f314 Mon Sep 17 00:00:00 2001 From: kud1ing Date: Thu, 2 May 2013 13:38:39 +0300 Subject: [PATCH 139/215] The following code was generated by "src/etc/unicode.py" --- src/libcore/unicode.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/unicode.rs b/src/libcore/unicode.rs index a13d66c48ee0c..34175f9888ffa 100644 --- a/src/libcore/unicode.rs +++ b/src/libcore/unicode.rs @@ -10,6 +10,8 @@ #[doc(hidden)]; // FIXME #3538 +// The following code was generated by "src/etc/unicode.py" + pub mod general_category { fn bsearch_range_table(c: char, r: &'static [(char,char)]) -> bool { From cff6aba76ea01888854a87bdd4c1f71aada8d250 Mon Sep 17 00:00:00 2001 From: gifnksm Date: Thu, 2 May 2013 20:20:22 +0900 Subject: [PATCH 140/215] libcore: Export core::from_str::FromStr from core::prelude --- src/libcore/bool.rs | 1 + src/libcore/cast.rs | 2 ++ src/libcore/core.rc | 1 + src/libcore/flate.rs | 1 - src/libcore/num/f32.rs | 3 +-- src/libcore/num/f64.rs | 3 +-- src/libcore/num/float.rs | 3 +-- src/libcore/num/int-template.rs | 1 - src/libcore/num/uint-template.rs | 1 - src/libcore/pipes.rs | 6 +++--- src/libcore/prelude.rs | 1 + src/libstd/net_url.rs | 8 +++----- src/libstd/num/bigint.rs | 5 ++--- 13 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/libcore/bool.rs b/src/libcore/bool.rs index 6c60cec2595ef..1b5855049ca61 100644 --- a/src/libcore/bool.rs +++ b/src/libcore/bool.rs @@ -108,6 +108,7 @@ mod tests { #[test] fn test_bool_from_str() { + #[cfg(stage0)] use from_str::FromStr; do all_values |v| { diff --git a/src/libcore/cast.rs b/src/libcore/cast.rs index 6fb737d37709f..22f31d52d2d54 100644 --- a/src/libcore/cast.rs +++ b/src/libcore/cast.rs @@ -10,7 +10,9 @@ //! Unsafe casting functions +#[cfg(not(stage0))] use sys; +#[cfg(not(stage0))] use unstable; pub mod rusti { diff --git a/src/libcore/core.rc b/src/libcore/core.rc index f410591fdc7a3..d8cca429f8447 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -111,6 +111,7 @@ pub use num::{Bitwise, BitCount, Bounded}; pub use num::{Primitive, Int, Float}; pub use ptr::Ptr; +pub use from_str::FromStr; pub use to_str::ToStr; pub use clone::Clone; diff --git a/src/libcore/flate.rs b/src/libcore/flate.rs index c3518cc8b6ee2..c18273955adab 100644 --- a/src/libcore/flate.rs +++ b/src/libcore/flate.rs @@ -16,7 +16,6 @@ Simple compression use libc; use libc::{c_void, size_t, c_int}; -use ptr; use vec; #[cfg(test)] use rand; diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index a00225e85bc49..1b4c679ea07b4 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -10,7 +10,6 @@ //! Operations and constants for `f32` -use from_str; use num::{Zero, One, strconv}; use prelude::*; @@ -798,7 +797,7 @@ pub fn from_str_radix(num: &str, rdx: uint) -> Option { strconv::ExpNone, false, false) } -impl from_str::FromStr for f32 { +impl FromStr for f32 { #[inline(always)] fn from_str(val: &str) -> Option { from_str(val) } } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index c3bd89b0e0361..0f7647fa8680d 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -10,7 +10,6 @@ //! Operations and constants for `f64` -use from_str; use libc::c_int; use num::{Zero, One, strconv}; use prelude::*; @@ -840,7 +839,7 @@ pub fn from_str_radix(num: &str, rdx: uint) -> Option { strconv::ExpNone, false, false) } -impl from_str::FromStr for f64 { +impl FromStr for f64 { #[inline(always)] fn from_str(val: &str) -> Option { from_str(val) } } diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index b487fa48782b8..16bb2aa128651 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -20,7 +20,6 @@ // PORT this must match in width according to architecture -use from_str; use libc::c_int; use num::{Zero, One, strconv}; use prelude::*; @@ -289,7 +288,7 @@ pub fn from_str_radix(num: &str, radix: uint) -> Option { strconv::ExpNone, false, false) } -impl from_str::FromStr for float { +impl FromStr for float { #[inline(always)] fn from_str(val: &str) -> Option { from_str(val) } } diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index fadba84a0fe93..090e0256abf6e 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -10,7 +10,6 @@ use T = self::inst::T; -use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::{Zero, One, strconv}; use prelude::*; diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index f6b98989545d0..379c1834543d2 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -11,7 +11,6 @@ use T = self::inst::T; use T_SIGNED = self::inst::T_SIGNED; -use from_str::FromStr; use num::{ToStrRadix, FromStrRadix}; use num::{Zero, One, strconv}; use prelude::*; diff --git a/src/libcore/pipes.rs b/src/libcore/pipes.rs index 145997fcb4bd5..19674900f908e 100644 --- a/src/libcore/pipes.rs +++ b/src/libcore/pipes.rs @@ -303,7 +303,7 @@ struct BufferResource { } #[unsafe_destructor] -impl ::ops::Drop for BufferResource { +impl Drop for BufferResource { fn finalize(&self) { unsafe { let b = move_it!(self.buffer); @@ -639,7 +639,7 @@ pub struct SendPacketBuffered { } #[unsafe_destructor] -impl ::ops::Drop for SendPacketBuffered { +impl Drop for SendPacketBuffered { fn finalize(&self) { //if self.p != none { // debug!("drop send %?", option::get(self.p)); @@ -708,7 +708,7 @@ pub struct RecvPacketBuffered { } #[unsafe_destructor] -impl ::ops::Drop for RecvPacketBuffered { +impl Drop for RecvPacketBuffered { fn finalize(&self) { //if self.p != none { // debug!("drop recv %?", option::get(self.p)); diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 4527fcf2923da..e3c57097471f2 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -51,6 +51,7 @@ pub use path::WindowsPath; pub use ptr::Ptr; pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr}; pub use str::{StrSlice, OwnedStr}; +pub use from_str::{FromStr}; pub use to_bytes::IterBytes; pub use to_str::{ToStr, ToStrConsume}; pub use tuple::{CopyableTuple, ImmutableTuple, ExtendedTupleOps}; diff --git a/src/libstd/net_url.rs b/src/libstd/net_url.rs index f3b11c132798c..fa872ffee87e6 100644 --- a/src/libstd/net_url.rs +++ b/src/libstd/net_url.rs @@ -13,15 +13,13 @@ #[allow(deprecated_mode)]; use core::cmp::Eq; +#[cfg(stage0)] use core::from_str::FromStr; use core::io::{Reader, ReaderUtil}; use core::io; use core::hashmap::HashMap; use core::str; -use core::to_bytes::IterBytes; use core::to_bytes; -use core::to_str::ToStr; -use core::to_str; use core::uint; #[deriving(Clone, Eq)] @@ -703,13 +701,13 @@ pub fn to_str(url: &Url) -> ~str { fmt!("%s:%s%s%s%s", url.scheme, authority, url.path, query, fragment) } -impl to_str::ToStr for Url { +impl ToStr for Url { pub fn to_str(&self) -> ~str { to_str(self) } } -impl to_bytes::IterBytes for Url { +impl IterBytes for Url { fn iter_bytes(&self, lsb0: bool, f: to_bytes::Cb) { self.to_str().iter_bytes(lsb0, f) } diff --git a/src/libstd/num/bigint.rs b/src/libstd/num/bigint.rs index e2a336027fdef..497ce7f41aae3 100644 --- a/src/libstd/num/bigint.rs +++ b/src/libstd/num/bigint.rs @@ -21,7 +21,6 @@ A BigInt is a combination of BigUint and Sign. use core::cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; use core::num::{IntConvertible, Zero, One, ToStrRadix, FromStrRadix}; -use core::*; /** A BigDigit is a BigUint's composing element. @@ -141,7 +140,7 @@ impl ToStr for BigUint { fn to_str(&self) -> ~str { self.to_str_radix(10) } } -impl from_str::FromStr for BigUint { +impl FromStr for BigUint { #[inline(always)] fn from_str(s: &str) -> Option { FromStrRadix::from_str_radix(s, 10) @@ -785,7 +784,7 @@ impl ToStr for BigInt { fn to_str(&self) -> ~str { self.to_str_radix(10) } } -impl from_str::FromStr for BigInt { +impl FromStr for BigInt { #[inline(always)] fn from_str(s: &str) -> Option { FromStrRadix::from_str_radix(s, 10) From 6883814a84d584e1fd65a1d40229807ff3d34efb Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Thu, 2 May 2013 21:56:20 +0900 Subject: [PATCH 141/215] Remove codes related to modes --- src/librustc/middle/ty.rs | 78 --------------------------------------- 1 file changed, 78 deletions(-) diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 3c8f100d1c933..6cb042efa793e 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1818,15 +1818,6 @@ pub impl TypeContents { if cx.vecs_implicitly_copyable {base} else {base + TC_OWNED_VEC} } - fn is_safe_for_default_mode(&self, cx: ctxt) -> bool { - !self.intersects(TypeContents::nondefault_mode(cx)) - } - - fn nondefault_mode(cx: ctxt) -> TypeContents { - let tc = TypeContents::nonimplicitly_copyable(cx); - tc + TC_BIG + TC_OWNED_VEC // disregard cx.vecs_implicitly_copyable - } - fn needs_drop(&self, cx: ctxt) -> bool { let tc = TC_MANAGED + TC_DTOR + TypeContents::owned(cx); self.intersects(tc) @@ -1886,9 +1877,6 @@ static TC_MUTABLE: TypeContents = TypeContents{bits:0b000010000000}; /// Mutable content, whether owned or by ref static TC_ONCE_CLOSURE: TypeContents = TypeContents{bits:0b000100000000}; -/// Something we estimate to be "big" -static TC_BIG: TypeContents = TypeContents{bits:0b001000000000}; - /// An enum with no variants. static TC_EMPTY_ENUM: TypeContents = TypeContents{bits:0b010000000000}; @@ -2109,10 +2097,6 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { } }; - if type_size(cx, ty) > 4 { - result = result + TC_BIG; - } - cache.insert(ty_id, result); return result; } @@ -2188,68 +2172,6 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { debug!("result = %s", r.to_str()); return r; } - - /// gives a rough estimate of how much space it takes to represent - /// an instance of `ty`. Used for the mode transition. - fn type_size(cx: ctxt, ty: t) -> uint { - match get(ty).sty { - ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | - ty_ptr(_) | ty_box(_) | ty_uniq(_) | ty_estr(vstore_uniq) | - ty_trait(*) | ty_rptr(*) | ty_evec(_, vstore_uniq) | - ty_evec(_, vstore_box) | ty_estr(vstore_box) => { - 1 - } - - ty_evec(_, vstore_slice(_)) | - ty_estr(vstore_slice(_)) | - ty_bare_fn(*) | - ty_closure(*) => { - 2 - } - - ty_evec(t, vstore_fixed(n)) => { - type_size(cx, t.ty) * n - } - - ty_estr(vstore_fixed(n)) => { - n - } - - ty_struct(did, ref substs) => { - let flds = struct_fields(cx, did, substs); - flds.foldl(0, |s, f| *s + type_size(cx, f.mt.ty)) - } - - ty_tup(ref tys) => { - tys.foldl(0, |s, t| *s + type_size(cx, *t)) - } - - ty_enum(did, ref substs) => { - let variants = substd_enum_variants(cx, did, substs); - variants.foldl( // find max size of any variant - 0, - |m, v| uint::max( - *m, - // find size of this variant: - v.args.foldl(0, |s, a| *s + type_size(cx, *a)))) - } - - ty_param(_) | ty_self(_) => { - 1 - } - - ty_infer(_) => { - cx.sess.bug(~"Asked to compute kind of a type variable"); - } - ty_type => 1, - ty_opaque_closure_ptr(_) => 1, - ty_opaque_box => 1, - ty_unboxed_vec(_) => 10, - ty_err => { - cx.sess.bug(~"Asked to compute kind of fictitious type"); - } - } - } } pub fn type_moves_by_default(cx: ctxt, ty: t) -> bool { From 35b91e2f73cec610af4a2a653389562ad7cbc85e Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 3 May 2013 01:28:53 +0900 Subject: [PATCH 142/215] Use static strings --- src/librustc/middle/borrowck/loan.rs | 6 +- src/librustc/middle/borrowck/mod.rs | 4 +- src/librustc/middle/borrowck/preserve.rs | 2 +- src/librustc/middle/trans/_match.rs | 3 +- src/librustc/middle/trans/base.rs | 9 +- src/librustc/middle/trans/callee.rs | 4 +- src/librustc/middle/trans/consts.rs | 35 +++---- src/librustc/middle/trans/datum.rs | 4 +- src/librustc/middle/trans/debuginfo.rs | 23 ++--- src/librustc/middle/trans/expr.rs | 11 +-- src/librustc/middle/trans/foreign.rs | 2 +- src/librustc/middle/trans/monomorphize.rs | 2 +- src/librustc/middle/trans/reachable.rs | 10 +- src/librustc/middle/trans/tvec.rs | 4 +- src/librustc/middle/typeck/astconv.rs | 31 +++---- src/librustc/middle/typeck/check/_match.rs | 37 ++++---- src/librustc/middle/typeck/check/method.rs | 14 +-- src/librustc/middle/typeck/check/mod.rs | 92 +++++++++---------- src/librustc/middle/typeck/check/regionck.rs | 18 ++-- src/librustc/middle/typeck/check/vtable.rs | 2 +- src/librustc/middle/typeck/coherence.rs | 52 ++++------- src/librustc/middle/typeck/collect.rs | 5 +- .../middle/typeck/infer/region_inference.rs | 8 +- src/librustc/middle/typeck/mod.rs | 8 +- src/libsyntax/ext/base.rs | 2 +- src/libsyntax/parse/parser.rs | 69 +++++++------- 26 files changed, 201 insertions(+), 256 deletions(-) diff --git a/src/librustc/middle/borrowck/loan.rs b/src/librustc/middle/borrowck/loan.rs index 21de29b8f60ad..4dd727390aadc 100644 --- a/src/librustc/middle/borrowck/loan.rs +++ b/src/librustc/middle/borrowck/loan.rs @@ -115,7 +115,7 @@ pub impl LoanContext { if cmt.lp.is_none() { self.bccx.tcx.sess.span_bug( cmt.span, - ~"loan() called with non-lendable value"); + "loan() called with non-lendable value"); } match cmt.cat { @@ -123,7 +123,7 @@ pub impl LoanContext { // should never be loanable self.bccx.tcx.sess.span_bug( cmt.span, - ~"rvalue with a non-none lp"); + "rvalue with a non-none lp"); } cat_local(local_id) | cat_arg(local_id) | cat_self(local_id) => { // FIXME(#4903) @@ -188,7 +188,7 @@ pub impl LoanContext { // Aliased data is simply not lendable. self.bccx.tcx.sess.span_bug( cmt.span, - ~"aliased ptr with a non-none lp"); + "aliased ptr with a non-none lp"); } } } diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 3746f9c6e60b1..f1d45e6e9aaa7 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -525,11 +525,11 @@ pub impl BorrowckCtxt { self.note_and_explain_bckerr(err); } - fn span_err(&self, s: span, m: ~str) { + fn span_err(&self, s: span, m: &str) { self.tcx.sess.span_err(s, m); } - fn span_note(&self, s: span, m: ~str) { + fn span_note(&self, s: span, m: &str) { self.tcx.sess.span_note(s, m); } diff --git a/src/librustc/middle/borrowck/preserve.rs b/src/librustc/middle/borrowck/preserve.rs index c44920fffa568..62358823f2322 100644 --- a/src/librustc/middle/borrowck/preserve.rs +++ b/src/librustc/middle/borrowck/preserve.rs @@ -124,7 +124,7 @@ pub impl<'self> PreserveCtxt<'self> { if self.root_managed_data { self.tcx().sess.span_bug( cmt.span, - ~"preserve() called with local and !root_managed_data"); + "preserve() called with local and !root_managed_data"); } let local_region = self.tcx().region_maps.encl_region(local_id); self.compare_scope(cmt, local_region) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 197b537fe9003..3bd2a8269b763 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -557,8 +557,7 @@ pub fn enter_opt<'r>(bcx: block, struct_id = found_struct_id; } _ => { - tcx.sess.span_bug(p.span, ~"expected enum \ - variant def"); + tcx.sess.span_bug(p.span, "expected enum variant def"); } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 0c3e3ba3cb672..87e347d200408 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1125,10 +1125,11 @@ pub fn init_local(bcx: block, local: @ast::local) -> block { } let llptr = match bcx.fcx.lllocals.find(&local.node.id) { - Some(&local_mem(v)) => v, - _ => { bcx.tcx().sess.span_bug(local.span, - ~"init_local: Someone forgot to document why it's\ - safe to assume local.node.init must be local_mem!"); + Some(&local_mem(v)) => v, + _ => { + bcx.tcx().sess.span_bug(local.span, + "init_local: Someone forgot to document why it's\ + safe to assume local.node.init must be local_mem!"); } }; diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index ad0fea3b4b4af..ed7f91bf04a6b 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -356,9 +356,7 @@ pub fn trans_method_call(in_cx: block, origin) } None => { - cx.tcx().sess.span_bug(call_ex.span, - ~"method call expr wasn't in \ - method map") + cx.tcx().sess.span_bug(call_ex.span, "method call expr wasn't in method map") } } }, diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index c6c5561854c0d..9d04905bcc978 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -58,8 +58,7 @@ pub fn const_lit(cx: @CrateContext, e: @ast::expr, lit: ast::lit) } _ => { cx.sess.span_bug(lit.span, - ~"floating point literal doesn't have the right \ - type"); + "floating point literal doesn't have the right type"); } } } @@ -281,7 +280,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { else { llvm::LLVMConstURem(te1, te2) } } ast::and | - ast::or => cx.sess.span_unimpl(e.span, ~"binop logic"), + ast::or => cx.sess.span_unimpl(e.span, "binop logic"), ast::bitxor => llvm::LLVMConstXor(te1, te2), ast::bitand => llvm::LLVMConstAnd(te1, te2), ast::bitor => llvm::LLVMConstOr(te1, te2), @@ -295,7 +294,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { ast::le | ast::ne | ast::ge | - ast::gt => cx.sess.span_unimpl(e.span, ~"binop comparator") + ast::gt => cx.sess.span_unimpl(e.span, "binop comparator") } } ast::expr_unary(u, e) => { @@ -344,8 +343,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { const_eval::const_int(i) => i as u64, const_eval::const_uint(u) => u, _ => cx.sess.span_bug(index.span, - ~"index is not an integer-constant \ - expression") + "index is not an integer-constant expression") }; let (arr, len) = match ty::get(bt).sty { ty::ty_evec(_, vstore) | ty::ty_estr(vstore) => @@ -363,12 +361,10 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { unit_sz)) }, _ => cx.sess.span_bug(base.span, - ~"index-expr base must be \ - fixed-size or slice") + "index-expr base must be fixed-size or slice") }, _ => cx.sess.span_bug(base.span, - ~"index-expr base must be \ - a vector or string type") + "index-expr base must be a vector or string type") }; let len = llvm::LLVMConstIntGetZExtValue(len) as u64; @@ -380,7 +376,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { // FIXME #3170: report this earlier on in the const-eval // pass. Reporting here is a bit late. cx.sess.span_err(e.span, - ~"const index-expr is out of bounds"); + "const index-expr is out of bounds"); } const_get_elt(cx, arr, [iv as c_uint]) } @@ -454,8 +450,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { match fs.find(|f| field_ty.ident == f.node.ident) { Some(ref f) => const_expr(cx, (*f).node.expr), None => { - cx.tcx.sess.span_bug( - e.span, ~"missing struct field"); + cx.tcx.sess.span_bug(e.span, "missing struct field"); } } }); @@ -471,8 +466,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { ast::expr_lit(ref lit) => { match lit.node { ast::lit_str(*) => { const_expr(cx, sub) } - _ => { cx.sess.span_bug(e.span, - ~"bad const-slice lit") } + _ => { cx.sess.span_bug(e.span, "bad const-slice lit") } } } ast::expr_vec(ref es, ast::m_imm) => { @@ -487,8 +481,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { let p = const_ptrcast(cx, gv, llunitty); C_struct(~[p, sz]) } - _ => cx.sess.span_bug(e.span, - ~"bad const-slice expr") + _ => cx.sess.span_bug(e.span, "bad const-slice expr") } } ast::expr_path(pth) => { @@ -520,8 +513,7 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { C_null(llty) } _ => { - cx.sess.span_bug(e.span, ~"expected a const, fn, \ - struct, or variant def") + cx.sess.span_bug(e.span, "expected a const, fn, struct, or variant def") } } } @@ -542,13 +534,12 @@ fn const_expr_unadjusted(cx: @CrateContext, e: @ast::expr) -> ValueRef { adt::trans_const(cx, repr, vinfo.disr_val, args.map(|a| const_expr(cx, *a))) } - _ => cx.sess.span_bug(e.span, ~"expected a struct or \ - variant def") + _ => cx.sess.span_bug(e.span, "expected a struct or variant def") } } ast::expr_paren(e) => { return const_expr(cx, e); } _ => cx.sess.span_bug(e.span, - ~"bad constant expression type in consts::const_expr") + "bad constant expression type in consts::const_expr") }; } } diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index fa27f652ac880..cf5fbb6e216ec 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -761,8 +761,8 @@ pub impl Datum { match self.try_deref(bcx, expr.id, derefs, false) { (Some(lvres), bcx) => DatumBlock { bcx: bcx, datum: lvres }, (None, _) => { - bcx.ccx().sess.span_bug( - expr.span, ~"Cannot deref this expression"); + bcx.ccx().sess.span_bug(expr.span, + "Cannot deref this expression"); } } } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 58fc5ea3be647..b7a1a90741c43 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -756,7 +756,7 @@ fn create_ty(cx: @CrateContext, t: ty::t, span: span) } }, ty::ty_enum(_did, ref _substs) => { - cx.sess.span_bug(span, ~"debuginfo for enum NYI") + cx.sess.span_bug(span, "debuginfo for enum NYI") } ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => { let boxed = create_ty(cx, mt.ty, span); @@ -782,7 +782,7 @@ fn create_ty(cx: @CrateContext, t: ty::t, span: span) create_pointer_type(cx, t, span, pointee) }, ty::ty_rptr(ref _region, ref _mt) => { - cx.sess.span_bug(span, ~"debuginfo for rptr NYI") + cx.sess.span_bug(span, "debuginfo for rptr NYI") }, ty::ty_bare_fn(ref barefnty) => { let inputs = do barefnty.sig.inputs.map |a| { a.ty }; @@ -790,10 +790,10 @@ fn create_ty(cx: @CrateContext, t: ty::t, span: span) create_fn_ty(cx, t, inputs, output, span) }, ty::ty_closure(ref _closurety) => { - cx.sess.span_bug(span, ~"debuginfo for closure NYI") + cx.sess.span_bug(span, "debuginfo for closure NYI") }, ty::ty_trait(_did, ref _substs, ref _vstore, _) => { - cx.sess.span_bug(span, ~"debuginfo for trait NYI") + cx.sess.span_bug(span, "debuginfo for trait NYI") }, ty::ty_struct(did, ref substs) => { let fields = ty::struct_fields(cx.tcx, did, substs); @@ -860,14 +860,12 @@ pub fn create_local_var(bcx: block, local: @ast::local) let llptr = match bcx.fcx.lllocals.find(&local.node.id) { option::Some(&local_mem(v)) => v, option::Some(_) => { - bcx.tcx().sess.span_bug(local.span, ~"local is bound to \ - something weird"); + bcx.tcx().sess.span_bug(local.span, "local is bound to something weird"); } option::None => { match *bcx.fcx.lllocals.get(&local.node.pat.id) { local_imm(v) => v, - _ => bcx.tcx().sess.span_bug(local.span, ~"local is bound to \ - something weird") + _ => bcx.tcx().sess.span_bug(local.span, "local is bound to something weird") } } }; @@ -966,8 +964,7 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata { ast::item_fn(ref decl, _, _, _, _) => { (item.ident, decl.output, item.id) } - _ => fcx.ccx.sess.span_bug(item.span, ~"create_function: item \ - bound to non-function") + _ => fcx.ccx.sess.span_bug(item.span, "create_function: item bound to non-function") } } ast_map::node_method(method, _, _) => { @@ -979,12 +976,10 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata { ((dbg_cx.names)(~"fn"), decl.output, expr.id) } _ => fcx.ccx.sess.span_bug(expr.span, - ~"create_function: \ - expected an expr_fn_block here") + "create_function: expected an expr_fn_block here") } } - _ => fcx.ccx.sess.bug(~"create_function: unexpected \ - sort of node") + _ => fcx.ccx.sess.bug("create_function: unexpected sort of node") }; debug!("%?", ident); diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index ae510ae6d114f..7cdd7c3799ec4 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -690,7 +690,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, } _ => { bcx.tcx().sess.span_bug(expr.span, - ~"expr_cast of non-trait"); + "expr_cast of non-trait"); } } } @@ -700,8 +700,7 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr, _ => { bcx.tcx().sess.span_bug( expr.span, - fmt!("trans_rvalue_dps_unadjusted reached \ - fall-through case: %?", + fmt!("trans_rvalue_dps_unadjusted reached fall-through case: %?", expr.node)); } } @@ -1202,7 +1201,7 @@ fn trans_rec_or_struct(bcx: block, } None => { tcx.sess.span_bug(field.span, - ~"Couldn't find field in struct type") + "Couldn't find field in struct type") } } }; @@ -1478,7 +1477,7 @@ fn trans_eager_binop(bcx: block, } else { if !ty::type_is_scalar(rhs_t) { bcx.tcx().sess.span_bug(binop_expr.span, - ~"non-scalar comparison"); + "non-scalar comparison"); } let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op); bcx = cmpr.bcx; @@ -1486,7 +1485,7 @@ fn trans_eager_binop(bcx: block, } } _ => { - bcx.tcx().sess.span_bug(binop_expr.span, ~"unexpected binop"); + bcx.tcx().sess.span_bug(binop_expr.span, "unexpected binop"); } }; diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index c45ba64c58470..0e2bf80cc5e84 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -1080,7 +1080,7 @@ pub fn trans_intrinsic(ccx: @CrateContext, _ => { // Could we make this an enum rather than a string? does it get // checked earlier? - ccx.sess.span_bug(item.span, ~"unknown intrinsic"); + ccx.sess.span_bug(item.span, "unknown intrinsic"); } } build_return(bcx); diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index aa49915d1759b..2640dab1c04fb 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -160,7 +160,7 @@ pub fn monomorphic_fn(ccx: @CrateContext, // causing an infinite expansion. if depth > 30 { ccx.sess.span_fatal( - span, ~"overly deep expansion of inlined function"); + span, "overly deep expansion of inlined function"); } ccx.monomorphizing.insert(fn_id, depth + 1); diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs index 234473dd35b60..f301a7d297342 100644 --- a/src/librustc/middle/trans/reachable.rs +++ b/src/librustc/middle/trans/reachable.rs @@ -170,11 +170,13 @@ fn traverse_inline_body(cx: &ctx, body: &blk) { expr_path(_) => { match cx.tcx.def_map.find(&e.id) { Some(&d) => { - traverse_def_id(cx, def_id_of_def(d)); + traverse_def_id(cx, def_id_of_def(d)); } - None => cx.tcx.sess.span_bug(e.span, fmt!("Unbound node \ - id %? while traversing %s", e.id, - expr_to_str(e, cx.tcx.sess.intr()))) + None => cx.tcx.sess.span_bug( + e.span, + fmt!("Unbound node id %? while traversing %s", + e.id, + expr_to_str(e, cx.tcx.sess.intr()))) } } expr_field(_, _, _) => { diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index da1cdfa4db103..e8075c1f2ad1d 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -469,7 +469,7 @@ pub fn write_content(bcx: block, } _ => { bcx.tcx().sess.span_bug(content_expr.span, - ~"Unexpected evec content"); + "Unexpected evec content"); } } } @@ -503,7 +503,7 @@ pub fn elements_required(bcx: block, content_expr: @ast::expr) -> uint { ty::eval_repeat_count(bcx.tcx(), count_expr) } _ => bcx.tcx().sess.span_bug(content_expr.span, - ~"Unexpected evec content") + "Unexpected evec content") } } diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index ffaa6d46d3379..7ef77646f5203 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -291,10 +291,8 @@ pub fn ast_ty_to_ty( ty::vstore_fixed(*) => { tcx.sess.span_err( path.span, - ~"@trait, ~trait or &trait \ - are the only supported \ - forms of casting-to-\ - trait"); + "@trait, ~trait or &trait are the only supported \ + forms of casting-to-trait"); ty::BoxTraitStore } }; @@ -321,7 +319,7 @@ pub fn ast_ty_to_ty( if path.types.len() > 0u { tcx.sess.span_err( path.span, - ~"type parameters are not allowed on this type"); + "type parameters are not allowed on this type"); } } @@ -329,7 +327,7 @@ pub fn ast_ty_to_ty( if path.rp.is_some() { tcx.sess.span_err( path.span, - ~"region parameters are not allowed on this type"); + "region parameters are not allowed on this type"); } } } @@ -339,9 +337,8 @@ pub fn ast_ty_to_ty( match tcx.ast_ty_to_ty_cache.find(&ast_ty.id) { Some(&ty::atttce_resolved(ty)) => return ty, Some(&ty::atttce_unresolved) => { - tcx.sess.span_fatal(ast_ty.span, ~"illegal recursive type; \ - insert an enum in the cycle, \ - if this is desired"); + tcx.sess.span_fatal(ast_ty.span, "illegal recursive type; \ + insert an enum in the cycle, if this is desired"); } None => { /* go on */ } } @@ -359,11 +356,9 @@ pub fn ast_ty_to_ty( |tmt| ty::mk_uniq(tcx, tmt)) } ast::ty_vec(ref mt) => { - tcx.sess.span_err(ast_ty.span, - ~"bare `[]` is not a type"); + tcx.sess.span_err(ast_ty.span, "bare `[]` is not a type"); // return /something/ so they can at least get more errors - ty::mk_evec(tcx, ast_mt_to_mt(self, rscope, mt), - ty::vstore_uniq) + ty::mk_evec(tcx, ast_mt_to_mt(self, rscope, mt), ty::vstore_uniq) } ast::ty_ptr(ref mt) => { ty::mk_ptr(tcx, ast_mt_to_mt(self, rscope, mt)) @@ -434,7 +429,7 @@ pub fn ast_ty_to_ty( } ast::ty_str => { tcx.sess.span_err(ast_ty.span, - ~"bare `str` is not a type"); + "bare `str` is not a type"); // return /something/ so they can at least get more errors ty::mk_estr(tcx, ty::vstore_uniq) } @@ -454,7 +449,7 @@ pub fn ast_ty_to_ty( } _ => { tcx.sess.span_fatal(ast_ty.span, - ~"found type name used as a variable"); + "found type name used as a variable"); } } } @@ -470,7 +465,7 @@ pub fn ast_ty_to_ty( ty::vstore_fixed(i as uint)), _ => { tcx.sess.span_fatal( - ast_ty.span, ~"expected constant expr for vector length"); + ast_ty.span, "expected constant expr for vector length"); } } } @@ -489,11 +484,11 @@ pub fn ast_ty_to_ty( // routine. self.tcx().sess.span_bug( ast_ty.span, - ~"found `ty_infer` in unexpected place"); + "found `ty_infer` in unexpected place"); } ast::ty_mac(_) => { tcx.sess.span_bug(ast_ty.span, - ~"found `ty_mac` in unexpected place"); + "found `ty_mac` in unexpected place"); } }; diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 5ff7105712183..de384d02dc3bc 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -204,8 +204,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, if arg_len > 0 { // N-ary variant. if arg_len != subpats_len { - let s = fmt!("this pattern has %u field%s, but the corresponding \ - %s has %u field%s", + let s = fmt!("this pattern has %u field%s, but the corresponding %s has %u field%s", subpats_len, if subpats_len == 1u { ~"" } else { ~"s" }, kind_name, @@ -223,13 +222,12 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, } } } else if subpats_len > 0 { - tcx.sess.span_err - (pat.span, fmt!("this pattern has %u field%s, but the \ - corresponding %s has no fields", - subpats_len, - if subpats_len == 1u { ~"" } - else { ~"s" }, - kind_name)); + tcx.sess.span_err(pat.span, + fmt!("this pattern has %u field%s, but the corresponding %s has no \ + fields", + subpats_len, + if subpats_len == 1u { "" } else { "s" }, + kind_name)); error_happened = true; } @@ -319,20 +317,19 @@ pub fn check_struct_pat(pcx: &pat_ctxt, pat_id: ast::node_id, span: span, Some(&ast::def_struct(*)) | Some(&ast::def_variant(*)) => { let name = pprust::path_to_str(path, tcx.sess.intr()); tcx.sess.span_err(span, - fmt!("mismatched types: expected `%s` but \ - found `%s`", + fmt!("mismatched types: expected `%s` but found `%s`", fcx.infcx().ty_to_str(expected), name)); } _ => { - tcx.sess.span_bug(span, ~"resolve didn't write in class"); + tcx.sess.span_bug(span, "resolve didn't write in class"); } } // Forbid pattern-matching structs with destructors. if ty::has_dtor(tcx, class_id) { - tcx.sess.span_err(span, ~"deconstructing struct not allowed in \ - pattern (it has a destructor)"); + tcx.sess.span_err(span, "deconstructing struct not allowed in pattern \ + (it has a destructor)"); } check_struct_pat_fields(pcx, span, path, fields, class_fields, class_id, @@ -370,7 +367,7 @@ pub fn check_struct_like_enum_variant_pat(pcx: &pat_ctxt, name)); } _ => { - tcx.sess.span_bug(span, ~"resolve didn't write in variant"); + tcx.sess.span_bug(span, "resolve didn't write in variant"); } } } @@ -404,10 +401,9 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { { // no-op } else if !ty::type_is_numeric(b_ty) { - tcx.sess.span_err(pat.span, ~"non-numeric type used in range"); + tcx.sess.span_err(pat.span, "non-numeric type used in range"); } else if !valid_range_bounds(fcx.ccx, begin, end) { - tcx.sess.span_err(begin.span, ~"lower range bound must be less \ - than upper"); + tcx.sess.span_err(begin.span, "lower range bound must be less than upper"); } fcx.write_ty(pat.id, b_ty); } @@ -476,9 +472,8 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { } _ => { tcx.sess.span_err(pat.span, - fmt!("mismatched types: expected `%s` \ - but found struct", - fcx.infcx().ty_to_str(expected))); + fmt!("mismatched types: expected `%s` but found struct", + fcx.infcx().ty_to_str(expected))); error_happened = true; } } diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index fb5b53d9400fb..abaadceb053fc 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -872,7 +872,7 @@ pub impl<'self> LookupContext<'self> { if relevant_candidates.len() > 1 { self.tcx().sess.span_err( self.expr.span, - ~"multiple applicable methods in scope"); + "multiple applicable methods in scope"); for uint::range(0, relevant_candidates.len()) |idx| { self.report_candidate(idx, &relevant_candidates[idx].origin); } @@ -983,12 +983,12 @@ pub impl<'self> LookupContext<'self> { } else if num_method_tps == 0u { tcx.sess.span_err( self.expr.span, - ~"this method does not take type parameters"); + "this method does not take type parameters"); self.fcx.infcx().next_ty_vars(num_method_tps) } else if num_supplied_tps != num_method_tps { tcx.sess.span_err( self.expr.span, - ~"incorrect number of type \ + "incorrect number of type \ parameters given for this method"); self.fcx.infcx().next_ty_vars(num_method_tps) } else { @@ -1082,14 +1082,14 @@ pub impl<'self> LookupContext<'self> { if ty::type_has_self(method_fty) { self.tcx().sess.span_err( self.expr.span, - ~"cannot call a method whose type contains a \ - self-type through a boxed trait"); + "cannot call a method whose type contains a \ + self-type through a boxed trait"); } if candidate.method_ty.generics.has_type_params() { self.tcx().sess.span_err( self.expr.span, - ~"cannot call a generic method through a boxed trait"); + "cannot call a generic method through a boxed trait"); } } @@ -1109,7 +1109,7 @@ pub impl<'self> LookupContext<'self> { if bad { self.tcx().sess.span_err(self.expr.span, - ~"explicit call to destructor"); + "explicit call to destructor"); } } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index d1c5ae18bc30b..69775771d9697 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -542,17 +542,15 @@ pub fn check_no_duplicate_fields(tcx: ty::ctxt, let (id, sp) = *p; let orig_sp = field_names.find(&id).map_consume(|x| *x); match orig_sp { - Some(orig_sp) => { - tcx.sess.span_err(sp, fmt!("Duplicate field \ - name %s in record type declaration", - *tcx.sess.str_of(id))); - tcx.sess.span_note(orig_sp, ~"First declaration of \ - this field occurred here"); - break; - } - None => { - field_names.insert(id, sp); - } + Some(orig_sp) => { + tcx.sess.span_err(sp, fmt!("Duplicate field name %s in record type declaration", + *tcx.sess.str_of(id))); + tcx.sess.span_note(orig_sp, "First declaration of this field occurred here"); + break; + } + None => { + field_names.insert(id, sp); + } } } } @@ -1252,8 +1250,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, ty::ty_rptr(_, mt) => formal_ty = mt.ty, ty::ty_err => (), _ => { - fcx.ccx.tcx.sess.span_bug(arg.span, - ~"no ref"); + fcx.ccx.tcx.sess.span_bug(arg.span, "no ref"); } } } @@ -1559,8 +1556,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, match ty::get(lhs_resolved_t).sty { ty::ty_bare_fn(_) | ty::ty_closure(_) => { tcx.sess.span_note( - ex.span, ~"did you forget the `do` keyword \ - for the call?"); + ex.span, "did you forget the `do` keyword for the call?"); } _ => () } @@ -1851,9 +1847,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, tcx.sess.span_err(span, fmt!("missing field%s: %s", if missing_fields.len() == 1 { - ~"" + "" } else { - ~"s" + "s" }, str::connect(missing_fields, ~", "))); } @@ -1901,7 +1897,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } _ => { tcx.sess.span_bug(span, - ~"resolve didn't map this to a class"); + "resolve didn't map this to a class"); } } } else { @@ -1989,7 +1985,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } _ => { tcx.sess.span_bug(span, - ~"resolve didn't map this to an enum"); + "resolve didn't map this to an enum"); } } } else { @@ -2201,7 +2197,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, } } _ => - tcx.sess.span_bug(expr.span, ~"vstore modifier on non-sequence") + tcx.sess.span_bug(expr.span, "vstore modifier on non-sequence") }; fcx.write_ty(ev.id, typ); fcx.write_ty(id, typ); @@ -2284,21 +2280,18 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, ty::ty_enum(*) => { tcx.sess.span_err( expr.span, - ~"can only dereference enums \ - with a single variant which has a \ - single argument"); + "can only dereference enums with a single variant which \ + has a single argument"); } ty::ty_struct(*) => { tcx.sess.span_err( expr.span, - ~"can only dereference structs with \ - one anonymous field"); + "can only dereference structs with one anonymous field"); } _ => { fcx.type_error_message(expr.span, |actual| { - fmt!("type %s cannot be \ - dereferenced", actual) + fmt!("type %s cannot be dereferenced", actual) }, oprnd_t, None); } } @@ -2394,7 +2387,7 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, result::Err(_) => { tcx.sess.span_err( expr.span, - ~"`return;` in function returning non-nil"); + "`return;` in function returning non-nil"); } }, Some(e) => { @@ -2758,8 +2751,8 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, variant_id, *fields); } _ => { - tcx.sess.span_bug(path.span, ~"structure constructor does \ - not name a structure type"); + tcx.sess.span_bug(path.span, + "structure constructor does not name a structure type"); } } } @@ -2961,7 +2954,7 @@ pub fn check_block_with_expected(fcx: @mut FnCtxt, } _ => false } { - fcx.ccx.tcx.sess.span_warn(s.span, ~"unreachable statement"); + fcx.ccx.tcx.sess.span_warn(s.span, "unreachable statement"); warned = true; } if ty::type_is_bot(s_ty) { @@ -2982,7 +2975,7 @@ pub fn check_block_with_expected(fcx: @mut FnCtxt, }, Some(e) => { if any_bot && !warned { - fcx.ccx.tcx.sess.span_warn(e.span, ~"unreachable expression"); + fcx.ccx.tcx.sess.span_warn(e.span, "unreachable expression"); } check_expr_with_opt_hint(fcx, e, expected); let ety = fcx.expr_ty(e); @@ -3073,8 +3066,8 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt, *disr_val = val as int; } Ok(_) => { - ccx.tcx.sess.span_err(e.span, ~"expected signed integer \ - constant"); + ccx.tcx.sess.span_err(e.span, "expected signed integer \ + constant"); } Err(ref err) => { ccx.tcx.sess.span_err(e.span, @@ -3085,7 +3078,7 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt, } if vec::contains(*disr_vals, &*disr_val) { ccx.tcx.sess.span_err(v.span, - ~"discriminator value already exists"); + "discriminator value already exists"); } disr_vals.push(*disr_val); let ctor_ty = ty::node_id_to_type(ccx.tcx, v.node.id); @@ -3142,9 +3135,9 @@ pub fn check_enum_variants(ccx: @mut CrateCtxt, _ => false } }) { - ccx.tcx.sess.span_err(sp, ~"illegal recursive enum type; \ - wrap the inner value in a box to \ - make it representable"); + ccx.tcx.sess.span_err(sp, + "illegal recursive enum type; \ + wrap the inner value in a box to make it representable"); } // Check that it is possible to instantiate this enum: @@ -3205,26 +3198,25 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt, ast::def_ty(_) | ast::def_prim_ty(_) | ast::def_ty_param(*)=> { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found type"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type"); } ast::def_mod(*) | ast::def_foreign_mod(*) => { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found module"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found module"); } ast::def_use(*) => { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found use"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found use"); } ast::def_region(*) => { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found region"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found region"); } ast::def_typaram_binder(*) => { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found type \ - parameter"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found type parameter"); } ast::def_label(*) => { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found label"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found label"); } ast::def_self_ty(*) => { - fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found self ty"); + fcx.ccx.tcx.sess.span_bug(sp, "expected value but found self ty"); } } } @@ -3253,7 +3245,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt, match tpt.generics.region_param { None => { // ...but the type is not lifetime parameterized! fcx.ccx.tcx.sess.span_err - (span, ~"this item is not region-parameterized"); + (span, "this item is not region-parameterized"); None } Some(_) => { // ...and the type is lifetime parameterized, ok. @@ -3273,15 +3265,15 @@ pub fn instantiate_path(fcx: @mut FnCtxt, fcx.infcx().next_ty_vars(ty_param_count) } else if ty_param_count == 0 { fcx.ccx.tcx.sess.span_err - (span, ~"this item does not take type parameters"); + (span, "this item does not take type parameters"); fcx.infcx().next_ty_vars(ty_param_count) } else if ty_substs_len > ty_param_count { fcx.ccx.tcx.sess.span_err - (span, ~"too many type parameters provided for this item"); + (span, "too many type parameters provided for this item"); fcx.infcx().next_ty_vars(ty_param_count) } else if ty_substs_len < ty_param_count { fcx.ccx.tcx.sess.span_err - (span, ~"not enough type parameters provided for this item"); + (span, "not enough type parameters provided for this item"); fcx.infcx().next_ty_vars(ty_param_count) } else { pth.types.map(|aty| fcx.to_ty(*aty)) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index cb2b854276d6f..3a38d0b1d7ba3 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -490,13 +490,13 @@ fn constrain_auto_ref(rcx: @mut Rcx, expr: @ast::expr) { // reporting an error would be the correct path. tcx.sess.span_err( expr.span, - ~"lifetime of borrowed pointer does not include \ - the expression being borrowed"); + "lifetime of borrowed pointer does not include \ + the expression being borrowed"); note_and_explain_region( tcx, - ~"lifetime of the borrowed pointer is", + "lifetime of the borrowed pointer is", region, - ~""); + ""); rcx.errors_reported += 1; } } @@ -522,17 +522,17 @@ fn constrain_free_variables( result::Err(_) => { tcx.sess.span_err( freevar.span, - ~"captured variable does not outlive the enclosing closure"); + "captured variable does not outlive the enclosing closure"); note_and_explain_region( tcx, - ~"captured variable is valid for ", + "captured variable is valid for ", en_region, - ~""); + ""); note_and_explain_region( tcx, - ~"closure is valid for ", + "closure is valid for ", region, - ~""); + ""); } } } diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 44b6212261246..532638faa68c7 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -414,7 +414,7 @@ fn lookup_vtable(vcx: &VtableContext, if !is_early { vcx.tcx().sess.span_err( location_info.span, - ~"multiple applicable methods in scope"); + "multiple applicable methods in scope"); } return Some(/*bad*/copy found[0]); } diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 05b2f6f577b82..7fff756b01da5 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -76,10 +76,8 @@ pub fn get_base_type(inference_context: @mut InferCtxt, } _ => { inference_context.tcx.sess.span_fatal(span, - ~"the type of this value \ - must be known in order \ - to determine the base \ - type"); + "the type of this value must be known in order \ + to determine the base type"); } } @@ -257,9 +255,8 @@ pub impl CoherenceChecker { None => { let session = self.crate_context.tcx.sess; session.span_err(item.span, - ~"no base type found for inherent \ - implementation; implement a \ - trait or new type instead"); + "no base type found for inherent implementation; \ + implement a trait or new type instead"); } Some(_) => { // Nothing to do. @@ -483,11 +480,9 @@ pub impl CoherenceChecker { if self.polytypes_unify(polytype_a, polytype_b) { let session = self.crate_context.tcx.sess; session.span_err(self.span_of_impl(implementation_b), - ~"conflicting implementations for a \ - trait"); + "conflicting implementations for a trait"); session.span_note(self.span_of_impl(implementation_a), - ~"note conflicting implementation \ - here"); + "note conflicting implementation here"); } } } @@ -667,11 +662,9 @@ pub impl CoherenceChecker { // This is an error. let session = self.crate_context.tcx.sess; session.span_err(item.span, - ~"cannot associate methods with \ - a type outside the crate the \ - type is defined in; define \ - and implement a trait or new \ - type instead"); + "cannot associate methods with a type outside the \ + crate the type is defined in; define and implement \ + a trait or new type instead"); } } item_impl(_, Some(trait_ref), _, _) => { @@ -690,10 +683,8 @@ pub impl CoherenceChecker { if trait_def_id.crate != local_crate { let session = self.crate_context.tcx.sess; session.span_err(item.span, - ~"cannot provide an \ - extension implementation \ - for a trait not defined \ - in this crate"); + "cannot provide an extension implementation \ + for a trait not defined in this crate"); } } @@ -765,7 +756,7 @@ pub impl CoherenceChecker { None => { self.crate_context.tcx.sess.span_bug( original_type.span, - ~"resolve didn't resolve this type?!"); + "resolve didn't resolve this type?!"); } Some(&node_item(item, _)) => { match item.node { @@ -849,8 +840,7 @@ pub impl CoherenceChecker { } _ => { self.crate_context.tcx.sess.span_bug(item.span, - ~"can't convert a \ - non-impl to an impl"); + "can't convert a non-impl to an impl"); } } } @@ -862,9 +852,8 @@ pub impl CoherenceChecker { return item.span; } _ => { - self.crate_context.tcx.sess.bug(~"span_of_impl() called on \ - something that wasn't an \ - impl!"); + self.crate_context.tcx.sess.bug("span_of_impl() called on something that \ + wasn't an impl!"); } } } @@ -1045,17 +1034,16 @@ pub impl CoherenceChecker { match tcx.items.find(&impl_info.did.node) { Some(&ast_map::node_item(@ref item, _)) => { tcx.sess.span_err((*item).span, - ~"the Drop trait may only \ - be implemented on \ - structures"); + "the Drop trait may only be implemented on \ + structures"); } _ => { - tcx.sess.bug(~"didn't find impl in ast map"); + tcx.sess.bug("didn't find impl in ast map"); } } } else { - tcx.sess.bug(~"found external impl of Drop trait on \ - something other than a struct"); + tcx.sess.bug("found external impl of Drop trait on \ + something other than a struct"); } } } diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 10537711b3289..45d61bb735728 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -151,7 +151,7 @@ impl AstConv for CrateCtxt { fn ty_infer(&self, span: span) -> ty::t { self.tcx.sess.span_bug(span, - ~"found `ty_infer` in unexpected place"); + "found `ty_infer` in unexpected place"); } } @@ -416,8 +416,7 @@ pub fn ensure_supertraits(ccx: &CrateCtxt, if ty_trait_refs.any(|other_trait| other_trait.def_id == trait_ref.def_id) { // This means a trait inherited from the same supertrait more // than once. - tcx.sess.span_err(sp, ~"Duplicate supertrait in trait \ - declaration"); + tcx.sess.span_err(sp, "Duplicate supertrait in trait declaration"); break; } else { ty_trait_refs.push(trait_ref); diff --git a/src/librustc/middle/typeck/infer/region_inference.rs b/src/librustc/middle/typeck/infer/region_inference.rs index e12a3f2e97522..25e65d7a18bca 100644 --- a/src/librustc/middle/typeck/infer/region_inference.rs +++ b/src/librustc/middle/typeck/infer/region_inference.rs @@ -1587,9 +1587,9 @@ pub impl RegionVarBindings { note_and_explain_region( self.tcx, - ~"first, the lifetime cannot outlive ", + "first, the lifetime cannot outlive ", upper_bound.region, - ~"..."); + "..."); self.tcx.sess.span_note( upper_bound.span, @@ -1597,9 +1597,9 @@ pub impl RegionVarBindings { note_and_explain_region( self.tcx, - ~"but, the lifetime must be valid for ", + "but, the lifetime must be valid for ", lower_bound.region, - ~"..."); + "..."); self.tcx.sess.span_note( lower_bound.span, diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index b0e0b7319ac84..0012eb700302a 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -214,7 +214,7 @@ pub fn lookup_def_tcx(tcx: ty::ctxt, sp: span, id: ast::node_id) -> ast::def { match tcx.def_map.find(&id) { Some(&x) => x, _ => { - tcx.sess.span_fatal(sp, ~"internal error looking up a definition") + tcx.sess.span_fatal(sp, "internal error looking up a definition") } } } @@ -301,8 +301,7 @@ fn check_main_fn_ty(ccx: @mut CrateCtxt, if ps.is_parameterized() => { tcx.sess.span_err( main_span, - ~"main function is not allowed \ - to have type parameters"); + "main function is not allowed to have type parameters"); return; } _ => () @@ -343,8 +342,7 @@ fn check_start_fn_ty(ccx: @mut CrateCtxt, if ps.is_parameterized() => { tcx.sess.span_err( start_span, - ~"start function is not allowed to have type \ - parameters"); + "start function is not allowed to have type parameters"); return; } _ => () diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 1c03ad1375919..db4912d213108 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -342,7 +342,7 @@ pub fn expr_to_str(cx: @ext_ctxt, expr: @ast::expr, err_msg: ~str) -> ~str { pub fn expr_to_ident(cx: @ext_ctxt, expr: @ast::expr, - err_msg: ~str) -> ast::ident { + err_msg: &str) -> ast::ident { match expr.node { ast::expr_path(p) => { if vec::len(p.types) > 0u || vec::len(p.idents) != 1u { diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8459fc8c6273d..5ae101a567cc2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -308,22 +308,22 @@ pub impl Parser { } return copy self.buffer[(*self.buffer_start + dist - 1) & 3].tok; } - fn fatal(&self, m: ~str) -> ! { + fn fatal(&self, m: &str) -> ! { self.sess.span_diagnostic.span_fatal(*copy self.span, m) } - fn span_fatal(&self, sp: span, m: ~str) -> ! { + fn span_fatal(&self, sp: span, m: &str) -> ! { self.sess.span_diagnostic.span_fatal(sp, m) } - fn span_note(&self, sp: span, m: ~str) { + fn span_note(&self, sp: span, m: &str) { self.sess.span_diagnostic.span_note(sp, m) } - fn bug(&self, m: ~str) -> ! { + fn bug(&self, m: &str) -> ! { self.sess.span_diagnostic.span_bug(*copy self.span, m) } - fn warn(&self, m: ~str) { + fn warn(&self, m: &str) { self.sess.span_diagnostic.span_warn(*copy self.span, m) } - fn span_err(&self, sp: span, m: ~str) { + fn span_err(&self, sp: span, m: &str) { self.sess.span_diagnostic.span_err(sp, m) } fn abort_if_errors(&self) { @@ -2029,8 +2029,7 @@ pub impl Parser { // This is a 'continue' expression if opt_ident.is_some() { self.span_err(*self.last_span, - ~"a label may not be used with a `loop` \ - expression"); + "a label may not be used with a `loop` expression"); } let lo = self.span.lo; @@ -2167,7 +2166,7 @@ pub impl Parser { @ast::pat { node: pat_wild, _ } => (), @ast::pat { node: pat_ident(_, _, _), _ } => (), @ast::pat { span, _ } => self.span_fatal( - span, ~"expected an identifier or `_`" + span, "expected an identifier or `_`" ) } slice = Some(subpat); @@ -2459,7 +2458,7 @@ pub impl Parser { -> ast::pat_ { if !is_plain_ident(&*self.token) { self.span_fatal(*self.last_span, - ~"expected identifier, found path"); + "expected identifier, found path"); } // why a path here, and not just an identifier? let name = self.parse_path_without_tps(); @@ -2478,7 +2477,7 @@ pub impl Parser { if *self.token == token::LPAREN { self.span_fatal( *self.last_span, - ~"expected identifier, found enum pattern"); + "expected identifier, found enum pattern"); } pat_ident(binding_mode, name, sub) @@ -2609,19 +2608,19 @@ pub impl Parser { match self.parse_item_or_view_item(/*bad*/ copy item_attrs, false) { - iovi_item(i) => { - let hi = i.span.hi; - let decl = @spanned(lo, hi, decl_item(i)); - return @spanned(lo, hi, stmt_decl(decl, self.get_id())); - } - iovi_view_item(vi) => { - self.span_fatal(vi.span, ~"view items must be declared at \ - the top of the block"); - } - iovi_foreign_item(_) => { - self.fatal(~"foreign items are not allowed here"); - } - iovi_none() => { /* fallthrough */ } + iovi_item(i) => { + let hi = i.span.hi; + let decl = @spanned(lo, hi, decl_item(i)); + return @spanned(lo, hi, stmt_decl(decl, self.get_id())); + } + iovi_view_item(vi) => { + self.span_fatal(vi.span, + "view items must be declared at the top of the block"); + } + iovi_foreign_item(_) => { + self.fatal(~"foreign items are not allowed here"); + } + iovi_none() => { /* fallthrough */ } } check_expected_item(self, item_attrs); @@ -2822,8 +2821,7 @@ pub impl Parser { result.push(RegionTyParamBound); } else { self.span_err(*self.span, - ~"`'static` is the only permissible \ - region bound here"); + "`'static` is the only permissible region bound here"); } self.bump(); } @@ -3238,7 +3236,7 @@ pub impl Parser { }) } _ => { - self.span_err(*self.span, ~"not a trait"); + self.span_err(*self.span, "not a trait"); None } }; @@ -3467,9 +3465,8 @@ pub impl Parser { ) { iovi_item(item) => items.push(item), iovi_view_item(view_item) => { - self.span_fatal(view_item.span, ~"view items must be \ - declared at the top of the \ - module"); + self.span_fatal(view_item.span, "view items must be declared at the top of the \ + module"); } _ => { self.fatal( @@ -3762,7 +3759,7 @@ pub impl Parser { } if opt_abis.is_some() { - self.span_err(*self.span, ~"an ABI may not be specified here"); + self.span_err(*self.span, "an ABI may not be specified here"); } // extern mod foo; @@ -4397,9 +4394,7 @@ pub impl Parser { view_item_extern_mod(*) if !extern_mod_allowed => { self.span_err(view_item.span, - ~"\"extern mod\" \ - declarations are not \ - allowed here"); + "\"extern mod\" declarations are not allowed here"); } view_item_extern_mod(*) => {} } @@ -4425,8 +4420,7 @@ pub impl Parser { iovi_none => break, iovi_view_item(view_item) => { self.span_err(view_item.span, - ~"`use` and `extern mod` declarations \ - must precede items"); + "`use` and `extern mod` declarations must precede items"); } iovi_item(item) => { items.push(item) @@ -4461,8 +4455,7 @@ pub impl Parser { iovi_view_item(view_item) => { // I think this can't occur: self.span_err(view_item.span, - ~"`use` and `extern mod` declarations \ - must precede items"); + "`use` and `extern mod` declarations must precede items"); } iovi_item(_) => { // FIXME #5668: this will occur for a macro invocation: From 7aa10e616bc3d4d43051c04a074d7e573fb72886 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Thu, 2 May 2013 12:46:58 -0400 Subject: [PATCH 143/215] make link_args use spaces as separators Lots of linking arguments need to be passed as -Wl,--foo so giving the comma meaning at the rustc layer makes those flags impossible to pass. Multiple arguments can now be passed from a shell by quoting the argument: --link-args='-lfoo -Wl,--as-needed'. --- src/librustc/driver/driver.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index afd0e0acfe910..5e5d0640d808e 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -653,7 +653,7 @@ pub fn build_session_options(binary: @~str, let linker_args = getopts::opt_strs(matches, ~"link-args").flat_map( |a| { let mut args = ~[]; - for str::each_split_char(*a, ',') |arg| { + for str::each_split_char(*a, ' ') |arg| { args.push(str::from_slice(arg)); } args @@ -760,7 +760,7 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] { optmulti("L", "", "Add a directory to the library search path", "PATH"), optflag("", "lib", "Compile a library crate"), - optmulti("", "link-args", "FLAGS is a comma-separated list of flags + optmulti("", "link-args", "FLAGS is a space-separated list of flags passed to the linker", "FLAGS"), optflag("", "ls", "List the symbols defined by a library crate"), optflag("", "no-trans", From a0d8873097a587163887e701c08373a1571f8973 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Fri, 3 May 2013 02:36:24 +0900 Subject: [PATCH 144/215] More accurate spans --- src/libsyntax/parse/attr.rs | 2 +- src/libsyntax/parse/common.rs | 2 +- src/libsyntax/parse/parser.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 037b2c089f46a..93584b00d39e6 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -156,7 +156,7 @@ impl parser_attr for Parser { @spanned(lo, hi, ast::meta_list(name, inner_items)) } _ => { - let hi = self.span.hi; + let hi = self.last_span.hi; @spanned(lo, hi, ast::meta_word(name)) } } diff --git a/src/libsyntax/parse/common.rs b/src/libsyntax/parse/common.rs index 01f80c032e9a0..1df6860fedee9 100644 --- a/src/libsyntax/parse/common.rs +++ b/src/libsyntax/parse/common.rs @@ -122,7 +122,7 @@ pub impl Parser { fn parse_path_list_ident(&self) -> ast::path_list_ident { let lo = self.span.lo; let ident = self.parse_ident(); - let hi = self.span.hi; + let hi = self.last_span.hi; spanned(lo, hi, ast::path_list_ident_ { name: ident, id: self.get_id() }) } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 8459fc8c6273d..f0e9634d214d6 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -2445,7 +2445,7 @@ pub impl Parser { } } } - hi = self.span.hi; + hi = self.last_span.hi; } } @ast::pat { id: self.get_id(), node: pat, span: mk_sp(lo, hi) } @@ -4311,7 +4311,7 @@ pub impl Parser { rp: None, types: ~[] }; return @spanned(lo, - self.span.hi, + self.last_span.hi, view_path_simple(last, path, self.get_id())); } From 544ac620ba131d0f58eb48f631338c0ea64e0f10 Mon Sep 17 00:00:00 2001 From: gareth Date: Tue, 30 Apr 2013 23:00:07 +0100 Subject: [PATCH 145/215] Convert most of rust_run_program.cpp to rust (issue #2674). --- src/libcore/libc.rs | 131 ++++++++++++- src/libcore/os.rs | 2 +- src/libcore/run.rs | 353 +++++++++++++++++++++++++++++++----- src/rt/rust_run_program.cpp | 200 ++------------------ src/rt/rustrt.def.in | 4 +- 5 files changed, 454 insertions(+), 236 deletions(-) diff --git a/src/libcore/libc.rs b/src/libcore/libc.rs index 53aaf5726dd0b..59b06faf5a251 100644 --- a/src/libcore/libc.rs +++ b/src/libcore/libc.rs @@ -582,12 +582,16 @@ pub mod types { pub type LPWSTR = *mut WCHAR; pub type LPSTR = *mut CHAR; + pub type LPTSTR = *mut CHAR; // Not really, but opaque to us. pub type LPSECURITY_ATTRIBUTES = LPVOID; pub type LPVOID = *mut c_void; + pub type LPBYTE = *mut BYTE; pub type LPWORD = *mut WORD; + pub type LPDWORD = *mut DWORD; + pub type LPHANDLE = *mut HANDLE; pub type LRESULT = LONG_PTR; pub type PBOOL = *mut BOOL; @@ -596,6 +600,36 @@ pub mod types { pub type time64_t = i64; pub type int64 = i64; + + pub struct STARTUPINFO { + cb: DWORD, + lpReserved: LPTSTR, + lpDesktop: LPTSTR, + lpTitle: LPTSTR, + dwX: DWORD, + dwY: DWORD, + dwXSize: DWORD, + dwYSize: DWORD, + dwXCountChars: DWORD, + dwYCountCharts: DWORD, + dwFillAttribute: DWORD, + dwFlags: DWORD, + wShowWindow: WORD, + cbReserved2: WORD, + lpReserved2: LPBYTE, + hStdInput: HANDLE, + hStdOutput: HANDLE, + hStdError: HANDLE + } + pub type LPSTARTUPINFO = *mut STARTUPINFO; + + pub struct PROCESS_INFORMATION { + hProcess: HANDLE, + hThread: HANDLE, + dwProcessId: DWORD, + dwThreadId: DWORD + } + pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; } } } @@ -848,6 +882,11 @@ pub mod consts { pub mod bsd44 { } pub mod extra { + use libc::types::os::arch::extra::{DWORD, BOOL}; + + pub static TRUE : BOOL = 1; + pub static FALSE : BOOL = 0; + pub static O_TEXT : int = 16384; pub static O_BINARY : int = 32768; pub static O_NOINHERIT: int = 128; @@ -855,6 +894,50 @@ pub mod consts { pub static ERROR_SUCCESS : int = 0; pub static ERROR_INSUFFICIENT_BUFFER : int = 122; pub static INVALID_HANDLE_VALUE: int = -1; + + pub static DELETE : DWORD = 0x00010000; + pub static READ_CONTROL : DWORD = 0x00020000; + pub static SYNCHRONIZE : DWORD = 0x00100000; + pub static WRITE_DAC : DWORD = 0x00040000; + pub static WRITE_OWNER : DWORD = 0x00080000; + + pub static PROCESS_CREATE_PROCESS : DWORD = 0x0080; + pub static PROCESS_CREATE_THREAD : DWORD = 0x0002; + pub static PROCESS_DUP_HANDLE : DWORD = 0x0040; + pub static PROCESS_QUERY_INFORMATION : DWORD = 0x0400; + pub static PROCESS_QUERY_LIMITED_INFORMATION : DWORD = 0x1000; + pub static PROCESS_SET_INFORMATION : DWORD = 0x0200; + pub static PROCESS_SET_QUOTA : DWORD = 0x0100; + pub static PROCESS_SUSPEND_RESUME : DWORD = 0x0800; + pub static PROCESS_TERMINATE : DWORD = 0x0001; + pub static PROCESS_VM_OPERATION : DWORD = 0x0008; + pub static PROCESS_VM_READ : DWORD = 0x0010; + pub static PROCESS_VM_WRITE : DWORD = 0x0020; + + pub static STARTF_FORCEONFEEDBACK : DWORD = 0x00000040; + pub static STARTF_FORCEOFFFEEDBACK : DWORD = 0x00000080; + pub static STARTF_PREVENTPINNING : DWORD = 0x00002000; + pub static STARTF_RUNFULLSCREEN : DWORD = 0x00000020; + pub static STARTF_TITLEISAPPID : DWORD = 0x00001000; + pub static STARTF_TITLEISLINKNAME : DWORD = 0x00000800; + pub static STARTF_USECOUNTCHARS : DWORD = 0x00000008; + pub static STARTF_USEFILLATTRIBUTE : DWORD = 0x00000010; + pub static STARTF_USEHOTKEY : DWORD = 0x00000200; + pub static STARTF_USEPOSITION : DWORD = 0x00000004; + pub static STARTF_USESHOWWINDOW : DWORD = 0x00000001; + pub static STARTF_USESIZE : DWORD = 0x00000002; + pub static STARTF_USESTDHANDLES : DWORD = 0x00000100; + + pub static WAIT_ABANDONED : DWORD = 0x00000080; + pub static WAIT_OBJECT_0 : DWORD = 0x00000000; + pub static WAIT_TIMEOUT : DWORD = 0x00000102; + pub static WAIT_FAILED : DWORD = -1; + + pub static DUPLICATE_CLOSE_SOURCE : DWORD = 0x00000001; + pub static DUPLICATE_SAME_ACCESS : DWORD = 0x00000002; + + pub static INFINITE : DWORD = -1; + pub static STILL_ACTIVE : DWORD = 259; } } @@ -1751,12 +1834,24 @@ pub mod funcs { unsafe fn sysctlnametomib(name: *c_char, mibp: *mut c_int, sizep: *mut size_t) -> c_int; + + unsafe fn getdtablesize() -> c_int; } } #[cfg(target_os = "linux")] #[cfg(target_os = "android")] + pub mod bsd44 { + use libc::types::os::arch::c95::{c_int}; + + #[abi = "cdecl"] + pub extern { + unsafe fn getdtablesize() -> c_int; + } + } + + #[cfg(target_os = "win32")] pub mod bsd44 { } @@ -1790,9 +1885,11 @@ pub mod funcs { pub mod kernel32 { use libc::types::os::arch::c95::{c_uint}; use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE}; - use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPTCH}; - use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES}; - use libc::types::os::arch::extra::{HANDLE}; + use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPCTSTR, + LPTSTR, LPTCH, LPDWORD, LPVOID}; + use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES, LPSTARTUPINFO, + LPPROCESS_INFORMATION}; + use libc::types::os::arch::extra::{HANDLE, LPHANDLE}; #[abi = "stdcall"] pub extern "stdcall" { @@ -1829,19 +1926,45 @@ pub mod funcs { findFileData: HANDLE) -> BOOL; unsafe fn FindClose(findFile: HANDLE) -> BOOL; + unsafe fn DuplicateHandle(hSourceProcessHandle: HANDLE, + hSourceHandle: HANDLE, + hTargetProcessHandle: HANDLE, + lpTargetHandle: LPHANDLE, + dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwOptions: DWORD) -> BOOL; unsafe fn CloseHandle(hObject: HANDLE) -> BOOL; + unsafe fn OpenProcess(dwDesiredAccess: DWORD, + bInheritHandle: BOOL, + dwProcessId: DWORD) -> HANDLE; + unsafe fn GetCurrentProcess() -> HANDLE; + unsafe fn CreateProcessA(lpApplicationName: LPCTSTR, + lpCommandLine: LPTSTR, + lpProcessAttributes: LPSECURITY_ATTRIBUTES, + lpThreadAttributes: LPSECURITY_ATTRIBUTES, + bInheritHandles: BOOL, + dwCreationFlags: DWORD, + lpEnvironment: LPVOID, + lpCurrentDirectory: LPCTSTR, + lpStartupInfo: LPSTARTUPINFO, + lpProcessInformation: LPPROCESS_INFORMATION) -> BOOL; + unsafe fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; unsafe fn TerminateProcess(hProcess: HANDLE, uExitCode: c_uint) -> BOOL; + unsafe fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: LPDWORD) -> BOOL; } } pub mod msvcrt { - use libc::types::os::arch::c95::c_int; + use libc::types::os::arch::c95::{c_int, c_long}; #[abi = "cdecl"] #[nolink] pub extern { #[link_name = "_commit"] unsafe fn commit(fd: c_int) -> c_int; + + #[link_name = "_get_osfhandle"] + unsafe fn get_osfhandle(fd: c_int) -> c_long; } } } diff --git a/src/libcore/os.rs b/src/libcore/os.rs index 8efae3e0e6890..c4b03d76cefec 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -373,7 +373,7 @@ pub fn pipe() -> Pipe { // inheritance has to be handled in a different way that I do not // fully understand. Here we explicitly make the pipe non-inheritable, // which means to pass it to a subprocess they need to be duplicated - // first, as in rust_run_program. + // first, as in core::run. let mut fds = Pipe {in: 0 as c_int, out: 0 as c_int }; let res = libc::pipe(&mut fds.in, 1024 as ::libc::c_uint, diff --git a/src/libcore/run.rs b/src/libcore/run.rs index d0c495dd19e44..0a8ccc3c5e9b9 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -22,31 +22,6 @@ use str; use task; use vec; -pub mod rustrt { - use libc::{c_int, c_void}; - use libc; - use run; - - #[abi = "cdecl"] - pub extern { - unsafe fn rust_run_program(argv: **libc::c_char, - envp: *c_void, - dir: *libc::c_char, - in_fd: c_int, - out_fd: c_int, - err_fd: c_int) -> run::RunProgramResult; - unsafe fn rust_process_wait(pid: c_int) -> c_int; - } -} - -pub struct RunProgramResult { - // the process id of the program, or -1 if in case of errors - pid: pid_t, - // a handle to the process - on unix this will always be NULL, but on windows it will be a - // HANDLE to the process, which will prevent the pid being re-used until the handle is closed. - handle: *(), -} - /// A value representing a child process pub struct Program { priv pid: pid_t, @@ -191,21 +166,262 @@ pub fn spawn_process(prog: &str, args: &[~str], return res.pid; } +struct RunProgramResult { + // the process id of the program (this should never be negative) + pid: pid_t, + // a handle to the process - on unix this will always be NULL, but on windows it will be a + // HANDLE to the process, which will prevent the pid being re-used until the handle is closed. + handle: *(), +} + +#[cfg(windows)] fn spawn_process_internal(prog: &str, args: &[~str], env: &Option<~[(~str,~str)]>, dir: &Option<~str>, in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult { + + use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; + use libc::consts::os::extra::{ + TRUE, FALSE, + STARTF_USESTDHANDLES, + INVALID_HANDLE_VALUE, + DUPLICATE_SAME_ACCESS + }; + use libc::funcs::extra::kernel32::{ + GetCurrentProcess, + DuplicateHandle, + CloseHandle, + CreateProcessA + }; + use libc::funcs::extra::msvcrt::get_osfhandle; + unsafe { - do with_argv(prog, args) |argv| { - do with_envp(env) |envp| { - do with_dirp(dir) |dirp| { - rustrt::rust_run_program(argv, envp, dirp, in_fd, out_fd, err_fd) + + let mut si = zeroed_startupinfo(); + si.cb = sys::size_of::() as DWORD; + si.dwFlags = STARTF_USESTDHANDLES; + + let cur_proc = GetCurrentProcess(); + + let orig_std_in = get_osfhandle(if in_fd > 0 { in_fd } else { 0 }) as HANDLE; + if orig_std_in == INVALID_HANDLE_VALUE as HANDLE { + fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error())); + } + if DuplicateHandle(cur_proc, orig_std_in, cur_proc, &mut si.hStdInput, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { + fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error())); + } + + let orig_std_out = get_osfhandle(if out_fd > 0 { out_fd } else { 1 }) as HANDLE; + if orig_std_out == INVALID_HANDLE_VALUE as HANDLE { + fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error())); + } + if DuplicateHandle(cur_proc, orig_std_out, cur_proc, &mut si.hStdOutput, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { + fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error())); + } + + let orig_std_err = get_osfhandle(if err_fd > 0 { err_fd } else { 2 }) as HANDLE; + if orig_std_err as HANDLE == INVALID_HANDLE_VALUE as HANDLE { + fail!(fmt!("failure in get_osfhandle: %s", os::last_os_error())); + } + if DuplicateHandle(cur_proc, orig_std_err, cur_proc, &mut si.hStdError, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { + fail!(fmt!("failure in DuplicateHandle: %s", os::last_os_error())); + } + + let cmd = make_command_line(prog, args); + let mut pi = zeroed_process_information(); + let mut create_err = None; + + do with_envp(env) |envp| { + do with_dirp(dir) |dirp| { + do str::as_c_str(cmd) |cmdp| { + let created = CreateProcessA(ptr::null(), cast::transmute(cmdp), + ptr::mut_null(), ptr::mut_null(), TRUE, + 0, envp, dirp, &mut si, &mut pi); + if created == FALSE { + create_err = Some(os::last_os_error()); + } } } } + + CloseHandle(si.hStdInput); + CloseHandle(si.hStdOutput); + CloseHandle(si.hStdError); + + for create_err.each |msg| { + fail!(fmt!("failure in CreateProcess: %s", *msg)); + } + + // We close the thread handle because we don't care about keeping the thread id valid, + // and we aren't keeping the thread handle around to be able to close it later. We don't + // close the process handle however because we want the process id to stay valid at least + // until the calling code closes the process handle. + CloseHandle(pi.hThread); + + RunProgramResult { + pid: pi.dwProcessId as pid_t, + handle: pi.hProcess as *() + } + } +} + +#[cfg(windows)] +fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO { + libc::types::os::arch::extra::STARTUPINFO { + cb: 0, + lpReserved: ptr::mut_null(), + lpDesktop: ptr::mut_null(), + lpTitle: ptr::mut_null(), + dwX: 0, + dwY: 0, + dwXSize: 0, + dwYSize: 0, + dwXCountChars: 0, + dwYCountCharts: 0, + dwFillAttribute: 0, + dwFlags: 0, + wShowWindow: 0, + cbReserved2: 0, + lpReserved2: ptr::mut_null(), + hStdInput: ptr::mut_null(), + hStdOutput: ptr::mut_null(), + hStdError: ptr::mut_null() + } +} + +#[cfg(windows)] +fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION { + libc::types::os::arch::extra::PROCESS_INFORMATION { + hProcess: ptr::mut_null(), + hThread: ptr::mut_null(), + dwProcessId: 0, + dwThreadId: 0 } } +// FIXME: this is only pub so it can be tested (see issue #4536) +#[cfg(windows)] +pub fn make_command_line(prog: &str, args: &[~str]) -> ~str { + + let mut cmd = ~""; + append_arg(&mut cmd, prog); + for args.each |arg| { + cmd.push_char(' '); + append_arg(&mut cmd, *arg); + } + return cmd; + + fn append_arg(cmd: &mut ~str, arg: &str) { + let quote = arg.any(|c| c == ' ' || c == '\t'); + if quote { + cmd.push_char('"'); + } + for uint::range(0, arg.len()) |i| { + append_char_at(cmd, arg, i); + } + if quote { + cmd.push_char('"'); + } + } + + fn append_char_at(cmd: &mut ~str, arg: &str, i: uint) { + match arg[i] as char { + '"' => { + // Escape quotes. + cmd.push_str("\\\""); + } + '\\' => { + if backslash_run_ends_in_quote(arg, i) { + // Double all backslashes that are in runs before quotes. + cmd.push_str("\\\\"); + } else { + // Pass other backslashes through unescaped. + cmd.push_char('\\'); + } + } + c => { + cmd.push_char(c); + } + } + } + + fn backslash_run_ends_in_quote(s: &str, mut i: uint) -> bool { + while i < s.len() && s[i] as char == '\\' { + i += 1; + } + return i < s.len() && s[i] as char == '"'; + } +} + +#[cfg(unix)] +fn spawn_process_internal(prog: &str, args: &[~str], + env: &Option<~[(~str,~str)]>, + dir: &Option<~str>, + in_fd: c_int, out_fd: c_int, err_fd: c_int) -> RunProgramResult { + + use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; + use libc::funcs::bsd44::getdtablesize; + + mod rustrt { + use libc::c_void; + + #[abi = "cdecl"] + pub extern { + unsafe fn rust_unset_sigprocmask(); + unsafe fn rust_set_environ(envp: *c_void); + } + } + + unsafe { + + let pid = fork(); + if pid < 0 { + fail!(fmt!("failure in fork: %s", os::last_os_error())); + } else if pid > 0 { + return RunProgramResult {pid: pid, handle: ptr::null()}; + } + + rustrt::rust_unset_sigprocmask(); + + if in_fd > 0 && dup2(in_fd, 0) == -1 { + fail!(fmt!("failure in dup2(in_fd, 0): %s", os::last_os_error())); + } + if out_fd > 0 && dup2(out_fd, 1) == -1 { + fail!(fmt!("failure in dup2(out_fd, 1): %s", os::last_os_error())); + } + if err_fd > 0 && dup2(err_fd, 2) == -1 { + fail!(fmt!("failure in dup3(err_fd, 2): %s", os::last_os_error())); + } + // close all other fds + for int::range_rev(getdtablesize() as int - 1, 2) |fd| { + close(fd as c_int); + } + + for dir.each |dir| { + do str::as_c_str(*dir) |dirp| { + if chdir(dirp) == -1 { + fail!(fmt!("failure in chdir: %s", os::last_os_error())); + } + } + } + + do with_envp(env) |envp| { + if !envp.is_null() { + rustrt::rust_set_environ(envp); + } + do with_argv(prog, args) |argv| { + execvp(*argv, argv); + // execvp only returns if an error occurred + fail!(fmt!("failure in execvp: %s", os::last_os_error())); + } + } + } +} + +#[cfg(unix)] fn with_argv(prog: &str, args: &[~str], cb: &fn(**libc::c_char) -> T) -> T { let mut argptrs = str::as_c_str(prog, |b| ~[b]); @@ -246,7 +462,7 @@ fn with_envp(env: &Option<~[(~str,~str)]>, #[cfg(windows)] fn with_envp(env: &Option<~[(~str,~str)]>, - cb: &fn(*c_void) -> T) -> T { + cb: &fn(*mut c_void) -> T) -> T { // On win32 we pass an "environment block" which is not a char**, but // rather a concatenation of null-terminated k=v\0 sequences, with a final // \0 to terminate. @@ -264,11 +480,12 @@ fn with_envp(env: &Option<~[(~str,~str)]>, blk += ~[0_u8]; vec::as_imm_buf(blk, |p, _len| cb(::cast::transmute(p))) } - _ => cb(ptr::null()) + _ => cb(ptr::mut_null()) } } } +#[cfg(windows)] fn with_dirp(d: &Option<~str>, cb: &fn(*libc::c_char) -> T) -> T { match *d { @@ -312,8 +529,6 @@ priv fn free_handle(_handle: *()) { pub fn run_program(prog: &str, args: &[~str]) -> int { let res = spawn_process_internal(prog, args, &None, &None, 0i32, 0i32, 0i32); - if res.pid == -1 as pid_t { fail!(); } - let code = waitpid(res.pid); free_handle(res.handle); return code; @@ -345,7 +560,6 @@ pub fn start_program(prog: &str, args: &[~str]) -> Program { pipe_err.out); unsafe { - if res.pid == -1 as pid_t { fail!(); } libc::close(pipe_input.in); libc::close(pipe_output.out); libc::close(pipe_err.out); @@ -398,13 +612,6 @@ pub fn program_output(prog: &str, args: &[~str]) -> ProgramOutput { os::close(pipe_in.in); os::close(pipe_out.out); os::close(pipe_err.out); - if res.pid == -1i32 { - os::close(pipe_in.out); - os::close(pipe_out.in); - os::close(pipe_err.in); - fail!(); - } - os::close(pipe_in.out); // Spawn two entire schedulers to read both stdout and sterr @@ -485,11 +692,46 @@ pub fn waitpid(pid: pid_t) -> int { #[cfg(windows)] fn waitpid_os(pid: pid_t) -> int { - let status = unsafe { rustrt::rust_process_wait(pid) }; - if status < 0 { - fail!(fmt!("failure in rust_process_wait: %s", os::last_os_error())); + + use libc::types::os::arch::extra::DWORD; + use libc::consts::os::extra::{ + SYNCHRONIZE, + PROCESS_QUERY_INFORMATION, + FALSE, + STILL_ACTIVE, + INFINITE, + WAIT_FAILED + }; + use libc::funcs::extra::kernel32::{ + OpenProcess, + GetExitCodeProcess, + CloseHandle, + WaitForSingleObject + }; + + unsafe { + + let proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD); + if proc.is_null() { + fail!(fmt!("failure in OpenProcess: %s", os::last_os_error())); + } + + loop { + let mut status = 0; + if GetExitCodeProcess(proc, &mut status) == FALSE { + CloseHandle(proc); + fail!(fmt!("failure in GetExitCodeProcess: %s", os::last_os_error())); + } + if status != STILL_ACTIVE { + CloseHandle(proc); + return status as int; + } + if WaitForSingleObject(proc, INFINITE) == WAIT_FAILED { + CloseHandle(proc); + fail!(fmt!("failure in WaitForSingleObject: %s", os::last_os_error())); + } + } } - return status as int; } #[cfg(unix)] @@ -543,6 +785,27 @@ mod tests { use run::{readclose, writeclose}; use run; + #[test] + #[cfg(windows)] + fn test_make_command_line() { + assert_eq!( + run::make_command_line("prog", [~"aaa", ~"bbb", ~"ccc"]), + ~"prog aaa bbb ccc" + ); + assert_eq!( + run::make_command_line("C:\\Program Files\\blah\\blah.exe", [~"aaa"]), + ~"\"C:\\Program Files\\blah\\blah.exe\" aaa" + ); + assert_eq!( + run::make_command_line("C:\\Program Files\\test", [~"aa\"bb"]), + ~"\"C:\\Program Files\\test\" aa\\\"bb" + ); + assert_eq!( + run::make_command_line("echo", [~"a b c"]), + ~"echo \"a b c\"" + ); + } + // Regression test for memory leaks #[test] fn test_leaks() { diff --git a/src/rt/rust_run_program.cpp b/src/rt/rust_run_program.cpp index cf4beed1a00c6..0ba7607869140 100644 --- a/src/rt/rust_run_program.cpp +++ b/src/rt/rust_run_program.cpp @@ -15,212 +15,44 @@ #include #endif -struct RunProgramResult { - pid_t pid; - void* handle; -}; - #if defined(__WIN32__) -#include -#include - -bool backslash_run_ends_in_quote(char const *c) { - while (*c == '\\') ++c; - return *c == '"'; -} - -void append_first_char(char *&buf, char const *c) { - switch (*c) { - - case '"': - // Escape quotes. - *buf++ = '\\'; - *buf++ = '"'; - break; - - - case '\\': - if (backslash_run_ends_in_quote(c)) { - // Double all backslashes that are in runs before quotes. - *buf++ = '\\'; - *buf++ = '\\'; - } else { - // Pass other backslashes through unescaped. - *buf++ = '\\'; - } - break; - - default: - *buf++ = *c; - } +extern "C" CDECL void +rust_unset_sigprocmask() { + // empty stub for windows to keep linker happy } -bool contains_whitespace(char const *arg) { - while (*arg) { - switch (*arg++) { - case ' ': - case '\t': - return true; - } - } - return false; -} - -void append_arg(char *& buf, char const *arg, bool last) { - bool quote = contains_whitespace(arg); - if (quote) - *buf++ = '"'; - while (*arg) - append_first_char(buf, arg++); - if (quote) - *buf++ = '"'; - - if (! last) { - *buf++ = ' '; - } else { - *buf++ = '\0'; - } -} - -extern "C" CDECL RunProgramResult -rust_run_program(const char* argv[], - void* envp, - const char* dir, - int in_fd, int out_fd, int err_fd) { - STARTUPINFO si; - ZeroMemory(&si, sizeof(STARTUPINFO)); - si.cb = sizeof(STARTUPINFO); - si.dwFlags = STARTF_USESTDHANDLES; - - RunProgramResult result = {-1, NULL}; - - HANDLE curproc = GetCurrentProcess(); - HANDLE origStdin = (HANDLE)_get_osfhandle(in_fd ? in_fd : 0); - if (!DuplicateHandle(curproc, origStdin, - curproc, &si.hStdInput, 0, 1, DUPLICATE_SAME_ACCESS)) - return result; - HANDLE origStdout = (HANDLE)_get_osfhandle(out_fd ? out_fd : 1); - if (!DuplicateHandle(curproc, origStdout, - curproc, &si.hStdOutput, 0, 1, DUPLICATE_SAME_ACCESS)) - return result; - HANDLE origStderr = (HANDLE)_get_osfhandle(err_fd ? err_fd : 2); - if (!DuplicateHandle(curproc, origStderr, - curproc, &si.hStdError, 0, 1, DUPLICATE_SAME_ACCESS)) - return result; - - size_t cmd_len = 0; - for (const char** arg = argv; *arg; arg++) { - cmd_len += strlen(*arg); - cmd_len += 3; // Two quotes plus trailing space or \0 - } - cmd_len *= 2; // Potentially backslash-escape everything. - - char* cmd = (char*)malloc(cmd_len); - char* pos = cmd; - for (const char** arg = argv; *arg; arg++) { - append_arg(pos, *arg, *(arg+1) == NULL); - } - - PROCESS_INFORMATION pi; - BOOL created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, - 0, envp, dir, &si, &pi); - - CloseHandle(si.hStdInput); - CloseHandle(si.hStdOutput); - CloseHandle(si.hStdError); - free(cmd); - - if (!created) { - return result; - } - - // We close the thread handle because we don't care about keeping the thread id valid, - // and we aren't keeping the thread handle around to be able to close it later. We don't - // close the process handle however because we want the process id to stay valid at least - // until the calling rust code closes the process handle. - CloseHandle(pi.hThread); - result.pid = pi.dwProcessId; - result.handle = pi.hProcess; - return result; -} - -extern "C" CDECL int -rust_process_wait(int pid) { - - HANDLE proc = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, pid); - if (proc == NULL) { - return -1; - } - - DWORD status; - while (true) { - if (!GetExitCodeProcess(proc, &status)) { - CloseHandle(proc); - return -1; - } - if (status != STILL_ACTIVE) { - CloseHandle(proc); - return (int) status; - } - WaitForSingleObject(proc, INFINITE); - } +extern "C" CDECL void +rust_set_environ(void* envp) { + // empty stub for windows to keep linker happy } #elif defined(__GNUC__) -#include #include -#include #include -#include #ifdef __FreeBSD__ extern char **environ; #endif -extern "C" CDECL RunProgramResult -rust_run_program(const char* argv[], - void* envp, - const char* dir, - int in_fd, int out_fd, int err_fd) { - int pid = fork(); - if (pid != 0) { - RunProgramResult result = {pid, NULL}; - return result; - } - +extern "C" CDECL void +rust_unset_sigprocmask() { + // this can't be safely converted to rust code because the + // representation of sigset_t is platform-dependent sigset_t sset; sigemptyset(&sset); sigprocmask(SIG_SETMASK, &sset, NULL); +} - if (in_fd) dup2(in_fd, 0); - if (out_fd) dup2(out_fd, 1); - if (err_fd) dup2(err_fd, 2); - /* Close all other fds. */ - for (int fd = getdtablesize() - 1; fd >= 3; fd--) close(fd); - if (dir) { - int result = chdir(dir); - // FIXME (#2674): need error handling - assert(!result && "chdir failed"); - } - - if (envp) { +extern "C" CDECL void +rust_set_environ(void* envp) { + // FIXME: this could actually be converted to rust (see issue #2674) #ifdef __APPLE__ - *_NSGetEnviron() = (char **)envp; + *_NSGetEnviron() = (char **) envp; #else - environ = (char **)envp; + environ = (char **) envp; #endif - } - - execvp(argv[0], (char * const *)argv); - exit(1); -} - -extern "C" CDECL int -rust_process_wait(int pid) { - // FIXME: stub; exists to placate linker. (#2692) - return 0; } #else diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 977e0248ca206..408e2e9a81671 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -37,8 +37,8 @@ rust_list_dir_wfd_size rust_list_dir_wfd_fp_buf rust_log_console_on rust_log_console_off -rust_process_wait -rust_run_program +rust_set_environ +rust_unset_sigprocmask rust_sched_current_nonlazy_threads rust_sched_threads rust_set_exit_status From 23e97ae89303f7e8933dce0c42de08d214bad066 Mon Sep 17 00:00:00 2001 From: gareth Date: Wed, 1 May 2013 22:20:26 +0100 Subject: [PATCH 146/215] Remove errant trailing whitespace. --- src/libcore/run.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 0a8ccc3c5e9b9..0850121d6020d 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -374,7 +374,7 @@ fn spawn_process_internal(prog: &str, args: &[~str], unsafe fn rust_set_environ(envp: *c_void); } } - + unsafe { let pid = fork(); From 88ec89d3fe42029dd6005822191dc97de07d930c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 2 May 2013 14:32:37 -0400 Subject: [PATCH 147/215] fix numerous dynamic borrow failures --- src/libcore/unstable/lang.rs | 2 +- src/libcore/util.rs | 19 +++++++------ src/librustc/middle/liveness.rs | 18 ++++++------ src/librustc/middle/region.rs | 3 +- src/librustc/middle/resolve.rs | 32 ++++++++++------------ src/librustc/middle/typeck/check/vtable.rs | 7 +++-- src/librustc/middle/typeck/coherence.rs | 23 ++++++++-------- src/librustc/middle/typeck/infer/glb.rs | 4 ++- src/librustc/middle/typeck/infer/lub.rs | 4 ++- src/librustc/middle/typeck/infer/mod.rs | 25 ++++++++--------- src/librustc/rustc.rc | 3 ++ src/libsyntax/codemap.rs | 2 +- 12 files changed, 77 insertions(+), 65 deletions(-) diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 017fc4b7b63a0..d25147fcde118 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -133,7 +133,7 @@ pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { /// Because this code is so perf. sensitive, use a static constant so that /// debug printouts are compiled out most of the time. -static ENABLE_DEBUG_PTR: bool = false; +static ENABLE_DEBUG_PTR: bool = true; #[inline] pub fn debug_ptr(tag: &'static str, p: *const T) { diff --git a/src/libcore/util.rs b/src/libcore/util.rs index a08e38c021fad..43616ebfd3032 100644 --- a/src/libcore/util.rs +++ b/src/libcore/util.rs @@ -26,19 +26,20 @@ pub fn ignore(_x: T) { } /// Sets `*ptr` to `new_value`, invokes `op()`, and then restores the /// original value of `*ptr`. +/// +/// NB: This function accepts `@mut T` and not `&mut T` to avoid +/// an obvious borrowck hazard. Typically passing in `&mut T` will +/// cause borrow check errors because it freezes whatever location +/// that `&mut T` is stored in (either statically or dynamically). #[inline(always)] -pub fn with( - ptr: &mut T, - new_value: T, +pub fn with( + ptr: @mut T, + mut value: T, op: &fn() -> R) -> R { - // NDM: if swap operator were defined somewhat differently, - // we wouldn't need to copy... - - let old_value = *ptr; - *ptr = new_value; + value <-> *ptr; let result = op(); - *ptr = old_value; + *ptr = value; return result; } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 2e2c92abcdc78..59a6e6469e2bb 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -112,7 +112,6 @@ use util::ppaux::ty_to_str; use core::cast::transmute; use core::hashmap::HashMap; -use core::util::with; use syntax::ast::*; use syntax::codemap::span; use syntax::parse::token::special_idents; @@ -343,9 +342,10 @@ pub impl IrMaps { } fn visit_item(item: @item, self: @mut IrMaps, v: vt<@mut IrMaps>) { - do with(&mut self.cur_item, item.id) { - visit::visit_item(item, self, v) - } + let old_cur_item = self.cur_item; + self.cur_item = item.id; + visit::visit_item(item, self, v); + self.cur_item = old_cur_item; } fn visit_fn(fk: &visit::fn_kind, @@ -762,11 +762,13 @@ pub impl Liveness { None => { // Vanilla 'break' or 'loop', so use the enclosing // loop scope - let loop_scope = &mut *self.loop_scope; - if loop_scope.len() == 0 { + let len = { // FIXME(#5074) stage0 + let loop_scope = &mut *self.loop_scope; + loop_scope.len() + }; + if len == 0 { self.tcx.sess.span_bug(sp, ~"break outside loop"); - } - else { + } else { // FIXME(#5275): this shouldn't have to be a method... self.last_loop_scope() } diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index ea21ab0527b4d..06eb2542235e4 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -949,7 +949,8 @@ pub fn determine_rp_in_crate(sess: Session, let cx = &mut *cx; while cx.worklist.len() != 0 { let c_id = cx.worklist.pop(); - let c_variance = *cx.region_paramd_items.get(&c_id); + let c_variance = { *cx.region_paramd_items.get(&c_id) }; + // NOTE cleanup scopes cause an exaggerated lock here debug!("popped %d from worklist", c_id); match cx.dep_map.find(&c_id) { None => {} diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index ff46abaf7128c..8e83ea7e32e3b 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -779,9 +779,9 @@ pub fn Resolver(session: Session, unresolved_imports: 0, current_module: current_module, - value_ribs: ~[], - type_ribs: ~[], - label_ribs: ~[], + value_ribs: @mut ~[], + type_ribs: @mut ~[], + label_ribs: @mut ~[], xray_context: NoXray, current_trait_refs: None, @@ -830,13 +830,13 @@ pub struct Resolver { // The current set of local scopes, for values. // FIXME #4948: Reuse ribs to avoid allocation. - value_ribs: ~[@Rib], + value_ribs: @mut ~[@Rib], // The current set of local scopes, for types. - type_ribs: ~[@Rib], + type_ribs: @mut ~[@Rib], // The current set of local scopes, for labels. - label_ribs: ~[@Rib], + label_ribs: @mut ~[@Rib], // Whether the current context is an X-ray context. An X-ray context is // allowed to access private names of any module. @@ -4313,19 +4313,18 @@ pub impl Resolver { } pat_struct(path, _, _) => { - let structs: &mut HashSet = &mut self.structs; match self.resolve_path(path, TypeNS, false, visitor) { Some(def_ty(class_id)) - if structs.contains(&class_id) => { + if self.structs.contains(&class_id) => { let class_def = def_struct(class_id); self.record_def(pattern.id, class_def); } - Some(definition @ def_struct(class_id)) - if structs.contains(&class_id) => { + Some(definition @ def_struct(class_id)) => { + assert!(self.structs.contains(&class_id)); self.record_def(pattern.id, definition); } Some(definition @ def_variant(_, variant_id)) - if structs.contains(&variant_id) => { + if self.structs.contains(&variant_id) => { self.record_def(pattern.id, definition); } result => { @@ -4627,12 +4626,12 @@ pub impl Resolver { let search_result; match namespace { ValueNS => { - search_result = self.search_ribs(&mut self.value_ribs, ident, + search_result = self.search_ribs(self.value_ribs, ident, span, DontAllowCapturingSelf); } TypeNS => { - search_result = self.search_ribs(&mut self.type_ribs, ident, + search_result = self.search_ribs(self.type_ribs, ident, span, AllowCapturingSelf); } } @@ -4822,15 +4821,14 @@ pub impl Resolver { expr_struct(path, _, _) => { // Resolve the path to the structure it goes to. - let structs: &mut HashSet = &mut self.structs; match self.resolve_path(path, TypeNS, false, visitor) { Some(def_ty(class_id)) | Some(def_struct(class_id)) - if structs.contains(&class_id) => { + if self.structs.contains(&class_id) => { let class_def = def_struct(class_id); self.record_def(expr.id, class_def); } Some(definition @ def_variant(_, class_id)) - if structs.contains(&class_id) => { + if self.structs.contains(&class_id) => { self.record_def(expr.id, definition); } _ => { @@ -4856,7 +4854,7 @@ pub impl Resolver { } expr_break(Some(label)) | expr_again(Some(label)) => { - match self.search_ribs(&mut self.label_ribs, label, expr.span, + match self.search_ribs(self.label_ribs, label, expr.span, DontAllowCapturingSelf) { None => self.session.span_err(expr.span, diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 44b6212261246..c177d5ab0eb3a 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -244,11 +244,14 @@ fn lookup_vtable(vcx: &VtableContext, // Nothing found. Continue. } Some(implementations) => { - let implementations: &mut ~[@Impl] = *implementations; + let len = { // FIXME(#5074): stage0 requires it + let implementations: &mut ~[@Impl] = *implementations; + implementations.len() + }; // implementations is the list of all impls in scope for // trait_ref. (Usually, there's just one.) - for uint::range(0, implementations.len()) |i| { + for uint::range(0, len) |i| { let im = implementations[i]; // im is one specific impl of trait_ref. diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 573e4bd579011..d779c20b3e81c 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -240,8 +240,8 @@ pub impl CoherenceChecker { fn check_implementation(&self, item: @item, associated_traits: ~[@trait_ref]) { - let self_type = self.crate_context.tcx.tcache.get( - &local_def(item.id)); + let tcx = self.crate_context.tcx; + let self_type = ty::lookup_item_type(tcx, local_def(item.id)); // If there are no traits, then this implementation must have a // base type. @@ -452,10 +452,8 @@ pub impl CoherenceChecker { } fn check_implementation_coherence(&self) { - let coherence_info = &mut self.crate_context.coherence_info; - let extension_methods = &coherence_info.extension_methods; - - for extension_methods.each_key |&trait_id| { + let coherence_info = self.crate_context.coherence_info; + for coherence_info.extension_methods.each_key |&trait_id| { self.check_implementation_coherence_of(trait_id); } } @@ -514,13 +512,16 @@ pub impl CoherenceChecker { } fn iter_impls_of_trait(&self, trait_def_id: def_id, f: &fn(@Impl)) { - let coherence_info = &mut self.crate_context.coherence_info; - let extension_methods = &coherence_info.extension_methods; + let coherence_info = self.crate_context.coherence_info; + let extension_methods = &*coherence_info.extension_methods; match extension_methods.find(&trait_def_id) { Some(impls) => { - let impls: &mut ~[@Impl] = *impls; - for uint::range(0, impls.len()) |i| { + let len = { // FIXME(#5074) stage0 requires this + let impls: &mut ~[@Impl] = *impls; + impls.len() + }; + for uint::range(0, len) |i| { f(impls[i]); } } @@ -1014,7 +1015,7 @@ pub impl CoherenceChecker { // fn populate_destructor_table(&self) { - let coherence_info = &mut self.crate_context.coherence_info; + let coherence_info = self.crate_context.coherence_info; let tcx = self.crate_context.tcx; let drop_trait = tcx.lang_items.drop_trait(); let impls_opt = coherence_info.extension_methods.find(&drop_trait); diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index 2bbcd24595cba..b818f666444f6 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -16,6 +16,7 @@ use middle::typeck::infer::lub::Lub; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::{cres, InferCtxt}; +use middle::typeck::infer::fold_regions_in_sig; use middle::typeck::isr_alist; use syntax::ast; use syntax::ast::{Many, Once, extern_fn, impure_fn, m_const, m_imm, m_mutbl}; @@ -188,7 +189,8 @@ impl Combine for Glb { let new_vars = self.infcx.region_vars.vars_created_since_snapshot(snapshot); let sig1 = - self.infcx.fold_regions_in_sig( + fold_regions_in_sig( + self.infcx.tcx, &sig0, |r, _in_fn| generalize_region(self, snapshot, new_vars, a_isr, a_vars, b_vars, diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs index 8591433801796..34e006c9615a7 100644 --- a/src/librustc/middle/typeck/infer/lub.rs +++ b/src/librustc/middle/typeck/infer/lub.rs @@ -16,6 +16,7 @@ use middle::typeck::infer::lattice::*; use middle::typeck::infer::sub::Sub; use middle::typeck::infer::to_str::InferStr; use middle::typeck::infer::{cres, InferCtxt}; +use middle::typeck::infer::fold_regions_in_sig; use middle::typeck::isr_alist; use util::common::indent; use util::ppaux::mt_to_str; @@ -141,7 +142,8 @@ impl Combine for Lub { let new_vars = self.infcx.region_vars.vars_created_since_snapshot(snapshot); let sig1 = - self.infcx.fold_regions_in_sig( + fold_regions_in_sig( + self.infcx.tcx, &sig0, |r, _in_fn| generalize_region(self, snapshot, new_vars, a_isr, r)); diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 4491b04b382ec..899b8cfd7edeb 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -574,7 +574,7 @@ pub impl InferCtxt { } /// Execute `f` and commit the bindings if successful - fn commit(&mut self, f: &fn() -> Result) -> Result { + fn commit(@mut self, f: &fn() -> Result) -> Result { assert!(!self.in_snapshot()); debug!("commit()"); @@ -589,7 +589,7 @@ pub impl InferCtxt { } /// Execute `f`, unroll bindings on failure - fn try(&mut self, f: &fn() -> Result) -> Result { + fn try(@mut self, f: &fn() -> Result) -> Result { debug!("try()"); do indent { let snapshot = self.start_snapshot(); @@ -603,7 +603,7 @@ pub impl InferCtxt { } /// Execute `f` then unroll any bindings it creates - fn probe(&mut self, f: &fn() -> Result) -> Result { + fn probe(@mut self, f: &fn() -> Result) -> Result { debug!("probe()"); do indent { let snapshot = self.start_snapshot(); @@ -783,15 +783,14 @@ pub impl InferCtxt { }); (fn_sig, isr) } +} - fn fold_regions_in_sig( - &mut self, - fn_sig: &ty::FnSig, - fldr: &fn(r: ty::Region, in_fn: bool) -> ty::Region) -> ty::FnSig - { - do ty::fold_sig(fn_sig) |t| { - ty::fold_regions(self.tcx, t, fldr) - } +pub fn fold_regions_in_sig( + tcx: ty::ctxt, + fn_sig: &ty::FnSig, + fldr: &fn(r: ty::Region, in_fn: bool) -> ty::Region) -> ty::FnSig +{ + do ty::fold_sig(fn_sig) |t| { + ty::fold_regions(tcx, t, fldr) } - -} +} \ No newline at end of file diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 9e34d5c6177e6..1ecb38854c815 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -76,6 +76,9 @@ pub mod middle { } pub mod ty; pub mod subst; + #[cfg(stage0)] #[path = "resolve_stage0.rs"] + pub mod resolve; + #[cfg(not(stage0))] pub mod resolve; #[path = "typeck/mod.rs"] pub mod typeck; diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 7facc181effec..1c822b520f6af 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -355,7 +355,7 @@ pub impl CodeMap { } pub fn span_to_str(&self, sp: span) -> ~str { - let files = &mut *self.files; + let files = &*self.files; if files.len() == 0 && sp == dummy_sp() { return ~"no-location"; } From cce97ab8cb225c9ae5b9e8dca4f96bd750eebdb7 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 2 May 2013 11:33:57 -0700 Subject: [PATCH 148/215] Add test for drop for newtype structs. --- src/test/run-pass/newtype-struct-drop-run.rs | 28 ++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/test/run-pass/newtype-struct-drop-run.rs diff --git a/src/test/run-pass/newtype-struct-drop-run.rs b/src/test/run-pass/newtype-struct-drop-run.rs new file mode 100644 index 0000000000000..dd5da3b09bb69 --- /dev/null +++ b/src/test/run-pass/newtype-struct-drop-run.rs @@ -0,0 +1,28 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Make sure the destructor is run for newtype structs. + +struct Foo(@mut int); + +#[unsafe_destructor] +impl Drop for Foo { + fn finalize(&self) { + ***self = 23; + } +} + +fn main() { + let y = @mut 32; + { + let x = Foo(y); + } + assert_eq!(*y, 23); +} From bd979c1fbf11ffb5b3ff42ca31aa2bfae3082ec6 Mon Sep 17 00:00:00 2001 From: gareth Date: Thu, 2 May 2013 21:19:12 +0100 Subject: [PATCH 149/215] Fix some issues with test_destroy_actually_kills: - it is now cross platform, instead of just unix - it now avoids sleeping (fixing issue #6156) - it now calls force_destroy() when force = true (was a bug) --- src/libcore/run.rs | 52 +++++++++++++++++++++++++++++++++------------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/libcore/run.rs b/src/libcore/run.rs index 0850121d6020d..7e73b3a3f80be 100644 --- a/src/libcore/run.rs +++ b/src/libcore/run.rs @@ -781,7 +781,6 @@ mod tests { use libc; use option::None; use os; - use path::Path; use run::{readclose, writeclose}; use run; @@ -870,34 +869,59 @@ mod tests { p.destroy(); // ...and nor should this (and nor should the destructor) } - #[cfg(unix)] // there is no way to sleep on windows from inside libcore... fn test_destroy_actually_kills(force: bool) { - let path = Path(fmt!("test/core-run-test-destroy-actually-kills-%?.tmp", force)); - os::remove_file(&path); + #[cfg(unix)] + static BLOCK_COMMAND: &'static str = "cat"; - let cmd = fmt!("sleep 5 && echo MurderDeathKill > %s", path.to_str()); - let mut p = run::start_program("sh", [~"-c", cmd]); + #[cfg(windows)] + static BLOCK_COMMAND: &'static str = "cmd"; - p.destroy(); // destroy the program before it has a chance to echo its message + #[cfg(unix)] + fn process_exists(pid: libc::pid_t) -> bool { + run::program_output("ps", [~"-p", pid.to_str()]).out.contains(pid.to_str()) + } - unsafe { - // wait to ensure the program is really destroyed and not just waiting itself - libc::sleep(10); + #[cfg(windows)] + fn process_exists(pid: libc::pid_t) -> bool { + + use libc::types::os::arch::extra::DWORD; + use libc::funcs::extra::kernel32::{CloseHandle, GetExitCodeProcess, OpenProcess}; + use libc::consts::os::extra::{FALSE, PROCESS_QUERY_INFORMATION, STILL_ACTIVE }; + + unsafe { + let proc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid as DWORD); + if proc.is_null() { + return false; + } + // proc will be non-null if the process is alive, or if it died recently + let mut status = 0; + GetExitCodeProcess(proc, &mut status); + CloseHandle(proc); + return status == STILL_ACTIVE; + } } - // the program should not have had chance to echo its message - assert!(!path.exists()); + // this program will stay alive indefinitely trying to read from stdin + let mut p = run::start_program(BLOCK_COMMAND, []); + + assert!(process_exists(p.get_id())); + + if force { + p.force_destroy(); + } else { + p.destroy(); + } + + assert!(!process_exists(p.get_id())); } #[test] - #[cfg(unix)] fn test_unforced_destroy_actually_kills() { test_destroy_actually_kills(false); } #[test] - #[cfg(unix)] fn test_forced_destroy_actually_kills() { test_destroy_actually_kills(true); } From 4999d44d5b244671492fbdc05121416e05f729eb Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 2 May 2013 16:37:28 -0400 Subject: [PATCH 150/215] trans: fix borrow violation --- src/librustc/middle/trans/base.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 7738e97779971..80cedf2372786 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1258,7 +1258,7 @@ pub fn trans_block_cleanups(bcx: block, cleanups: ~[cleanup]) -> block { } pub fn trans_block_cleanups_(bcx: block, - cleanups: ~[cleanup], + cleanups: &[cleanup], /* cleanup_cx: block, */ is_lpad: bool) -> block { let _icx = bcx.insn_ctxt("trans_block_cleanups"); @@ -1317,7 +1317,7 @@ pub fn cleanup_and_leave(bcx: block, dest: sub_cx.llbb }); bcx = trans_block_cleanups_(sub_cx, - block_cleanups(cur), + inf.cleanups, is_lpad); } _ => () From cc62680cc95d2ea733dbdc03c30e5c4c48fdad04 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 2 May 2013 17:08:04 -0400 Subject: [PATCH 151/215] free the borrow list propertly instead of crashing --- src/libcore/cleanup.rs | 5 +++++ src/libcore/unstable/lang.rs | 11 ++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/libcore/cleanup.rs b/src/libcore/cleanup.rs index 1dfe1b22dc4fb..5e2f4af184dc4 100644 --- a/src/libcore/cleanup.rs +++ b/src/libcore/cleanup.rs @@ -15,6 +15,7 @@ use ptr::mut_null; use repr::BoxRepr; use sys::TypeDesc; use cast::transmute; +use unstable::lang::clear_task_borrow_list; #[cfg(notest)] use ptr::to_unsafe_ptr; @@ -179,6 +180,10 @@ pub unsafe fn annihilate() { n_bytes_freed: 0 }; + // Quick hack: we need to free this list upon task exit, and this + // is a convenient place to do it. + clear_task_borrow_list(); + // Pass 1: Make all boxes immortal. // // In this pass, nothing gets freed, so it does not matter whether diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index d25147fcde118..a3e44b5feea4a 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -91,7 +91,16 @@ fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { } } -pub fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { +pub unsafe fn clear_task_borrow_list() { + // pub because it is used by the box annihilator. + let cur_task = rust_get_task(); + let ptr = rustrt::rust_take_task_borrow_list(cur_task); + if !ptr.is_null() { + let _: ~[BorrowRecord] = transmute(ptr); + } +} + +fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { debug_ptr("fail_borrowed: ", box); if !::rt::env::get().debug_borrows { From 32ebaacbc6dcd705562ac96af5c803f574284584 Mon Sep 17 00:00:00 2001 From: Graydon Hoare Date: Thu, 2 May 2013 14:12:55 -0700 Subject: [PATCH 152/215] re-xfail some tests that fail on x86 --- src/test/run-pass/tag-align-dyn-u64.rs | 2 ++ src/test/run-pass/tag-align-dyn-variants.rs | 2 ++ src/test/run-pass/tag-align-u64.rs | 1 + 3 files changed, 5 insertions(+) diff --git a/src/test/run-pass/tag-align-dyn-u64.rs b/src/test/run-pass/tag-align-dyn-u64.rs index 0fdf4e019a775..a09ee23f1478a 100644 --- a/src/test/run-pass/tag-align-dyn-u64.rs +++ b/src/test/run-pass/tag-align-dyn-u64.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test + enum a_tag { a_tag(A) } diff --git a/src/test/run-pass/tag-align-dyn-variants.rs b/src/test/run-pass/tag-align-dyn-variants.rs index 96921f2a065c2..cd94bd30c21e0 100644 --- a/src/test/run-pass/tag-align-dyn-variants.rs +++ b/src/test/run-pass/tag-align-dyn-variants.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test + enum a_tag { varA(A), varB(B) diff --git a/src/test/run-pass/tag-align-u64.rs b/src/test/run-pass/tag-align-u64.rs index 56d384e5fdb76..ea60f389663cf 100644 --- a/src/test/run-pass/tag-align-u64.rs +++ b/src/test/run-pass/tag-align-u64.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// xfail-test enum a_tag { a_tag(u64) From 6f2e429041da1990a91477e37316c73729cb6fe2 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Mon, 29 Apr 2013 15:23:04 -0700 Subject: [PATCH 153/215] libstd: De-mut arena --- src/libstd/arena.rs | 115 ++++++++++++++++++++++++-------------------- src/libstd/list.rs | 25 ++++++++++ 2 files changed, 89 insertions(+), 51 deletions(-) diff --git a/src/libstd/arena.rs b/src/libstd/arena.rs index 8e2c734504512..bea7935d5c3a4 100644 --- a/src/libstd/arena.rs +++ b/src/libstd/arena.rs @@ -32,11 +32,11 @@ // overhead when initializing plain-old-data and means we don't need // to waste time running the destructors of POD. +use list::{MutList, MutCons, MutNil}; use list; -use list::{List, Cons, Nil}; use core::at_vec; -use core::cast::transmute; +use core::cast::{transmute, transmute_mut_region}; use core::cast; use core::libc::size_t; use core::ptr; @@ -74,7 +74,7 @@ static tydesc_drop_glue_index: size_t = 3 as size_t; // will always stay at 0. struct Chunk { data: @[u8], - mut fill: uint, + fill: uint, is_pod: bool, } @@ -82,9 +82,9 @@ pub struct Arena { // The head is seperated out from the list as a unbenchmarked // microoptimization, to avoid needing to case on the list to // access the head. - priv mut head: Chunk, - priv mut pod_head: Chunk, - priv mut chunks: @List, + priv head: Chunk, + priv pod_head: Chunk, + priv chunks: @mut MutList, } #[unsafe_destructor] @@ -92,8 +92,10 @@ impl Drop for Arena { fn finalize(&self) { unsafe { destroy_chunk(&self.head); - for list::each(self.chunks) |chunk| { - if !chunk.is_pod { destroy_chunk(chunk); } + for self.chunks.each |chunk| { + if !chunk.is_pod { + destroy_chunk(chunk); + } } } } @@ -113,7 +115,7 @@ pub fn arena_with_size(initial_size: uint) -> Arena { Arena { head: chunk(initial_size, false), pod_head: chunk(initial_size, true), - chunks: @Nil, + chunks: @mut MutNil, } } @@ -170,11 +172,11 @@ unsafe fn un_bitpack_tydesc_ptr(p: uint) -> (*TypeDesc, bool) { pub impl Arena { // Functions for the POD part of the arena - priv fn alloc_pod_grow(&self, n_bytes: uint, align: uint) -> *u8 { + priv fn alloc_pod_grow(&mut self, n_bytes: uint, align: uint) -> *u8 { // Allocate a new chunk. let chunk_size = at_vec::capacity(self.pod_head.data); let new_min_chunk_size = uint::max(n_bytes, chunk_size); - self.chunks = @Cons(copy self.pod_head, self.chunks); + self.chunks = @mut MutCons(copy self.pod_head, self.chunks); self.pod_head = chunk(uint::next_power_of_two(new_min_chunk_size + 1u), true); @@ -182,27 +184,28 @@ pub impl Arena { } #[inline(always)] - priv fn alloc_pod_inner(&self, n_bytes: uint, align: uint) -> *u8 { - let head = &mut self.pod_head; + priv fn alloc_pod_inner(&mut self, n_bytes: uint, align: uint) -> *u8 { + unsafe { + // XXX: Borrow check + let head = transmute_mut_region(&mut self.pod_head); - let start = round_up_to(head.fill, align); - let end = start + n_bytes; - if end > at_vec::capacity(head.data) { - return self.alloc_pod_grow(n_bytes, align); - } - head.fill = end; + let start = round_up_to(head.fill, align); + let end = start + n_bytes; + if end > at_vec::capacity(head.data) { + return self.alloc_pod_grow(n_bytes, align); + } + head.fill = end; - //debug!("idx = %u, size = %u, align = %u, fill = %u", - // start, n_bytes, align, head.fill); + //debug!("idx = %u, size = %u, align = %u, fill = %u", + // start, n_bytes, align, head.fill); - unsafe { ptr::offset(vec::raw::to_ptr(head.data), start) } } #[inline(always)] #[cfg(stage0)] - priv fn alloc_pod(&self, op: &fn() -> T) -> &'self T { + priv fn alloc_pod(&mut self, op: &fn() -> T) -> &'self T { unsafe { let tydesc = sys::get_type_desc::(); let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align); @@ -216,7 +219,7 @@ pub impl Arena { #[cfg(stage1)] #[cfg(stage2)] #[cfg(stage3)] - priv fn alloc_pod<'a, T>(&'a self, op: &fn() -> T) -> &'a T { + priv fn alloc_pod<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T { unsafe { let tydesc = sys::get_type_desc::(); let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align); @@ -227,11 +230,12 @@ pub impl Arena { } // Functions for the non-POD part of the arena - priv fn alloc_nonpod_grow(&self, n_bytes: uint, align: uint) -> (*u8, *u8) { + priv fn alloc_nonpod_grow(&mut self, n_bytes: uint, align: uint) + -> (*u8, *u8) { // Allocate a new chunk. let chunk_size = at_vec::capacity(self.head.data); let new_min_chunk_size = uint::max(n_bytes, chunk_size); - self.chunks = @Cons(copy self.head, self.chunks); + self.chunks = @mut MutCons(copy self.head, self.chunks); self.head = chunk(uint::next_power_of_two(new_min_chunk_size + 1u), false); @@ -239,22 +243,23 @@ pub impl Arena { } #[inline(always)] - priv fn alloc_nonpod_inner(&self, n_bytes: uint, align: uint) -> (*u8, *u8) { - let head = &mut self.head; - - let tydesc_start = head.fill; - let after_tydesc = head.fill + sys::size_of::<*TypeDesc>(); - let start = round_up_to(after_tydesc, align); - let end = start + n_bytes; - if end > at_vec::capacity(head.data) { - return self.alloc_nonpod_grow(n_bytes, align); - } - head.fill = round_up_to(end, sys::pref_align_of::<*TypeDesc>()); + priv fn alloc_nonpod_inner(&mut self, n_bytes: uint, align: uint) + -> (*u8, *u8) { + unsafe { + let head = transmute_mut_region(&mut self.head); + + let tydesc_start = head.fill; + let after_tydesc = head.fill + sys::size_of::<*TypeDesc>(); + let start = round_up_to(after_tydesc, align); + let end = start + n_bytes; + if end > at_vec::capacity(head.data) { + return self.alloc_nonpod_grow(n_bytes, align); + } + head.fill = round_up_to(end, sys::pref_align_of::<*TypeDesc>()); - //debug!("idx = %u, size = %u, align = %u, fill = %u", - // start, n_bytes, align, head.fill); + //debug!("idx = %u, size = %u, align = %u, fill = %u", + // start, n_bytes, align, head.fill); - unsafe { let buf = vec::raw::to_ptr(head.data); return (ptr::offset(buf, tydesc_start), ptr::offset(buf, start)); } @@ -262,7 +267,7 @@ pub impl Arena { #[inline(always)] #[cfg(stage0)] - priv fn alloc_nonpod(&self, op: &fn() -> T) -> &'self T { + priv fn alloc_nonpod(&mut self, op: &fn() -> T) -> &'self T { unsafe { let tydesc = sys::get_type_desc::(); let (ty_ptr, ptr) = @@ -286,7 +291,7 @@ pub impl Arena { #[cfg(stage1)] #[cfg(stage2)] #[cfg(stage3)] - priv fn alloc_nonpod<'a, T>(&'a self, op: &fn() -> T) -> &'a T { + priv fn alloc_nonpod<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T { unsafe { let tydesc = sys::get_type_desc::(); let (ty_ptr, ptr) = @@ -309,13 +314,16 @@ pub impl Arena { // The external interface #[inline(always)] #[cfg(stage0)] - fn alloc(&self, op: &fn() -> T) -> &'self T { + fn alloc(&mut self, op: &fn() -> T) -> &'self T { unsafe { + // XXX: Borrow check + let this = transmute_mut_region(self); if !rusti::needs_drop::() { - self.alloc_pod(op) - } else { - self.alloc_nonpod(op) + return this.alloc_pod(op); } + // XXX: Borrow check + let this = transmute_mut_region(self); + this.alloc_nonpod(op) } } @@ -324,13 +332,16 @@ pub impl Arena { #[cfg(stage1)] #[cfg(stage2)] #[cfg(stage3)] - fn alloc<'a, T>(&'a self, op: &fn() -> T) -> &'a T { + fn alloc<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T { unsafe { + // XXX: Borrow check + let this = transmute_mut_region(self); if !rusti::needs_drop::() { - self.alloc_pod(op) - } else { - self.alloc_nonpod(op) + return this.alloc_pod(op); } + // XXX: Borrow check + let this = transmute_mut_region(self); + this.alloc_nonpod(op) } } } @@ -348,7 +359,9 @@ fn test_arena_destructors() { } } -#[test] #[should_fail] #[ignore(cfg(windows))] +#[test] +#[should_fail] +#[ignore(cfg(windows))] fn test_arena_destructors_fail() { let arena = Arena(); // Put some stuff in the arena. diff --git a/src/libstd/list.rs b/src/libstd/list.rs index 2b6fa0bc05691..8d15508b26e05 100644 --- a/src/libstd/list.rs +++ b/src/libstd/list.rs @@ -16,6 +16,12 @@ pub enum List { Nil, } +#[deriving(Eq)] +pub enum MutList { + MutCons(T, @mut MutList), + MutNil, +} + /// Create a list from a vector pub fn from_vec(v: &[T]) -> @List { vec::foldr(v, @Nil::, |h, t| @Cons(*h, t)) @@ -147,6 +153,25 @@ pub fn each(l: @List, f: &fn(&T) -> bool) { } } +impl MutList { + /// Iterate over a mutable list + pub fn each(@mut self, f: &fn(&mut T) -> bool) { + let mut cur = self; + loop { + let borrowed = &mut *cur; + cur = match *borrowed { + MutCons(ref mut hd, tl) => { + if !f(hd) { + return; + } + tl + } + MutNil => break + } + } + } +} + #[cfg(test)] mod tests { use list::*; From dc5df61bc1914224d50d92cdd5599b6337ac68f2 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Wed, 1 May 2013 17:54:54 -0700 Subject: [PATCH 154/215] librustc: Update the serializer to work properly with INHTWAMA, removing mutable fields in the process --- src/librustc/metadata/decoder.rs | 9 + src/librustc/metadata/encoder.rs | 1638 +++++++++++++++-- src/librustc/middle/astencode.rs | 888 ++++++++- src/libstd/arena.rs | 4 +- src/libstd/ebml.rs | 818 +++++++- src/libstd/flatpipes.rs | 33 +- src/libstd/json.rs | 871 ++++++++- src/libstd/serialize.rs | 1145 +++++++++++- src/libstd/workcache.rs | 53 +- src/libsyntax/ast.rs | 38 +- src/libsyntax/codemap.rs | 17 + src/libsyntax/ext/auto_encode.rs | 304 +-- src/libsyntax/ext/deriving/decodable.rs | 49 +- src/libsyntax/ext/deriving/encodable.rs | 42 +- src/libsyntax/parse/mod.rs | 3 +- src/test/bench/shootout-binarytrees.rs | 23 +- src/test/run-pass/auto-encode.rs | 7 +- src/test/run-pass/issue-4036.rs | 3 +- src/test/run-pass/placement-new-arena.rs | 3 +- src/test/run-pass/regions-mock-trans-impls.rs | 28 +- 20 files changed, 5381 insertions(+), 595 deletions(-) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 61454c802cc9a..1be49528b9e79 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -272,12 +272,21 @@ fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd, @bounds } +#[cfg(stage0)] fn item_ty_region_param(item: ebml::Doc) -> Option { reader::maybe_get_doc(item, tag_region_param).map(|doc| { Decodable::decode(&reader::Decoder(*doc)) }) } +#[cfg(not(stage0))] +fn item_ty_region_param(item: ebml::Doc) -> Option { + reader::maybe_get_doc(item, tag_region_param).map(|doc| { + let mut decoder = reader::Decoder(*doc); + Decodable::decode(&mut decoder) + }) +} + fn item_ty_param_count(item: ebml::Doc) -> uint { let mut n = 0u; reader::tagged_docs(item, tag_items_data_item_ty_param_bounds, diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 2a4334781e4dc..77373076137b9 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -42,11 +42,18 @@ use writer = std::ebml::writer; // used by astencode: type abbrev_map = @mut HashMap; +#[cfg(stage0)] pub type encode_inlined_item = @fn(ecx: @EncodeContext, ebml_w: &writer::Encoder, path: &[ast_map::path_elt], ii: ast::inlined_item); +#[cfg(not(stage0))] +pub type encode_inlined_item = @fn(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + path: &[ast_map::path_elt], + ii: ast::inlined_item); + pub struct EncodeParams { diag: @span_handler, tcx: ty::ctxt, @@ -91,21 +98,47 @@ pub fn reachable(ecx: @EncodeContext, id: node_id) -> bool { ecx.reachable.contains(&id) } +#[cfg(stage0)] fn encode_name(ecx: @EncodeContext, ebml_w: &writer::Encoder, name: ident) { ebml_w.wr_tagged_str(tag_paths_data_name, *ecx.tcx.sess.str_of(name)); } -fn encode_impl_type_basename(ecx: @EncodeContext, ebml_w: &writer::Encoder, +#[cfg(not(stage0))] +fn encode_name(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + name: ident) { + ebml_w.wr_tagged_str(tag_paths_data_name, *ecx.tcx.sess.str_of(name)); +} + +#[cfg(stage0)] +fn encode_impl_type_basename(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + name: ident) { + ebml_w.wr_tagged_str(tag_item_impl_type_basename, + *ecx.tcx.sess.str_of(name)); +} + +#[cfg(not(stage0))] +fn encode_impl_type_basename(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, name: ident) { ebml_w.wr_tagged_str(tag_item_impl_type_basename, *ecx.tcx.sess.str_of(name)); } +#[cfg(stage0)] pub fn encode_def_id(ebml_w: &writer::Encoder, id: def_id) { ebml_w.wr_tagged_str(tag_def_id, def_to_str(id)); } -fn encode_region_param(ecx: @EncodeContext, ebml_w: &writer::Encoder, +#[cfg(not(stage0))] +pub fn encode_def_id(ebml_w: &mut writer::Encoder, id: def_id) { + ebml_w.wr_tagged_str(tag_def_id, def_to_str(id)); +} + +#[cfg(stage0)] +fn encode_region_param(ecx: @EncodeContext, + ebml_w: &writer::Encoder, it: @ast::item) { let opt_rp = ecx.tcx.region_paramd_items.find(&it.id); for opt_rp.each |rp| { @@ -115,6 +148,19 @@ fn encode_region_param(ecx: @EncodeContext, ebml_w: &writer::Encoder, } } +#[cfg(not(stage0))] +fn encode_region_param(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + it: @ast::item) { + let opt_rp = ecx.tcx.region_paramd_items.find(&it.id); + for opt_rp.each |rp| { + ebml_w.start_tag(tag_region_param); + rp.encode(ebml_w); + ebml_w.end_tag(); + } +} + +#[cfg(stage0)] fn encode_mutability(ebml_w: &writer::Encoder, mt: struct_mutability) { do ebml_w.wr_tag(tag_struct_mut) { let val = match mt { @@ -125,13 +171,45 @@ fn encode_mutability(ebml_w: &writer::Encoder, mt: struct_mutability) { } } +#[cfg(not(stage0))] +fn encode_mutability(ebml_w: &mut writer::Encoder, mt: struct_mutability) { + ebml_w.start_tag(tag_struct_mut); + let val = match mt { + struct_immutable => 'a', + struct_mutable => 'm' + }; + ebml_w.writer.write(&[val as u8]); + ebml_w.end_tag(); +} + struct entry { val: T, pos: uint } -fn add_to_index(ecx: @EncodeContext, ebml_w: &writer::Encoder, path: &[ident], - index: &mut ~[entry<~str>], name: ident) { +#[cfg(stage0)] +fn add_to_index(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + path: &[ident], + index: &mut ~[entry<~str>], + name: ident) { + let mut full_path = ~[]; + full_path.push_all(path); + full_path.push(name); + index.push( + entry { + val: ast_util::path_name_i(full_path, + ecx.tcx.sess.parse_sess.interner), + pos: ebml_w.writer.tell() + }); +} + +#[cfg(not(stage0))] +fn add_to_index(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + path: &[ident], + index: &mut ~[entry<~str>], + name: ident) { let mut full_path = ~[]; full_path.push_all(path); full_path.push(name); @@ -143,11 +221,28 @@ fn add_to_index(ecx: @EncodeContext, ebml_w: &writer::Encoder, path: &[ident], }); } +#[cfg(stage0)] fn encode_trait_ref(ebml_w: &writer::Encoder, ecx: @EncodeContext, trait_ref: &ty::TraitRef, - tag: uint) -{ + tag: uint) { + let ty_str_ctxt = @tyencode::ctxt { + diag: ecx.diag, + ds: def_to_str, + tcx: ecx.tcx, + reachable: |a| reachable(ecx, a), + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + + ebml_w.start_tag(tag); + tyencode::enc_trait_ref(ebml_w.writer, ty_str_ctxt, trait_ref); + ebml_w.end_tag(); +} + +#[cfg(not(stage0))] +fn encode_trait_ref(ebml_w: &mut writer::Encoder, + ecx: @EncodeContext, + trait_ref: &ty::TraitRef, + tag: uint) { let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, ds: def_to_str, @@ -161,14 +256,26 @@ fn encode_trait_ref(ebml_w: &writer::Encoder, } // Item info table encoding +#[cfg(stage0)] fn encode_family(ebml_w: &writer::Encoder, c: char) { ebml_w.start_tag(tag_items_data_item_family); ebml_w.writer.write(&[c as u8]); ebml_w.end_tag(); } -pub fn def_to_str(did: def_id) -> ~str { fmt!("%d:%d", did.crate, did.node) } +// Item info table encoding +#[cfg(not(stage0))] +fn encode_family(ebml_w: &mut writer::Encoder, c: char) { + ebml_w.start_tag(tag_items_data_item_family); + ebml_w.writer.write(&[c as u8]); + ebml_w.end_tag(); +} + +pub fn def_to_str(did: def_id) -> ~str { + fmt!("%d:%d", did.crate, did.node) +} +#[cfg(stage0)] fn encode_ty_type_param_defs(ebml_w: &writer::Encoder, ecx: @EncodeContext, params: @~[ty::TypeParameterDef], @@ -186,6 +293,25 @@ fn encode_ty_type_param_defs(ebml_w: &writer::Encoder, } } +#[cfg(not(stage0))] +fn encode_ty_type_param_defs(ebml_w: &mut writer::Encoder, + ecx: @EncodeContext, + params: @~[ty::TypeParameterDef], + tag: uint) { + let ty_str_ctxt = @tyencode::ctxt { + diag: ecx.diag, + ds: def_to_str, + tcx: ecx.tcx, + reachable: |a| reachable(ecx, a), + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + for params.each |param| { + ebml_w.start_tag(tag); + tyencode::enc_type_param_def(ebml_w.writer, ty_str_ctxt, param); + ebml_w.end_tag(); + } +} + +#[cfg(stage0)] fn encode_type_param_bounds(ebml_w: &writer::Encoder, ecx: @EncodeContext, params: &OptVec) { @@ -195,13 +321,31 @@ fn encode_type_param_bounds(ebml_w: &writer::Encoder, tag_items_data_item_ty_param_bounds); } +#[cfg(not(stage0))] +fn encode_type_param_bounds(ebml_w: &mut writer::Encoder, + ecx: @EncodeContext, + params: &OptVec) { + let ty_param_defs = + @params.map_to_vec(|param| *ecx.tcx.ty_param_defs.get(¶m.id)); + encode_ty_type_param_defs(ebml_w, ecx, ty_param_defs, + tag_items_data_item_ty_param_bounds); +} +#[cfg(stage0)] fn encode_variant_id(ebml_w: &writer::Encoder, vid: def_id) { ebml_w.start_tag(tag_items_data_item_variant); ebml_w.writer.write(str::to_bytes(def_to_str(vid))); ebml_w.end_tag(); } +#[cfg(not(stage0))] +fn encode_variant_id(ebml_w: &mut writer::Encoder, vid: def_id) { + ebml_w.start_tag(tag_items_data_item_variant); + ebml_w.writer.write(str::to_bytes(def_to_str(vid))); + ebml_w.end_tag(); +} + +#[cfg(stage0)] pub fn write_type(ecx: @EncodeContext, ebml_w: &writer::Encoder, typ: ty::t) { let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, @@ -212,7 +356,35 @@ pub fn write_type(ecx: @EncodeContext, ebml_w: &writer::Encoder, typ: ty::t) { tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ); } -pub fn write_vstore(ecx: @EncodeContext, ebml_w: &writer::Encoder, +#[cfg(not(stage0))] +pub fn write_type(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + typ: ty::t) { + let ty_str_ctxt = @tyencode::ctxt { + diag: ecx.diag, + ds: def_to_str, + tcx: ecx.tcx, + reachable: |a| reachable(ecx, a), + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ); +} + +#[cfg(stage0)] +pub fn write_vstore(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + vstore: ty::vstore) { + let ty_str_ctxt = @tyencode::ctxt { + diag: ecx.diag, + ds: def_to_str, + tcx: ecx.tcx, + reachable: |a| reachable(ecx, a), + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + tyencode::enc_vstore(ebml_w.writer, ty_str_ctxt, vstore); +} + +#[cfg(not(stage0))] +pub fn write_vstore(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, vstore: ty::vstore) { let ty_str_ctxt = @tyencode::ctxt { diag: ecx.diag, @@ -223,16 +395,37 @@ pub fn write_vstore(ecx: @EncodeContext, ebml_w: &writer::Encoder, tyencode::enc_vstore(ebml_w.writer, ty_str_ctxt, vstore); } +#[cfg(stage0)] fn encode_type(ecx: @EncodeContext, ebml_w: &writer::Encoder, typ: ty::t) { ebml_w.start_tag(tag_items_data_item_type); write_type(ecx, ebml_w, typ); ebml_w.end_tag(); } +#[cfg(not(stage0))] +fn encode_type(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + typ: ty::t) { + ebml_w.start_tag(tag_items_data_item_type); + write_type(ecx, ebml_w, typ); + ebml_w.end_tag(); +} + +#[cfg(stage0)] fn encode_transformed_self_ty(ecx: @EncodeContext, ebml_w: &writer::Encoder, - opt_typ: Option) -{ + opt_typ: Option) { + for opt_typ.each |&typ| { + ebml_w.start_tag(tag_item_method_transformed_self_ty); + write_type(ecx, ebml_w, typ); + ebml_w.end_tag(); + } +} + +#[cfg(not(stage0))] +fn encode_transformed_self_ty(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + opt_typ: Option) { for opt_typ.each |&typ| { ebml_w.start_tag(tag_item_method_transformed_self_ty); write_type(ecx, ebml_w, typ); @@ -240,10 +433,27 @@ fn encode_transformed_self_ty(ecx: @EncodeContext, } } +#[cfg(stage0)] fn encode_method_fty(ecx: @EncodeContext, ebml_w: &writer::Encoder, - typ: &ty::BareFnTy) -{ + typ: &ty::BareFnTy) { + ebml_w.start_tag(tag_item_method_fty); + + let ty_str_ctxt = @tyencode::ctxt { + diag: ecx.diag, + ds: def_to_str, + tcx: ecx.tcx, + reachable: |a| reachable(ecx, a), + abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; + tyencode::enc_bare_fn_ty(ebml_w.writer, ty_str_ctxt, typ); + + ebml_w.end_tag(); +} + +#[cfg(not(stage0))] +fn encode_method_fty(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + typ: &ty::BareFnTy) { ebml_w.start_tag(tag_item_method_fty); let ty_str_ctxt = @tyencode::ctxt { @@ -257,6 +467,7 @@ fn encode_method_fty(ecx: @EncodeContext, ebml_w.end_tag(); } +#[cfg(stage0)] fn encode_symbol(ecx: @EncodeContext, ebml_w: &writer::Encoder, id: node_id) { ebml_w.start_tag(tag_items_data_item_symbol); match ecx.item_symbols.find(&id) { @@ -272,28 +483,123 @@ fn encode_symbol(ecx: @EncodeContext, ebml_w: &writer::Encoder, id: node_id) { ebml_w.end_tag(); } -fn encode_discriminant(ecx: @EncodeContext, ebml_w: &writer::Encoder, +#[cfg(not(stage0))] +fn encode_symbol(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + id: node_id) { + ebml_w.start_tag(tag_items_data_item_symbol); + match ecx.item_symbols.find(&id) { + Some(x) => { + debug!("encode_symbol(id=%?, str=%s)", id, *x); + ebml_w.writer.write(str::to_bytes(*x)); + } + None => { + ecx.diag.handler().bug( + fmt!("encode_symbol: id not found %d", id)); + } + } + ebml_w.end_tag(); +} + +#[cfg(stage0)] +fn encode_discriminant(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + id: node_id) { + ebml_w.start_tag(tag_items_data_item_symbol); + ebml_w.writer.write(str::to_bytes(**ecx.discrim_symbols.get(&id))); + ebml_w.end_tag(); +} + +#[cfg(not(stage0))] +fn encode_discriminant(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, id: node_id) { ebml_w.start_tag(tag_items_data_item_symbol); ebml_w.writer.write(str::to_bytes(**ecx.discrim_symbols.get(&id))); ebml_w.end_tag(); } -fn encode_disr_val(_ecx: @EncodeContext, ebml_w: &writer::Encoder, +#[cfg(stage0)] +fn encode_disr_val(_: @EncodeContext, + ebml_w: &writer::Encoder, disr_val: int) { ebml_w.start_tag(tag_disr_val); ebml_w.writer.write(str::to_bytes(int::to_str(disr_val))); ebml_w.end_tag(); } +#[cfg(not(stage0))] +fn encode_disr_val(_: @EncodeContext, + ebml_w: &mut writer::Encoder, + disr_val: int) { + ebml_w.start_tag(tag_disr_val); + ebml_w.writer.write(str::to_bytes(int::to_str(disr_val))); + ebml_w.end_tag(); +} + +#[cfg(stage0)] fn encode_parent_item(ebml_w: &writer::Encoder, id: def_id) { ebml_w.start_tag(tag_items_data_parent_item); ebml_w.writer.write(str::to_bytes(def_to_str(id))); ebml_w.end_tag(); } -fn encode_enum_variant_info(ecx: @EncodeContext, ebml_w: &writer::Encoder, - id: node_id, variants: &[variant], +#[cfg(not(stage0))] +fn encode_parent_item(ebml_w: &mut writer::Encoder, id: def_id) { + ebml_w.start_tag(tag_items_data_parent_item); + ebml_w.writer.write(str::to_bytes(def_to_str(id))); + ebml_w.end_tag(); +} + +#[cfg(stage0)] +fn encode_enum_variant_info(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + id: node_id, + variants: &[variant], + path: &[ast_map::path_elt], + index: @mut ~[entry], + generics: &ast::Generics) { + debug!("encode_enum_variant_info(id=%?)", id); + + let mut disr_val = 0; + let mut i = 0; + let vi = ty::enum_variants(ecx.tcx, + ast::def_id { crate: local_crate, node: id }); + for variants.each |variant| { + index.push(entry {val: variant.node.id, pos: ebml_w.writer.tell()}); + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(variant.node.id)); + encode_family(ebml_w, 'v'); + encode_name(ecx, ebml_w, variant.node.name); + encode_parent_item(ebml_w, local_def(id)); + encode_type(ecx, ebml_w, + node_id_to_type(ecx.tcx, variant.node.id)); + match variant.node.kind { + ast::tuple_variant_kind(ref args) + if args.len() > 0 && generics.ty_params.len() == 0 => { + encode_symbol(ecx, ebml_w, variant.node.id); + } + ast::tuple_variant_kind(_) | ast::struct_variant_kind(_) => {} + } + encode_discriminant(ecx, ebml_w, variant.node.id); + if vi[i].disr_val != disr_val { + encode_disr_val(ecx, ebml_w, vi[i].disr_val); + disr_val = vi[i].disr_val; + } + encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); + encode_path(ecx, ebml_w, path, + ast_map::path_name(variant.node.name)); + ebml_w.end_tag(); + disr_val += 1; + i += 1; + } +} + +#[cfg(not(stage0))] +fn encode_enum_variant_info(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + id: node_id, + variants: &[variant], path: &[ast_map::path_elt], index: @mut ~[entry], generics: &ast::Generics) { @@ -333,8 +639,11 @@ fn encode_enum_variant_info(ecx: @EncodeContext, ebml_w: &writer::Encoder, } } -fn encode_path(ecx: @EncodeContext, ebml_w: &writer::Encoder, - path: &[ast_map::path_elt], name: ast_map::path_elt) { +#[cfg(stage0)] +fn encode_path(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + path: &[ast_map::path_elt], + name: ast_map::path_elt) { fn encode_path_elt(ecx: @EncodeContext, ebml_w: &writer::Encoder, elt: ast_map::path_elt) { let (tag, name) = match elt { @@ -354,8 +663,37 @@ fn encode_path(ecx: @EncodeContext, ebml_w: &writer::Encoder, } } -fn encode_info_for_mod(ecx: @EncodeContext, ebml_w: &writer::Encoder, - md: &_mod, id: node_id, path: &[ast_map::path_elt], +#[cfg(not(stage0))] +fn encode_path(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + path: &[ast_map::path_elt], + name: ast_map::path_elt) { + fn encode_path_elt(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + elt: ast_map::path_elt) { + let (tag, name) = match elt { + ast_map::path_mod(name) => (tag_path_elt_mod, name), + ast_map::path_name(name) => (tag_path_elt_name, name) + }; + + ebml_w.wr_tagged_str(tag, *ecx.tcx.sess.str_of(name)); + } + + ebml_w.start_tag(tag_path); + ebml_w.wr_tagged_u32(tag_path_len, (path.len() + 1) as u32); + for path.each |pe| { + encode_path_elt(ecx, ebml_w, *pe); + } + encode_path_elt(ecx, ebml_w, name); + ebml_w.end_tag(); +} + +#[cfg(stage0)] +fn encode_info_for_mod(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + md: &_mod, + id: node_id, + path: &[ast_map::path_elt], name: ident) { ebml_w.start_tag(tag_items_data_item); encode_def_id(ebml_w, local_def(id)); @@ -412,32 +750,164 @@ fn encode_info_for_mod(ecx: @EncodeContext, ebml_w: &writer::Encoder, ebml_w.end_tag(); } -fn encode_struct_field_family(ebml_w: &writer::Encoder, - visibility: visibility) { - encode_family(ebml_w, match visibility { - public => 'g', - private => 'j', - inherited => 'N' - }); -} - -fn encode_visibility(ebml_w: &writer::Encoder, visibility: visibility) { - ebml_w.start_tag(tag_items_data_item_visibility); - let ch = match visibility { - public => 'y', - private => 'n', - inherited => 'i', - }; - ebml_w.wr_str(str::from_char(ch)); - ebml_w.end_tag(); -} +#[cfg(not(stage0))] +fn encode_info_for_mod(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + md: &_mod, + id: node_id, + path: &[ast_map::path_elt], + name: ident) { + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(id)); + encode_family(ebml_w, 'm'); + encode_name(ecx, ebml_w, name); + debug!("(encoding info for module) encoding info for module ID %d", id); -fn encode_self_type(ebml_w: &writer::Encoder, self_type: ast::self_ty_) { - ebml_w.start_tag(tag_item_trait_method_self_ty); + // Encode info about all the module children. + for md.items.each |item| { + match item.node { + item_impl(*) => { + let (ident, did) = (item.ident, item.id); + debug!("(encoding info for module) ... encoding impl %s \ + (%?/%?)", + *ecx.tcx.sess.str_of(ident), + did, + ast_map::node_id_to_str(ecx.tcx.items, did, ecx.tcx + .sess.parse_sess.interner)); - // Encode the base self type. - match self_type { - sty_static => { + ebml_w.start_tag(tag_mod_impl); + ebml_w.wr_str(def_to_str(local_def(did))); + ebml_w.end_tag(); + } + _ => {} // FIXME #4573: Encode these too. + } + } + + encode_path(ecx, ebml_w, path, ast_map::path_mod(name)); + + // Encode the reexports of this module. + debug!("(encoding info for module) encoding reexports for %d", id); + match ecx.reexports2.find(&id) { + Some(ref exports) => { + debug!("(encoding info for module) found reexports for %d", id); + for exports.each |exp| { + debug!("(encoding info for module) reexport '%s' for %d", + *exp.name, id); + ebml_w.start_tag(tag_items_data_item_reexport); + ebml_w.start_tag(tag_items_data_item_reexport_def_id); + ebml_w.wr_str(def_to_str(exp.def_id)); + ebml_w.end_tag(); + ebml_w.start_tag(tag_items_data_item_reexport_name); + ebml_w.wr_str(*exp.name); + ebml_w.end_tag(); + ebml_w.end_tag(); + } + } + None => { + debug!("(encoding info for module) found no reexports for %d", + id); + } + } + + ebml_w.end_tag(); +} + +#[cfg(stage0)] +fn encode_struct_field_family(ebml_w: &writer::Encoder, + visibility: visibility) { + encode_family(ebml_w, match visibility { + public => 'g', + private => 'j', + inherited => 'N' + }); +} + +#[cfg(not(stage0))] +fn encode_struct_field_family(ebml_w: &mut writer::Encoder, + visibility: visibility) { + encode_family(ebml_w, match visibility { + public => 'g', + private => 'j', + inherited => 'N' + }); +} + +#[cfg(stage0)] +fn encode_visibility(ebml_w: &writer::Encoder, visibility: visibility) { + ebml_w.start_tag(tag_items_data_item_visibility); + let ch = match visibility { + public => 'y', + private => 'n', + inherited => 'i', + }; + ebml_w.wr_str(str::from_char(ch)); + ebml_w.end_tag(); +} + +#[cfg(not(stage0))] +fn encode_visibility(ebml_w: &mut writer::Encoder, visibility: visibility) { + ebml_w.start_tag(tag_items_data_item_visibility); + let ch = match visibility { + public => 'y', + private => 'n', + inherited => 'i', + }; + ebml_w.wr_str(str::from_char(ch)); + ebml_w.end_tag(); +} + +#[cfg(stage0)] +fn encode_self_type(ebml_w: &writer::Encoder, self_type: ast::self_ty_) { + ebml_w.start_tag(tag_item_trait_method_self_ty); + + // Encode the base self type. + match self_type { + sty_static => { + ebml_w.writer.write(&[ 's' as u8 ]); + } + sty_value => { + ebml_w.writer.write(&[ 'v' as u8 ]); + } + sty_region(_, m) => { + // FIXME(#4846) encode custom lifetime + ebml_w.writer.write(&[ '&' as u8 ]); + encode_mutability(ebml_w, m); + } + sty_box(m) => { + ebml_w.writer.write(&[ '@' as u8 ]); + encode_mutability(ebml_w, m); + } + sty_uniq(m) => { + ebml_w.writer.write(&[ '~' as u8 ]); + encode_mutability(ebml_w, m); + } + } + + ebml_w.end_tag(); + + fn encode_mutability(ebml_w: &writer::Encoder, + m: ast::mutability) { + match m { + m_imm => { + ebml_w.writer.write(&[ 'i' as u8 ]); + } + m_mutbl => { + ebml_w.writer.write(&[ 'm' as u8 ]); + } + m_const => { + ebml_w.writer.write(&[ 'c' as u8 ]); + } + } + } +} + +#[cfg(not(stage0))] +fn encode_self_type(ebml_w: &mut writer::Encoder, self_type: ast::self_ty_) { + ebml_w.start_tag(tag_item_trait_method_self_ty); + + // Encode the base self type. + match self_type { + sty_static => { ebml_w.writer.write(&[ 's' as u8 ]); } sty_value => { @@ -476,17 +946,68 @@ fn encode_self_type(ebml_w: &writer::Encoder, self_type: ast::self_ty_) { } } +#[cfg(stage0)] fn encode_method_sort(ebml_w: &writer::Encoder, sort: char) { ebml_w.start_tag(tag_item_trait_method_sort); ebml_w.writer.write(&[ sort as u8 ]); ebml_w.end_tag(); } +#[cfg(not(stage0))] +fn encode_method_sort(ebml_w: &mut writer::Encoder, sort: char) { + ebml_w.start_tag(tag_item_trait_method_sort); + ebml_w.writer.write(&[ sort as u8 ]); + ebml_w.end_tag(); +} + /* Returns an index of items in this class */ -fn encode_info_for_struct(ecx: @EncodeContext, ebml_w: &writer::Encoder, - path: &[ast_map::path_elt], - fields: &[@struct_field], - global_index: @mut~[entry]) -> ~[entry] { +#[cfg(stage0)] +fn encode_info_for_struct(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + path: &[ast_map::path_elt], + fields: &[@struct_field], + global_index: @mut~[entry]) + -> ~[entry] { + /* Each class has its own index, since different classes + may have fields with the same name */ + let index = @mut ~[]; + let tcx = ecx.tcx; + /* We encode both private and public fields -- need to include + private fields to get the offsets right */ + for fields.each |field| { + let (nm, mt, vis) = match field.node.kind { + named_field(nm, mt, vis) => (nm, mt, vis), + unnamed_field => ( + special_idents::unnamed_field, + struct_immutable, + inherited + ) + }; + + let id = field.node.id; + index.push(entry {val: id, pos: ebml_w.writer.tell()}); + global_index.push(entry {val: id, pos: ebml_w.writer.tell()}); + ebml_w.start_tag(tag_items_data_item); + debug!("encode_info_for_struct: doing %s %d", + *tcx.sess.str_of(nm), id); + encode_struct_field_family(ebml_w, vis); + encode_name(ecx, ebml_w, nm); + encode_path(ecx, ebml_w, path, ast_map::path_name(nm)); + encode_type(ecx, ebml_w, node_id_to_type(tcx, id)); + encode_mutability(ebml_w, mt); + encode_def_id(ebml_w, local_def(id)); + ebml_w.end_tag(); + } + /*bad*/copy *index +} + +#[cfg(not(stage0))] +fn encode_info_for_struct(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + path: &[ast_map::path_elt], + fields: &[@struct_field], + global_index: @mut ~[entry]) + -> ~[entry] { /* Each class has its own index, since different classes may have fields with the same name */ let index = @mut ~[]; @@ -521,6 +1042,7 @@ fn encode_info_for_struct(ecx: @EncodeContext, ebml_w: &writer::Encoder, } // This is for encoding info for ctors and dtors +#[cfg(stage0)] fn encode_info_for_ctor(ecx: @EncodeContext, ebml_w: &writer::Encoder, id: node_id, @@ -550,6 +1072,37 @@ fn encode_info_for_ctor(ecx: @EncodeContext, ebml_w.end_tag(); } +#[cfg(not(stage0))] +fn encode_info_for_ctor(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + id: node_id, + ident: ident, + path: &[ast_map::path_elt], + item: Option, + generics: &ast::Generics) { + ebml_w.start_tag(tag_items_data_item); + encode_name(ecx, ebml_w, ident); + encode_def_id(ebml_w, local_def(id)); + encode_family(ebml_w, purity_fn_family(ast::impure_fn)); + encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); + let its_ty = node_id_to_type(ecx.tcx, id); + debug!("fn name = %s ty = %s its node id = %d", + *ecx.tcx.sess.str_of(ident), + ty_to_str(ecx.tcx, its_ty), id); + encode_type(ecx, ebml_w, its_ty); + encode_path(ecx, ebml_w, path, ast_map::path_name(ident)); + match item { + Some(it) => { + (ecx.encode_inlined_item)(ecx, ebml_w, path, it); + } + None => { + encode_symbol(ecx, ebml_w, id); + } + } + ebml_w.end_tag(); +} + +#[cfg(stage0)] fn encode_info_for_struct_ctor(ecx: @EncodeContext, ebml_w: &writer::Encoder, path: &[ast_map::path_elt], @@ -569,100 +1122,489 @@ fn encode_info_for_struct_ctor(ecx: @EncodeContext, encode_symbol(ecx, ebml_w, ctor_id); } - ebml_w.end_tag(); -} + ebml_w.end_tag(); +} + +#[cfg(not(stage0))] +fn encode_info_for_struct_ctor(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + path: &[ast_map::path_elt], + name: ast::ident, + ctor_id: node_id, + index: @mut ~[entry]) { + index.push(entry { val: ctor_id, pos: ebml_w.writer.tell() }); + + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(ctor_id)); + encode_family(ebml_w, 'f'); + encode_name(ecx, ebml_w, name); + encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, ctor_id)); + encode_path(ecx, ebml_w, path, ast_map::path_name(name)); + + if ecx.item_symbols.contains_key(&ctor_id) { + encode_symbol(ecx, ebml_w, ctor_id); + } + + ebml_w.end_tag(); +} + +#[cfg(stage0)] +fn encode_method_ty_fields(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + method_ty: &ty::method) { + encode_def_id(ebml_w, method_ty.def_id); + encode_name(ecx, ebml_w, method_ty.ident); + encode_ty_type_param_defs(ebml_w, ecx, + method_ty.generics.type_param_defs, + tag_item_method_tps); + encode_transformed_self_ty(ecx, ebml_w, method_ty.transformed_self_ty); + encode_method_fty(ecx, ebml_w, &method_ty.fty); + encode_visibility(ebml_w, method_ty.vis); + encode_self_type(ebml_w, method_ty.self_ty); +} + +#[cfg(not(stage0))] +fn encode_method_ty_fields(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + method_ty: &ty::method) { + encode_def_id(ebml_w, method_ty.def_id); + encode_name(ecx, ebml_w, method_ty.ident); + encode_ty_type_param_defs(ebml_w, ecx, + method_ty.generics.type_param_defs, + tag_item_method_tps); + encode_transformed_self_ty(ecx, ebml_w, method_ty.transformed_self_ty); + encode_method_fty(ecx, ebml_w, &method_ty.fty); + encode_visibility(ebml_w, method_ty.vis); + encode_self_type(ebml_w, method_ty.self_ty); +} + +#[cfg(stage0)] +fn encode_info_for_method(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + impl_path: &[ast_map::path_elt], + should_inline: bool, + parent_id: node_id, + m: @method, + owner_generics: &ast::Generics, + method_generics: &ast::Generics) { + debug!("encode_info_for_method: %d %s %u %u", m.id, + *ecx.tcx.sess.str_of(m.ident), + owner_generics.ty_params.len(), + method_generics.ty_params.len()); + ebml_w.start_tag(tag_items_data_item); + + let method_def_id = local_def(m.id); + let method_ty: @ty::method = ty::method(ecx.tcx, method_def_id); + encode_method_ty_fields(ecx, ebml_w, method_ty); + + match m.self_ty.node { + ast::sty_static => { + encode_family(ebml_w, purity_static_method_family(m.purity)); + } + _ => encode_family(ebml_w, purity_fn_family(m.purity)) + } + + let mut combined_ty_params = opt_vec::Empty; + combined_ty_params.push_all(&owner_generics.ty_params); + combined_ty_params.push_all(&method_generics.ty_params); + let len = combined_ty_params.len(); + encode_type_param_bounds(ebml_w, ecx, &combined_ty_params); + + encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id)); + encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident)); + + if len > 0u || should_inline { + (ecx.encode_inlined_item)( + ecx, ebml_w, impl_path, + ii_method(local_def(parent_id), m)); + } else { + encode_symbol(ecx, ebml_w, m.id); + } + + ebml_w.end_tag(); +} + +#[cfg(not(stage0))] +fn encode_info_for_method(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + impl_path: &[ast_map::path_elt], + should_inline: bool, + parent_id: node_id, + m: @method, + owner_generics: &ast::Generics, + method_generics: &ast::Generics) { + debug!("encode_info_for_method: %d %s %u %u", m.id, + *ecx.tcx.sess.str_of(m.ident), + owner_generics.ty_params.len(), + method_generics.ty_params.len()); + ebml_w.start_tag(tag_items_data_item); + + let method_def_id = local_def(m.id); + let method_ty: @ty::method = ty::method(ecx.tcx, method_def_id); + encode_method_ty_fields(ecx, ebml_w, method_ty); + + match m.self_ty.node { + ast::sty_static => { + encode_family(ebml_w, purity_static_method_family(m.purity)); + } + _ => encode_family(ebml_w, purity_fn_family(m.purity)) + } + + let mut combined_ty_params = opt_vec::Empty; + combined_ty_params.push_all(&owner_generics.ty_params); + combined_ty_params.push_all(&method_generics.ty_params); + let len = combined_ty_params.len(); + encode_type_param_bounds(ebml_w, ecx, &combined_ty_params); + + encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id)); + encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident)); + + if len > 0u || should_inline { + (ecx.encode_inlined_item)( + ecx, ebml_w, impl_path, + ii_method(local_def(parent_id), m)); + } else { + encode_symbol(ecx, ebml_w, m.id); + } + + ebml_w.end_tag(); +} + +fn purity_fn_family(p: purity) -> char { + match p { + unsafe_fn => 'u', + pure_fn => 'p', + impure_fn => 'f', + extern_fn => 'e' + } +} + +fn purity_static_method_family(p: purity) -> char { + match p { + unsafe_fn => 'U', + pure_fn => 'P', + impure_fn => 'F', + _ => fail!(~"extern fn can't be static") + } +} + + +fn should_inline(attrs: &[attribute]) -> bool { + match attr::find_inline_attr(attrs) { + attr::ia_none | attr::ia_never => false, + attr::ia_hint | attr::ia_always => true + } +} + +#[cfg(stage0)] +fn encode_info_for_item(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + item: @item, + index: @mut ~[entry], + path: &[ast_map::path_elt]) { + let tcx = ecx.tcx; + let must_write = + match item.node { + item_enum(_, _) | item_impl(*) | item_trait(*) | item_struct(*) | + item_mod(*) | item_foreign_mod(*) | item_const(*) => true, + _ => false + }; + if !must_write && !reachable(ecx, item.id) { return; } + + fn add_to_index_(item: @item, ebml_w: &writer::Encoder, + index: @mut ~[entry]) { + index.push(entry { val: item.id, pos: ebml_w.writer.tell() }); + } + let add_to_index: &fn() = || add_to_index_(item, ebml_w, index); + + debug!("encoding info for item at %s", + ecx.tcx.sess.codemap.span_to_str(item.span)); + + match item.node { + item_const(_, _) => { + add_to_index(); + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(item.id)); + encode_family(ebml_w, 'c'); + encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + encode_symbol(ecx, ebml_w, item.id); + encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); + ebml_w.end_tag(); + } + item_fn(_, purity, _, ref generics, _) => { + add_to_index(); + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(item.id)); + encode_family(ebml_w, purity_fn_family(purity)); + let tps_len = generics.ty_params.len(); + encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); + encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + encode_attributes(ebml_w, item.attrs); + if tps_len > 0u || should_inline(item.attrs) { + (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); + } else { + encode_symbol(ecx, ebml_w, item.id); + } + ebml_w.end_tag(); + } + item_mod(ref m) => { + add_to_index(); + encode_info_for_mod(ecx, ebml_w, m, item.id, path, item.ident); + } + item_foreign_mod(_) => { + add_to_index(); + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(item.id)); + encode_family(ebml_w, 'n'); + encode_name(ecx, ebml_w, item.ident); + encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + ebml_w.end_tag(); + } + item_ty(_, ref generics) => { + add_to_index(); + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(item.id)); + encode_family(ebml_w, 'y'); + encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); + encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + encode_name(ecx, ebml_w, item.ident); + encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + encode_region_param(ecx, ebml_w, item); + ebml_w.end_tag(); + } + item_enum(ref enum_definition, ref generics) => { + add_to_index(); + do ebml_w.wr_tag(tag_items_data_item) { + encode_def_id(ebml_w, local_def(item.id)); + encode_family(ebml_w, 't'); + encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); + encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + encode_name(ecx, ebml_w, item.ident); + for (*enum_definition).variants.each |v| { + encode_variant_id(ebml_w, local_def(v.node.id)); + } + (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); + encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + encode_region_param(ecx, ebml_w, item); + } + encode_enum_variant_info(ecx, + ebml_w, + item.id, + (*enum_definition).variants, + path, + index, + generics); + } + item_struct(struct_def, ref generics) => { + /* First, encode the fields + These come first because we need to write them to make + the index, and the index needs to be in the item for the + class itself */ + let idx = encode_info_for_struct(ecx, ebml_w, path, + struct_def.fields, index); + + /* Index the class*/ + add_to_index(); + + /* Now, make an item for the class itself */ + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(item.id)); + encode_family(ebml_w, 'S'); + encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); + encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + + // If this is a tuple- or enum-like struct, encode the type of the + // constructor. + if struct_def.fields.len() > 0 && + struct_def.fields[0].node.kind == ast::unnamed_field { + let ctor_id = match struct_def.ctor_id { + Some(ctor_id) => ctor_id, + None => ecx.tcx.sess.bug(~"struct def didn't have ctor id"), + }; + + encode_info_for_struct_ctor(ecx, + ebml_w, + path, + item.ident, + ctor_id, + index); + } + + encode_name(ecx, ebml_w, item.ident); + encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + encode_region_param(ecx, ebml_w, item); + + /* Encode def_ids for each field and method + for methods, write all the stuff get_trait_method + needs to know*/ + for struct_def.fields.each |f| { + match f.node.kind { + named_field(ident, _, vis) => { + ebml_w.start_tag(tag_item_field); + encode_struct_field_family(ebml_w, vis); + encode_name(ecx, ebml_w, ident); + encode_def_id(ebml_w, local_def(f.node.id)); + ebml_w.end_tag(); + } + unnamed_field => { + ebml_w.start_tag(tag_item_unnamed_field); + encode_def_id(ebml_w, local_def(f.node.id)); + ebml_w.end_tag(); + } + } + } + + /* Each class has its own index -- encode it */ + let bkts = create_index(idx); + encode_index(ebml_w, bkts, write_int); + ebml_w.end_tag(); + } + item_impl(ref generics, opt_trait, ty, ref methods) => { + add_to_index(); + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(item.id)); + encode_family(ebml_w, 'i'); + encode_region_param(ecx, ebml_w, item); + encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); + encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + encode_name(ecx, ebml_w, item.ident); + encode_attributes(ebml_w, item.attrs); + match ty.node { + ast::ty_path(path, _) if path.idents.len() == 1 => { + encode_impl_type_basename(ecx, ebml_w, + ast_util::path_to_ident(path)); + } + _ => {} + } + for methods.each |m| { + ebml_w.start_tag(tag_item_impl_method); + let method_def_id = local_def(m.id); + ebml_w.writer.write(str::to_bytes(def_to_str(method_def_id))); + ebml_w.end_tag(); + } + for opt_trait.each |ast_trait_ref| { + let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id); + encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_trait_ref); + } + encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + ebml_w.end_tag(); + + // >:-< + let mut impl_path = vec::append(~[], path); + impl_path += ~[ast_map::path_name(item.ident)]; + + for methods.each |m| { + index.push(entry {val: m.id, pos: ebml_w.writer.tell()}); + encode_info_for_method(ecx, + ebml_w, + impl_path, + should_inline(m.attrs), + item.id, + *m, + generics, + &m.generics); + } + } + item_trait(ref generics, ref super_traits, ref ms) => { + add_to_index(); + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(item.id)); + encode_family(ebml_w, 'I'); + encode_region_param(ecx, ebml_w, item); + encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); + let trait_def = ty::lookup_trait_def(tcx, local_def(item.id)); + encode_trait_ref(ebml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); + encode_name(ecx, ebml_w, item.ident); + encode_attributes(ebml_w, item.attrs); + for ty::trait_method_def_ids(tcx, local_def(item.id)).each |&method_def_id| { + ebml_w.start_tag(tag_item_trait_method); + encode_def_id(ebml_w, method_def_id); + ebml_w.end_tag(); + } + encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + for super_traits.each |ast_trait_ref| { + let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id); + encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_super_trait_ref); + } + ebml_w.end_tag(); + + // Now output the method info for each method. + for ty::trait_method_def_ids(tcx, local_def(item.id)).eachi |i, &method_def_id| { + assert!(method_def_id.crate == ast::local_crate); -fn encode_method_ty_fields(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - method_ty: &ty::method) -{ - encode_def_id(ebml_w, method_ty.def_id); - encode_name(ecx, ebml_w, method_ty.ident); - encode_ty_type_param_defs(ebml_w, ecx, - method_ty.generics.type_param_defs, - tag_item_method_tps); - encode_transformed_self_ty(ecx, ebml_w, method_ty.transformed_self_ty); - encode_method_fty(ecx, ebml_w, &method_ty.fty); - encode_visibility(ebml_w, method_ty.vis); - encode_self_type(ebml_w, method_ty.self_ty); -} + let method_ty: @ty::method = ty::method(tcx, method_def_id); -fn encode_info_for_method(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - impl_path: &[ast_map::path_elt], - should_inline: bool, - parent_id: node_id, - m: @method, - owner_generics: &ast::Generics, - method_generics: &ast::Generics) { - debug!("encode_info_for_method: %d %s %u %u", m.id, - *ecx.tcx.sess.str_of(m.ident), - owner_generics.ty_params.len(), - method_generics.ty_params.len()); - ebml_w.start_tag(tag_items_data_item); + index.push(entry {val: method_def_id.node, pos: ebml_w.writer.tell()}); - let method_def_id = local_def(m.id); - let method_ty: @ty::method = ty::method(ecx.tcx, method_def_id); - encode_method_ty_fields(ecx, ebml_w, method_ty); + ebml_w.start_tag(tag_items_data_item); - match m.self_ty.node { - ast::sty_static => { - encode_family(ebml_w, purity_static_method_family(m.purity)); - } - _ => encode_family(ebml_w, purity_fn_family(m.purity)) - } + encode_method_ty_fields(ecx, ebml_w, method_ty); - let mut combined_ty_params = opt_vec::Empty; - combined_ty_params.push_all(&owner_generics.ty_params); - combined_ty_params.push_all(&method_generics.ty_params); - let len = combined_ty_params.len(); - encode_type_param_bounds(ebml_w, ecx, &combined_ty_params); + encode_parent_item(ebml_w, local_def(item.id)); - encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id)); - encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident)); + let mut trait_path = vec::append(~[], path); + trait_path.push(ast_map::path_name(item.ident)); + encode_path(ecx, ebml_w, trait_path, ast_map::path_name(method_ty.ident)); - if len > 0u || should_inline { - (ecx.encode_inlined_item)( - ecx, ebml_w, impl_path, - ii_method(local_def(parent_id), m)); - } else { - encode_symbol(ecx, ebml_w, m.id); - } + match method_ty.self_ty { + sty_static => { + encode_family(ebml_w, + purity_static_method_family( + method_ty.fty.purity)); - ebml_w.end_tag(); -} + let tpt = ty::lookup_item_type(tcx, method_def_id); + encode_ty_type_param_defs(ebml_w, ecx, + tpt.generics.type_param_defs, + tag_items_data_item_ty_param_bounds); + encode_type(ecx, ebml_w, tpt.ty); + } -fn purity_fn_family(p: purity) -> char { - match p { - unsafe_fn => 'u', - pure_fn => 'p', - impure_fn => 'f', - extern_fn => 'e' - } -} + _ => { + encode_family(ebml_w, + purity_fn_family( + method_ty.fty.purity)); + } + } -fn purity_static_method_family(p: purity) -> char { - match p { - unsafe_fn => 'U', - pure_fn => 'P', - impure_fn => 'F', - _ => fail!(~"extern fn can't be static") - } -} + match ms[i] { + required(_) => { + encode_method_sort(ebml_w, 'r'); + } + provided(m) => { + // This is obviously a bogus assert but I don't think this + // ever worked before anyhow...near as I can tell, before + // we would emit two items. + if method_ty.self_ty == sty_static { + tcx.sess.span_unimpl( + item.span, + fmt!("Method %s is both provided and static", + *tcx.sess.intr().get(method_ty.ident))); + } + encode_type_param_bounds(ebml_w, ecx, + &m.generics.ty_params); + encode_method_sort(ebml_w, 'p'); + (ecx.encode_inlined_item)( + ecx, ebml_w, path, + ii_method(local_def(item.id), m)); + } + } -fn should_inline(attrs: &[attribute]) -> bool { - match attr::find_inline_attr(attrs) { - attr::ia_none | attr::ia_never => false, - attr::ia_hint | attr::ia_always => true + ebml_w.end_tag(); + } + } + item_mac(*) => fail!(~"item macros unimplemented") } } - -fn encode_info_for_item(ecx: @EncodeContext, ebml_w: &writer::Encoder, - item: @item, index: @mut ~[entry], +#[cfg(not(stage0))] +fn encode_info_for_item(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + item: @item, + index: @mut ~[entry], path: &[ast_map::path_elt]) { - let tcx = ecx.tcx; let must_write = match item.node { @@ -737,19 +1679,21 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: &writer::Encoder, } item_enum(ref enum_definition, ref generics) => { add_to_index(); - do ebml_w.wr_tag(tag_items_data_item) { - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 't'); - encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - encode_name(ecx, ebml_w, item.ident); - for (*enum_definition).variants.each |v| { - encode_variant_id(ebml_w, local_def(v.node.id)); - } - (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); - encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - encode_region_param(ecx, ebml_w, item); + + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(item.id)); + encode_family(ebml_w, 't'); + encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); + encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); + encode_name(ecx, ebml_w, item.ident); + for (*enum_definition).variants.each |v| { + encode_variant_id(ebml_w, local_def(v.node.id)); } + (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); + encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); + encode_region_param(ecx, ebml_w, item); + ebml_w.end_tag(); + encode_enum_variant_info(ecx, ebml_w, item.id, @@ -960,6 +1904,7 @@ fn encode_info_for_item(ecx: @EncodeContext, ebml_w: &writer::Encoder, } } +#[cfg(stage0)] fn encode_info_for_foreign_item(ecx: @EncodeContext, ebml_w: &writer::Encoder, nitem: @foreign_item, @@ -994,8 +1939,46 @@ fn encode_info_for_foreign_item(ecx: @EncodeContext, ebml_w.end_tag(); } -fn encode_info_for_items(ecx: @EncodeContext, ebml_w: &writer::Encoder, - crate: &crate) -> ~[entry] { +#[cfg(not(stage0))] +fn encode_info_for_foreign_item(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + nitem: @foreign_item, + index: @mut ~[entry], + path: ast_map::path, + abi: AbiSet) { + if !reachable(ecx, nitem.id) { return; } + index.push(entry { val: nitem.id, pos: ebml_w.writer.tell() }); + + ebml_w.start_tag(tag_items_data_item); + match nitem.node { + foreign_item_fn(_, purity, ref generics) => { + encode_def_id(ebml_w, local_def(nitem.id)); + encode_family(ebml_w, purity_fn_family(purity)); + encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); + encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); + if abi.is_intrinsic() { + (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_foreign(nitem)); + } else { + encode_symbol(ecx, ebml_w, nitem.id); + } + encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident)); + } + foreign_item_const(*) => { + encode_def_id(ebml_w, local_def(nitem.id)); + encode_family(ebml_w, 'c'); + encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); + encode_symbol(ecx, ebml_w, nitem.id); + encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident)); + } + } + ebml_w.end_tag(); +} + +#[cfg(stage0)] +fn encode_info_for_items(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + crate: &crate) + -> ~[entry] { let index = @mut ~[]; ebml_w.start_tag(tag_items_data); index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() }); @@ -1038,6 +2021,57 @@ fn encode_info_for_items(ecx: @EncodeContext, ebml_w: &writer::Encoder, return /*bad*/copy *index; } +#[cfg(not(stage0))] +fn encode_info_for_items(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + crate: &crate) + -> ~[entry] { + let index = @mut ~[]; + ebml_w.start_tag(tag_items_data); + index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() }); + encode_info_for_mod(ecx, ebml_w, &crate.node.module, + crate_node_id, ~[], + syntax::parse::token::special_idents::invalid); + visit::visit_crate(crate, (), visit::mk_vt(@visit::Visitor { + visit_expr: |_e, _cx, _v| { }, + visit_item: { + let ebml_w = copy *ebml_w; + |i, cx, v| { + visit::visit_item(i, cx, v); + match *ecx.tcx.items.get(&i.id) { + ast_map::node_item(_, pt) => { + let mut ebml_w = copy ebml_w; + encode_info_for_item(ecx, &mut ebml_w, i, index, *pt); + } + _ => fail!(~"bad item") + } + } + }, + visit_foreign_item: { + let ebml_w = copy *ebml_w; + |ni, cx, v| { + visit::visit_foreign_item(ni, cx, v); + match *ecx.tcx.items.get(&ni.id) { + ast_map::node_foreign_item(_, abi, _, pt) => { + let mut ebml_w = copy ebml_w; + encode_info_for_foreign_item(ecx, + &mut ebml_w, + ni, + index, + /*bad*/copy *pt, + abi); + } + // case for separate item and foreign-item tables + _ => fail!(~"bad foreign item") + } + } + }, + ..*visit::default_visitor() + })); + ebml_w.end_tag(); + return /*bad*/copy *index; +} + // Path and definition ID indexing @@ -1049,15 +2083,47 @@ fn create_index(index: ~[entry]) -> let h = elt.val.hash() as uint; buckets[h % 256].push(*elt); } - - let mut buckets_frozen = ~[]; - for buckets.each |bucket| { - buckets_frozen.push(@/*bad*/copy **bucket); + + let mut buckets_frozen = ~[]; + for buckets.each |bucket| { + buckets_frozen.push(@/*bad*/copy **bucket); + } + return buckets_frozen; +} + +#[cfg(stage0)] +fn encode_index(ebml_w: &writer::Encoder, + buckets: ~[@~[entry]], + write_fn: &fn(@io::Writer, &T)) { + let writer = ebml_w.writer; + ebml_w.start_tag(tag_index); + let mut bucket_locs: ~[uint] = ~[]; + ebml_w.start_tag(tag_index_buckets); + for buckets.each |bucket| { + bucket_locs.push(ebml_w.writer.tell()); + ebml_w.start_tag(tag_index_buckets_bucket); + for vec::each(**bucket) |elt| { + ebml_w.start_tag(tag_index_buckets_bucket_elt); + assert!(elt.pos < 0xffff_ffff); + writer.write_be_u32(elt.pos as u32); + write_fn(writer, &elt.val); + ebml_w.end_tag(); + } + ebml_w.end_tag(); + } + ebml_w.end_tag(); + ebml_w.start_tag(tag_index_table); + for bucket_locs.each |pos| { + assert!(*pos < 0xffff_ffff); + writer.write_be_u32(*pos as u32); } - return buckets_frozen; + ebml_w.end_tag(); + ebml_w.end_tag(); } -fn encode_index(ebml_w: &writer::Encoder, buckets: ~[@~[entry]], +#[cfg(not(stage0))] +fn encode_index(ebml_w: &mut writer::Encoder, + buckets: ~[@~[entry]], write_fn: &fn(@io::Writer, &T)) { let writer = ebml_w.writer; ebml_w.start_tag(tag_index); @@ -1085,13 +2151,16 @@ fn encode_index(ebml_w: &writer::Encoder, buckets: ~[@~[entry]], ebml_w.end_tag(); } -fn write_str(writer: @io::Writer, s: ~str) { writer.write_str(s); } +fn write_str(writer: @io::Writer, s: ~str) { + writer.write_str(s); +} fn write_int(writer: @io::Writer, &n: &int) { assert!(n < 0x7fff_ffff); writer.write_be_u32(n as u32); } +#[cfg(stage0)] fn encode_meta_item(ebml_w: &writer::Encoder, mi: @meta_item) { match mi.node { meta_word(name) => { @@ -1129,6 +2198,45 @@ fn encode_meta_item(ebml_w: &writer::Encoder, mi: @meta_item) { } } +#[cfg(not(stage0))] +fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @meta_item) { + match mi.node { + meta_word(name) => { + ebml_w.start_tag(tag_meta_item_word); + ebml_w.start_tag(tag_meta_item_name); + ebml_w.writer.write(str::to_bytes(*name)); + ebml_w.end_tag(); + ebml_w.end_tag(); + } + meta_name_value(name, value) => { + match value.node { + lit_str(value) => { + ebml_w.start_tag(tag_meta_item_name_value); + ebml_w.start_tag(tag_meta_item_name); + ebml_w.writer.write(str::to_bytes(*name)); + ebml_w.end_tag(); + ebml_w.start_tag(tag_meta_item_value); + ebml_w.writer.write(str::to_bytes(*value)); + ebml_w.end_tag(); + ebml_w.end_tag(); + } + _ => {/* FIXME (#623): encode other variants */ } + } + } + meta_list(name, ref items) => { + ebml_w.start_tag(tag_meta_item_list); + ebml_w.start_tag(tag_meta_item_name); + ebml_w.writer.write(str::to_bytes(*name)); + ebml_w.end_tag(); + for items.each |inner_item| { + encode_meta_item(ebml_w, *inner_item); + } + ebml_w.end_tag(); + } + } +} + +#[cfg(stage0)] fn encode_attributes(ebml_w: &writer::Encoder, attrs: &[attribute]) { ebml_w.start_tag(tag_attributes); for attrs.each |attr| { @@ -1139,6 +2247,17 @@ fn encode_attributes(ebml_w: &writer::Encoder, attrs: &[attribute]) { ebml_w.end_tag(); } +#[cfg(not(stage0))] +fn encode_attributes(ebml_w: &mut writer::Encoder, attrs: &[attribute]) { + ebml_w.start_tag(tag_attributes); + for attrs.each |attr| { + ebml_w.start_tag(tag_attribute); + encode_meta_item(ebml_w, attr.node.value); + ebml_w.end_tag(); + } + ebml_w.end_tag(); +} + // So there's a special crate attribute called 'link' which defines the // metadata that Rust cares about for linking crates. This attribute requires // 'name' and 'vers' items, so if the user didn't provide them we will throw @@ -1193,6 +2312,7 @@ fn synthesize_crate_attrs(ecx: @EncodeContext, return attrs; } +#[cfg(stage0)] fn encode_crate_deps(ecx: @EncodeContext, ebml_w: &writer::Encoder, cstore: @mut cstore::CStore) { @@ -1235,6 +2355,50 @@ fn encode_crate_deps(ecx: @EncodeContext, ebml_w.end_tag(); } +#[cfg(not(stage0))] +fn encode_crate_deps(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + cstore: @mut cstore::CStore) { + fn get_ordered_deps(ecx: @EncodeContext, cstore: @mut cstore::CStore) + -> ~[decoder::crate_dep] { + type numdep = decoder::crate_dep; + + // Pull the cnums and name,vers,hash out of cstore + let mut deps = ~[]; + do cstore::iter_crate_data(cstore) |key, val| { + let dep = decoder::crate_dep {cnum: key, + name: ecx.tcx.sess.ident_of(/*bad*/ copy *val.name), + vers: decoder::get_crate_vers(val.data), + hash: decoder::get_crate_hash(val.data)}; + deps.push(dep); + }; + + // Sort by cnum + std::sort::quick_sort(deps, |kv1, kv2| kv1.cnum <= kv2.cnum); + + // Sanity-check the crate numbers + let mut expected_cnum = 1; + for deps.each |n| { + assert!((n.cnum == expected_cnum)); + expected_cnum += 1; + } + + // mut -> immutable hack for vec::map + deps.slice(0, deps.len()).to_owned() + } + + // We're just going to write a list of crate 'name-hash-version's, with + // the assumption that they are numbered 1 to n. + // FIXME (#2166): This is not nearly enough to support correct versioning + // but is enough to get transitive crate dependencies working. + ebml_w.start_tag(tag_crate_deps); + for get_ordered_deps(ecx, cstore).each |dep| { + encode_crate_dep(ecx, ebml_w, *dep); + } + ebml_w.end_tag(); +} + +#[cfg(stage0)] fn encode_lang_items(ecx: @EncodeContext, ebml_w: &writer::Encoder) { ebml_w.start_tag(tag_lang_items); @@ -1259,8 +2423,47 @@ fn encode_lang_items(ecx: @EncodeContext, ebml_w: &writer::Encoder) { ebml_w.end_tag(); // tag_lang_items } -fn encode_link_args(ecx: @EncodeContext, - ebml_w: &writer::Encoder) { +#[cfg(not(stage0))] +fn encode_lang_items(ecx: @EncodeContext, ebml_w: &mut writer::Encoder) { + ebml_w.start_tag(tag_lang_items); + + for ecx.tcx.lang_items.each_item |def_id, i| { + if def_id.crate != local_crate { + loop; + } + + ebml_w.start_tag(tag_lang_items_item); + + ebml_w.start_tag(tag_lang_items_item_id); + ebml_w.writer.write_be_u32(i as u32); + ebml_w.end_tag(); // tag_lang_items_item_id + + ebml_w.start_tag(tag_lang_items_item_node_id); + ebml_w.writer.write_be_u32(def_id.node as u32); + ebml_w.end_tag(); // tag_lang_items_item_node_id + + ebml_w.end_tag(); // tag_lang_items_item + } + + ebml_w.end_tag(); // tag_lang_items +} + +#[cfg(stage0)] +fn encode_link_args(ecx: @EncodeContext, ebml_w: &writer::Encoder) { + ebml_w.start_tag(tag_link_args); + + let link_args = cstore::get_used_link_args(ecx.cstore); + for link_args.each |link_arg| { + ebml_w.start_tag(tag_link_args_arg); + ebml_w.writer.write_str(link_arg.to_str()); + ebml_w.end_tag(); + } + + ebml_w.end_tag(); +} + +#[cfg(not(stage0))] +fn encode_link_args(ecx: @EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.start_tag(tag_link_args); let link_args = cstore::get_used_link_args(ecx.cstore); @@ -1273,7 +2476,26 @@ fn encode_link_args(ecx: @EncodeContext, ebml_w.end_tag(); } -fn encode_crate_dep(ecx: @EncodeContext, ebml_w: &writer::Encoder, +#[cfg(stage0)] +fn encode_crate_dep(ecx: @EncodeContext, + ebml_w: &writer::Encoder, + dep: decoder::crate_dep) { + ebml_w.start_tag(tag_crate_dep); + ebml_w.start_tag(tag_crate_dep_name); + ebml_w.writer.write(str::to_bytes(*ecx.tcx.sess.str_of(dep.name))); + ebml_w.end_tag(); + ebml_w.start_tag(tag_crate_dep_vers); + ebml_w.writer.write(str::to_bytes(*dep.vers)); + ebml_w.end_tag(); + ebml_w.start_tag(tag_crate_dep_hash); + ebml_w.writer.write(str::to_bytes(*dep.hash)); + ebml_w.end_tag(); + ebml_w.end_tag(); +} + +#[cfg(not(stage0))] +fn encode_crate_dep(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, dep: decoder::crate_dep) { ebml_w.start_tag(tag_crate_dep); ebml_w.start_tag(tag_crate_dep_name); @@ -1288,12 +2510,20 @@ fn encode_crate_dep(ecx: @EncodeContext, ebml_w: &writer::Encoder, ebml_w.end_tag(); } +#[cfg(stage0)] fn encode_hash(ebml_w: &writer::Encoder, hash: &str) { ebml_w.start_tag(tag_crate_hash); ebml_w.writer.write(str::to_bytes(hash)); ebml_w.end_tag(); } +#[cfg(not(stage0))] +fn encode_hash(ebml_w: &mut writer::Encoder, hash: &str) { + ebml_w.start_tag(tag_crate_hash); + ebml_w.writer.write(str::to_bytes(hash)); + ebml_w.end_tag(); +} + // NB: Increment this as you change the metadata encoding version. pub static metadata_encoding_version : &'static [u8] = &[0x72, //'r' as u8, @@ -1302,6 +2532,7 @@ pub static metadata_encoding_version : &'static [u8] = 0x74, //'t' as u8, 0, 0, 0, 1 ]; +#[cfg(stage0)] pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { let wr = @io::BytesWriter(); let stats = Stats { @@ -1408,6 +2639,113 @@ pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { }) + flate::deflate_bytes(wr.bytes) } +#[cfg(not(stage0))] +pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { + let wr = @io::BytesWriter(); + let stats = Stats { + inline_bytes: 0, + attr_bytes: 0, + dep_bytes: 0, + lang_item_bytes: 0, + link_args_bytes: 0, + item_bytes: 0, + index_bytes: 0, + zero_bytes: 0, + total_bytes: 0, + n_inlines: 0 + }; + let EncodeParams{item_symbols, diag, tcx, reachable, reexports2, + discrim_symbols, cstore, encode_inlined_item, + link_meta, _} = parms; + let ecx = @EncodeContext { + diag: diag, + tcx: tcx, + stats: @mut stats, + reachable: reachable, + reexports2: reexports2, + item_symbols: item_symbols, + discrim_symbols: discrim_symbols, + link_meta: link_meta, + cstore: cstore, + encode_inlined_item: encode_inlined_item, + type_abbrevs: @mut HashMap::new() + }; + + let mut ebml_w = writer::Encoder(wr as @io::Writer); + + encode_hash(&mut ebml_w, ecx.link_meta.extras_hash); + + let mut i = wr.pos; + let crate_attrs = synthesize_crate_attrs(ecx, crate); + encode_attributes(&mut ebml_w, crate_attrs); + ecx.stats.attr_bytes = wr.pos - i; + + i = wr.pos; + encode_crate_deps(ecx, &mut ebml_w, ecx.cstore); + ecx.stats.dep_bytes = wr.pos - i; + + // Encode the language items. + i = wr.pos; + encode_lang_items(ecx, &mut ebml_w); + ecx.stats.lang_item_bytes = wr.pos - i; + + // Encode the link args. + i = wr.pos; + encode_link_args(ecx, &mut ebml_w); + ecx.stats.link_args_bytes = wr.pos - i; + + // Encode and index the items. + ebml_w.start_tag(tag_items); + i = wr.pos; + let items_index = encode_info_for_items(ecx, &mut ebml_w, crate); + ecx.stats.item_bytes = wr.pos - i; + + i = wr.pos; + let items_buckets = create_index(items_index); + encode_index(&mut ebml_w, items_buckets, write_int); + ecx.stats.index_bytes = wr.pos - i; + ebml_w.end_tag(); + + ecx.stats.total_bytes = wr.pos; + + if (tcx.sess.meta_stats()) { + + do wr.bytes.each |e| { + if *e == 0 { + ecx.stats.zero_bytes += 1; + } + true + } + + io::println("metadata stats:"); + io::println(fmt!(" inline bytes: %u", ecx.stats.inline_bytes)); + io::println(fmt!(" attribute bytes: %u", ecx.stats.attr_bytes)); + io::println(fmt!(" dep bytes: %u", ecx.stats.dep_bytes)); + io::println(fmt!(" lang item bytes: %u", ecx.stats.lang_item_bytes)); + io::println(fmt!(" link args bytes: %u", ecx.stats.link_args_bytes)); + io::println(fmt!(" item bytes: %u", ecx.stats.item_bytes)); + io::println(fmt!(" index bytes: %u", ecx.stats.index_bytes)); + io::println(fmt!(" zero bytes: %u", ecx.stats.zero_bytes)); + io::println(fmt!(" total bytes: %u", ecx.stats.total_bytes)); + } + + // Pad this, since something (LLVM, presumably) is cutting off the + // remaining % 4 bytes. + wr.write(&[0u8, 0u8, 0u8, 0u8]); + + // FIXME #3396: weird bug here, for reasons unclear this emits random + // looking bytes (mostly 0x1) if we use the version byte-array constant + // above; so we use a string constant inline instead. + // + // Should be: + // + // vec::from_slice(metadata_encoding_version) + + + (do str::as_bytes(&~"rust\x00\x00\x00\x01") |bytes| { + vec::slice(*bytes, 0, 8).to_vec() + }) + flate::deflate_bytes(wr.bytes) +} + // Get the encoded string for a type pub fn encoded_ty(tcx: ty::ctxt, t: ty::t) -> ~str { let cx = @tyencode::ctxt { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 2f753523a7bc0..2a9f19fc84695 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -77,6 +77,7 @@ trait tr_intern { // ______________________________________________________________________ // Top-level methods. +#[cfg(stage0)] pub fn encode_inlined_item(ecx: @e::EncodeContext, ebml_w: &writer::Encoder, path: &[ast_map::path_elt], @@ -100,6 +101,32 @@ pub fn encode_inlined_item(ecx: @e::EncodeContext, ebml_w.writer.tell()); } +#[cfg(not(stage0))] +pub fn encode_inlined_item(ecx: @e::EncodeContext, + ebml_w: &mut writer::Encoder, + path: &[ast_map::path_elt], + ii: ast::inlined_item, + maps: Maps) { + debug!("> Encoding inlined item: %s::%s (%u)", + ast_map::path_to_str(path, ecx.tcx.sess.parse_sess.interner), + *ecx.tcx.sess.str_of(ii.ident()), + ebml_w.writer.tell()); + + let id_range = ast_util::compute_id_range_for_inlined_item(&ii); + + ebml_w.start_tag(c::tag_ast as uint); + id_range.encode(ebml_w); + encode_ast(ebml_w, simplify_ast(&ii)); + encode_side_tables_for_ii(ecx, maps, ebml_w, &ii); + ebml_w.end_tag(); + + debug!("< Encoded inlined fn: %s::%s (%u)", + ast_map::path_to_str(path, ecx.tcx.sess.parse_sess.interner), + *ecx.tcx.sess.str_of(ii.ident()), + ebml_w.writer.tell()); +} + +#[cfg(stage0)] pub fn decode_inlined_item(cdata: @cstore::crate_metadata, tcx: ty::ctxt, maps: Maps, @@ -145,6 +172,52 @@ pub fn decode_inlined_item(cdata: @cstore::crate_metadata, } } +#[cfg(not(stage0))] +pub fn decode_inlined_item(cdata: @cstore::crate_metadata, + tcx: ty::ctxt, + maps: Maps, + path: ast_map::path, + par_doc: ebml::Doc) + -> Option { + let dcx = @DecodeContext { + cdata: cdata, + tcx: tcx, + maps: maps + }; + match par_doc.opt_child(c::tag_ast) { + None => None, + Some(ast_doc) => { + debug!("> Decoding inlined fn: %s::?", + ast_map::path_to_str(path, tcx.sess.parse_sess.interner)); + let mut ast_dsr = reader::Decoder(ast_doc); + let from_id_range = Decodable::decode(&mut ast_dsr); + let to_id_range = reserve_id_range(dcx.tcx.sess, from_id_range); + let xcx = @ExtendedDecodeContext { + dcx: dcx, + from_id_range: from_id_range, + to_id_range: to_id_range + }; + let raw_ii = decode_ast(ast_doc); + let ii = renumber_ast(xcx, raw_ii); + debug!("Fn named: %s", *tcx.sess.str_of(ii.ident())); + debug!("< Decoded inlined fn: %s::%s", + ast_map::path_to_str(path, tcx.sess.parse_sess.interner), + *tcx.sess.str_of(ii.ident())); + ast_map::map_decoded_item(tcx.sess.diagnostic(), + dcx.tcx.items, path, &ii); + decode_side_tables(xcx, ast_doc); + match ii { + ast::ii_item(i) => { + debug!(">>> DECODED ITEM >>>\n%s\n<<< DECODED ITEM <<<", + syntax::print::pprust::item_to_str(i, tcx.sess.intr())); + } + _ => { } + } + Some(ii) + } + } +} + // ______________________________________________________________________ // Enumerating the IDs which appear in an AST @@ -236,28 +309,56 @@ impl tr for span { } } +#[cfg(stage0)] trait def_id_encoder_helpers { fn emit_def_id(&self, did: ast::def_id); } +#[cfg(not(stage0))] +trait def_id_encoder_helpers { + fn emit_def_id(&mut self, did: ast::def_id); +} + +#[cfg(stage0)] impl def_id_encoder_helpers for S { fn emit_def_id(&self, did: ast::def_id) { did.encode(self) } } +#[cfg(not(stage0))] +impl def_id_encoder_helpers for S { + fn emit_def_id(&mut self, did: ast::def_id) { + did.encode(self) + } +} + +#[cfg(stage0)] trait def_id_decoder_helpers { fn read_def_id(&self, xcx: @ExtendedDecodeContext) -> ast::def_id; } -impl def_id_decoder_helpers for D { +#[cfg(not(stage0))] +trait def_id_decoder_helpers { + fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id; +} +#[cfg(stage0)] +impl def_id_decoder_helpers for D { fn read_def_id(&self, xcx: @ExtendedDecodeContext) -> ast::def_id { let did: ast::def_id = Decodable::decode(self); did.tr(xcx) } } +#[cfg(not(stage0))] +impl def_id_decoder_helpers for D { + fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id { + let did: ast::def_id = Decodable::decode(self); + did.tr(xcx) + } +} + // ______________________________________________________________________ // Encoding and decoding the AST itself // @@ -273,12 +374,20 @@ impl def_id_decoder_helpers for D { // We also have to adjust the spans: for now we just insert a dummy span, // but eventually we should add entries to the local codemap as required. +#[cfg(stage0)] fn encode_ast(ebml_w: &writer::Encoder, item: ast::inlined_item) { do ebml_w.wr_tag(c::tag_tree as uint) { item.encode(ebml_w) } } +#[cfg(not(stage0))] +fn encode_ast(ebml_w: &mut writer::Encoder, item: ast::inlined_item) { + ebml_w.start_tag(c::tag_tree as uint); + item.encode(ebml_w); + ebml_w.end_tag(); +} + // Produces a simplified copy of the AST which does not include things // that we do not need to or do not want to export. For example, we // do not include any nested items: if these nested items are to be @@ -330,12 +439,20 @@ fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item { } } +#[cfg(stage0)] fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item { let chi_doc = par_doc.get(c::tag_tree as uint); let d = &reader::Decoder(chi_doc); Decodable::decode(d) } +#[cfg(not(stage0))] +fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item { + let chi_doc = par_doc.get(c::tag_tree as uint); + let mut d = reader::Decoder(chi_doc); + Decodable::decode(&mut d) +} + fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item) -> ast::inlined_item { let fld = fold::make_fold(@fold::AstFoldFns{ @@ -360,16 +477,30 @@ fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item) // ______________________________________________________________________ // Encoding and decoding of ast::def +#[cfg(stage0)] fn encode_def(ebml_w: &writer::Encoder, def: ast::def) { def.encode(ebml_w) } +#[cfg(not(stage0))] +fn encode_def(ebml_w: &mut writer::Encoder, def: ast::def) { + def.encode(ebml_w) +} + +#[cfg(stage0)] fn decode_def(xcx: @ExtendedDecodeContext, doc: ebml::Doc) -> ast::def { let dsr = &reader::Decoder(doc); let def: ast::def = Decodable::decode(dsr); def.tr(xcx) } +#[cfg(not(stage0))] +fn decode_def(xcx: @ExtendedDecodeContext, doc: ebml::Doc) -> ast::def { + let mut dsr = reader::Decoder(doc); + let def: ast::def = Decodable::decode(&mut dsr); + def.tr(xcx) +} + impl tr for ast::def { fn tr(&self, xcx: @ExtendedDecodeContext) -> ast::def { match *self { @@ -471,18 +602,41 @@ impl tr for ty::bound_region { // ______________________________________________________________________ // Encoding and decoding of freevar information +#[cfg(stage0)] fn encode_freevar_entry(ebml_w: &writer::Encoder, fv: @freevar_entry) { (*fv).encode(ebml_w) } +#[cfg(not(stage0))] +fn encode_freevar_entry(ebml_w: &mut writer::Encoder, fv: @freevar_entry) { + (*fv).encode(ebml_w) +} + +#[cfg(stage0)] trait ebml_decoder_helper { fn read_freevar_entry(&self, xcx: @ExtendedDecodeContext) - -> freevar_entry; + -> freevar_entry; +} + +#[cfg(not(stage0))] +trait ebml_decoder_helper { + fn read_freevar_entry(&mut self, xcx: @ExtendedDecodeContext) + -> freevar_entry; } +#[cfg(stage0)] impl ebml_decoder_helper for reader::Decoder { fn read_freevar_entry(&self, xcx: @ExtendedDecodeContext) - -> freevar_entry { + -> freevar_entry { + let fv: freevar_entry = Decodable::decode(self); + fv.tr(xcx) + } +} + +#[cfg(not(stage0))] +impl ebml_decoder_helper for reader::Decoder { + fn read_freevar_entry(&mut self, xcx: @ExtendedDecodeContext) + -> freevar_entry { let fv: freevar_entry = Decodable::decode(self); fv.tr(xcx) } @@ -500,14 +654,31 @@ impl tr for freevar_entry { // ______________________________________________________________________ // Encoding and decoding of CaptureVar information +#[cfg(stage0)] trait capture_var_helper { fn read_capture_var(&self, xcx: @ExtendedDecodeContext) - -> moves::CaptureVar; + -> moves::CaptureVar; } +#[cfg(not(stage0))] +trait capture_var_helper { + fn read_capture_var(&mut self, xcx: @ExtendedDecodeContext) + -> moves::CaptureVar; +} + +#[cfg(stage0)] impl capture_var_helper for reader::Decoder { fn read_capture_var(&self, xcx: @ExtendedDecodeContext) - -> moves::CaptureVar { + -> moves::CaptureVar { + let cvar: moves::CaptureVar = Decodable::decode(self); + cvar.tr(xcx) + } +} + +#[cfg(not(stage0))] +impl capture_var_helper for reader::Decoder { + fn read_capture_var(&mut self, xcx: @ExtendedDecodeContext) + -> moves::CaptureVar { let cvar: moves::CaptureVar = Decodable::decode(self); cvar.tr(xcx) } @@ -527,14 +698,18 @@ impl tr for moves::CaptureVar { // Encoding and decoding of method_map_entry trait read_method_map_entry_helper { + #[cfg(stage0)] fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) - -> method_map_entry; + -> method_map_entry; + #[cfg(not(stage0))] + fn read_method_map_entry(&mut self, xcx: @ExtendedDecodeContext) + -> method_map_entry; } #[cfg(stage0)] fn encode_method_map_entry(ecx: @e::EncodeContext, - ebml_w: &writer::Encoder, - mme: method_map_entry) { + ebml_w: &writer::Encoder, + mme: method_map_entry) { do ebml_w.emit_struct("method_map_entry", 3) { do ebml_w.emit_field(~"self_arg", 0u) { ebml_w.emit_arg(ecx, mme.self_arg); @@ -551,23 +726,21 @@ fn encode_method_map_entry(ecx: @e::EncodeContext, } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] fn encode_method_map_entry(ecx: @e::EncodeContext, - ebml_w: &writer::Encoder, - mme: method_map_entry) { - do ebml_w.emit_struct("method_map_entry", 3) { - do ebml_w.emit_struct_field("self_arg", 0u) { + ebml_w: &mut writer::Encoder, + mme: method_map_entry) { + do ebml_w.emit_struct("method_map_entry", 3) |ebml_w| { + do ebml_w.emit_struct_field("self_arg", 0u) |ebml_w| { ebml_w.emit_arg(ecx, mme.self_arg); } - do ebml_w.emit_struct_field("explicit_self", 2u) { + do ebml_w.emit_struct_field("explicit_self", 2u) |ebml_w| { mme.explicit_self.encode(ebml_w); } - do ebml_w.emit_struct_field("origin", 1u) { + do ebml_w.emit_struct_field("origin", 1u) |ebml_w| { mme.origin.encode(ebml_w); } - do ebml_w.emit_struct_field("self_mode", 3) { + do ebml_w.emit_struct_field("self_mode", 3) |ebml_w| { mme.self_mode.encode(ebml_w); } } @@ -576,7 +749,7 @@ fn encode_method_map_entry(ecx: @e::EncodeContext, impl read_method_map_entry_helper for reader::Decoder { #[cfg(stage0)] fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) - -> method_map_entry { + -> method_map_entry { do self.read_struct("method_map_entry", 3) { method_map_entry { self_arg: self.read_field(~"self_arg", 0u, || { @@ -599,27 +772,27 @@ impl read_method_map_entry_helper for reader::Decoder { } } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) - -> method_map_entry { - do self.read_struct("method_map_entry", 3) { + #[cfg(not(stage0))] + fn read_method_map_entry(&mut self, xcx: @ExtendedDecodeContext) + -> method_map_entry { + do self.read_struct("method_map_entry", 3) |this| { method_map_entry { - self_arg: self.read_struct_field("self_arg", 0u, || { - self.read_arg(xcx) + self_arg: this.read_struct_field("self_arg", 0, |this| { + this.read_arg(xcx) }), - explicit_self: self.read_struct_field("explicit_self", 2, || { - let self_type: ast::self_ty_ = Decodable::decode(self); + explicit_self: this.read_struct_field("explicit_self", + 2, + |this| { + let self_type: ast::self_ty_ = Decodable::decode(this); self_type }), - origin: self.read_struct_field("origin", 1u, || { + origin: this.read_struct_field("origin", 1, |this| { let method_origin: method_origin = - Decodable::decode(self); + Decodable::decode(this); method_origin.tr(xcx) }), - self_mode: self.read_struct_field("self_mode", 3, || { - let self_mode: ty::SelfMode = Decodable::decode(self); + self_mode: this.read_struct_field("self_mode", 3, |this| { + let self_mode: ty::SelfMode = Decodable::decode(this); self_mode }), } @@ -657,6 +830,7 @@ impl tr for method_origin { // ______________________________________________________________________ // Encoding and decoding vtable_res +#[cfg(stage0)] fn encode_vtable_res(ecx: @e::EncodeContext, ebml_w: &writer::Encoder, dr: typeck::vtable_res) { @@ -669,6 +843,20 @@ fn encode_vtable_res(ecx: @e::EncodeContext, } } +#[cfg(not(stage0))] +fn encode_vtable_res(ecx: @e::EncodeContext, + ebml_w: &mut writer::Encoder, + dr: typeck::vtable_res) { + // can't autogenerate this code because automatic code of + // ty::t doesn't work, and there is no way (atm) to have + // hand-written encoding routines combine with auto-generated + // ones. perhaps we should fix this. + do ebml_w.emit_from_vec(*dr) |ebml_w, vtable_origin| { + encode_vtable_origin(ecx, ebml_w, vtable_origin) + } +} + +#[cfg(stage0)] fn encode_vtable_origin(ecx: @e::EncodeContext, ebml_w: &writer::Encoder, vtable_origin: &typeck::vtable_origin) { @@ -699,24 +887,72 @@ fn encode_vtable_origin(ecx: @e::EncodeContext, } } } +} +#[cfg(not(stage0))] +fn encode_vtable_origin(ecx: @e::EncodeContext, + ebml_w: &mut writer::Encoder, + vtable_origin: &typeck::vtable_origin) { + do ebml_w.emit_enum(~"vtable_origin") |ebml_w| { + match *vtable_origin { + typeck::vtable_static(def_id, ref tys, vtable_res) => { + do ebml_w.emit_enum_variant(~"vtable_static", 0u, 3u) |ebml_w| { + do ebml_w.emit_enum_variant_arg(0u) |ebml_w| { + ebml_w.emit_def_id(def_id) + } + do ebml_w.emit_enum_variant_arg(1u) |ebml_w| { + ebml_w.emit_tys(ecx, /*bad*/copy *tys); + } + do ebml_w.emit_enum_variant_arg(2u) |ebml_w| { + encode_vtable_res(ecx, ebml_w, vtable_res); + } + } + } + typeck::vtable_param(pn, bn) => { + do ebml_w.emit_enum_variant(~"vtable_param", 1u, 2u) |ebml_w| { + do ebml_w.emit_enum_variant_arg(0u) |ebml_w| { + ebml_w.emit_uint(pn); + } + do ebml_w.emit_enum_variant_arg(1u) |ebml_w| { + ebml_w.emit_uint(bn); + } + } + } + } + } } trait vtable_decoder_helpers { + #[cfg(stage0)] fn read_vtable_res(&self, xcx: @ExtendedDecodeContext) -> typeck::vtable_res; + #[cfg(not(stage0))] + fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) + -> typeck::vtable_res; + #[cfg(stage0)] fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext) - -> typeck::vtable_origin; + -> typeck::vtable_origin; + #[cfg(not(stage0))] + fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) + -> typeck::vtable_origin; } impl vtable_decoder_helpers for reader::Decoder { + #[cfg(stage0)] fn read_vtable_res(&self, xcx: @ExtendedDecodeContext) -> typeck::vtable_res { - @self.read_to_vec(|| self.read_vtable_origin(xcx) ) + @self.read_to_vec(|| self.read_vtable_origin(xcx)) } + #[cfg(not(stage0))] + fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) + -> typeck::vtable_res { + @self.read_to_vec(|this| this.read_vtable_origin(xcx)) + } + + #[cfg(stage0)] fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext) - -> typeck::vtable_origin { + -> typeck::vtable_origin { do self.read_enum("vtable_origin") { do self.read_enum_variant(["vtable_static", "vtable_param"]) |i| { match i { @@ -749,6 +985,43 @@ impl vtable_decoder_helpers for reader::Decoder { } } } + + #[cfg(not(stage0))] + fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) + -> typeck::vtable_origin { + do self.read_enum("vtable_origin") |this| { + do this.read_enum_variant(["vtable_static", "vtable_param"]) + |this, i| { + match i { + 0 => { + typeck::vtable_static( + do this.read_enum_variant_arg(0u) |this| { + this.read_def_id(xcx) + }, + do this.read_enum_variant_arg(1u) |this| { + this.read_tys(xcx) + }, + do this.read_enum_variant_arg(2u) |this| { + this.read_vtable_res(xcx) + } + ) + } + 1 => { + typeck::vtable_param( + do this.read_enum_variant_arg(0u) |this| { + this.read_uint() + }, + do this.read_enum_variant_arg(1u) |this| { + this.read_uint() + } + ) + } + // hard to avoid - user input + _ => fail!(~"bad enum variant") + } + } + } + } } // ______________________________________________________________________ @@ -769,6 +1042,7 @@ impl get_ty_str_ctxt for e::EncodeContext { } } +#[cfg(stage0)] trait ebml_writer_helpers { fn emit_arg(&self, ecx: @e::EncodeContext, arg: ty::arg); fn emit_ty(&self, ecx: @e::EncodeContext, ty: ty::t); @@ -781,31 +1055,78 @@ trait ebml_writer_helpers { tpbt: ty::ty_param_bounds_and_ty); } +#[cfg(not(stage0))] +trait ebml_writer_helpers { + fn emit_arg(&mut self, ecx: @e::EncodeContext, arg: ty::arg); + fn emit_ty(&mut self, ecx: @e::EncodeContext, ty: ty::t); + fn emit_vstore(&mut self, ecx: @e::EncodeContext, vstore: ty::vstore); + fn emit_tys(&mut self, ecx: @e::EncodeContext, tys: ~[ty::t]); + fn emit_type_param_def(&mut self, + ecx: @e::EncodeContext, + type_param_def: &ty::TypeParameterDef); + fn emit_tpbt(&mut self, + ecx: @e::EncodeContext, + tpbt: ty::ty_param_bounds_and_ty); +} + impl ebml_writer_helpers for writer::Encoder { + #[cfg(stage0)] fn emit_ty(&self, ecx: @e::EncodeContext, ty: ty::t) { do self.emit_opaque { e::write_type(ecx, self, ty) } } + #[cfg(not(stage0))] + fn emit_ty(&mut self, ecx: @e::EncodeContext, ty: ty::t) { + do self.emit_opaque |this| { + e::write_type(ecx, this, ty) + } + } + + #[cfg(stage0)] fn emit_vstore(&self, ecx: @e::EncodeContext, vstore: ty::vstore) { do self.emit_opaque { e::write_vstore(ecx, self, vstore) } } + #[cfg(not(stage0))] + fn emit_vstore(&mut self, ecx: @e::EncodeContext, vstore: ty::vstore) { + do self.emit_opaque |this| { + e::write_vstore(ecx, this, vstore) + } + } + + #[cfg(stage0)] fn emit_arg(&self, ecx: @e::EncodeContext, arg: ty::arg) { do self.emit_opaque { tyencode::enc_arg(self.writer, ecx.ty_str_ctxt(), arg); } } + #[cfg(not(stage0))] + fn emit_arg(&mut self, ecx: @e::EncodeContext, arg: ty::arg) { + do self.emit_opaque |this| { + tyencode::enc_arg(this.writer, ecx.ty_str_ctxt(), arg); + } + } + + #[cfg(stage0)] fn emit_tys(&self, ecx: @e::EncodeContext, tys: ~[ty::t]) { do self.emit_from_vec(tys) |ty| { self.emit_ty(ecx, *ty) } } + #[cfg(not(stage0))] + fn emit_tys(&mut self, ecx: @e::EncodeContext, tys: ~[ty::t]) { + do self.emit_from_vec(tys) |this, ty| { + this.emit_ty(ecx, *ty) + } + } + + #[cfg(stage0)] fn emit_type_param_def(&self, ecx: @e::EncodeContext, type_param_def: &ty::TypeParameterDef) { @@ -815,16 +1136,27 @@ impl ebml_writer_helpers for writer::Encoder { } } + #[cfg(not(stage0))] + fn emit_type_param_def(&mut self, + ecx: @e::EncodeContext, + type_param_def: &ty::TypeParameterDef) { + do self.emit_opaque |this| { + tyencode::enc_type_param_def(this.writer, + ecx.ty_str_ctxt(), + type_param_def) + } + } + #[cfg(stage0)] - fn emit_tpbt(&self, ecx: @e::EncodeContext, + fn emit_tpbt(&self, + ecx: @e::EncodeContext, tpbt: ty::ty_param_bounds_and_ty) { do self.emit_struct("ty_param_bounds_and_ty", 2) { do self.emit_field(~"generics", 0) { do self.emit_struct("Generics", 2) { do self.emit_field(~"type_param_defs", 0) { do self.emit_from_vec(*tpbt.generics.type_param_defs) - |type_param_def| - { + |type_param_def| { self.emit_type_param_def(ecx, type_param_def); } } @@ -839,38 +1171,44 @@ impl ebml_writer_helpers for writer::Encoder { } } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn emit_tpbt(&self, ecx: @e::EncodeContext, + #[cfg(not(stage0))] + fn emit_tpbt(&mut self, + ecx: @e::EncodeContext, tpbt: ty::ty_param_bounds_and_ty) { - do self.emit_struct("ty_param_bounds_and_ty", 2) { - do self.emit_struct_field("generics", 0) { - do self.emit_struct("Generics", 2) { - do self.emit_struct_field("type_param_defs", 0) { - do self.emit_from_vec(*tpbt.generics.type_param_defs) - |type_param_def| - { - self.emit_type_param_def(ecx, type_param_def); + do self.emit_struct("ty_param_bounds_and_ty", 2) |this| { + do this.emit_struct_field(~"generics", 0) |this| { + do this.emit_struct("Generics", 2) |this| { + do this.emit_struct_field(~"type_param_defs", 0) |this| { + do this.emit_from_vec(*tpbt.generics.type_param_defs) + |this, type_param_def| { + this.emit_type_param_def(ecx, type_param_def); } } - do self.emit_struct_field("region_param", 1) { - tpbt.generics.region_param.encode(self); + do this.emit_struct_field(~"region_param", 1) |this| { + tpbt.generics.region_param.encode(this); } } } - do self.emit_struct_field("ty", 1) { - self.emit_ty(ecx, tpbt.ty); + do this.emit_struct_field(~"ty", 1) |this| { + this.emit_ty(ecx, tpbt.ty); } } } } +#[cfg(stage0)] trait write_tag_and_id { fn tag(&self, tag_id: c::astencode_tag, f: &fn()); fn id(&self, id: ast::node_id); } +#[cfg(not(stage0))] +trait write_tag_and_id { + fn tag(&mut self, tag_id: c::astencode_tag, f: &fn(&mut Self)); + fn id(&mut self, id: ast::node_id); +} + +#[cfg(stage0)] impl write_tag_and_id for writer::Encoder { fn tag(&self, tag_id: c::astencode_tag, f: &fn()) { do self.wr_tag(tag_id as uint) { f() } @@ -881,6 +1219,22 @@ impl write_tag_and_id for writer::Encoder { } } +#[cfg(not(stage0))] +impl write_tag_and_id for writer::Encoder { + fn tag(&mut self, + tag_id: c::astencode_tag, + f: &fn(&mut writer::Encoder)) { + self.start_tag(tag_id as uint); + f(self); + self.end_tag(); + } + + fn id(&mut self, id: ast::node_id) { + self.wr_tagged_u64(c::tag_table_id as uint, id as u64) + } +} + +#[cfg(stage0)] fn encode_side_tables_for_ii(ecx: @e::EncodeContext, maps: Maps, ebml_w: &writer::Encoder, @@ -899,6 +1253,26 @@ fn encode_side_tables_for_ii(ecx: @e::EncodeContext, } } +#[cfg(not(stage0))] +fn encode_side_tables_for_ii(ecx: @e::EncodeContext, + maps: Maps, + ebml_w: &mut writer::Encoder, + ii: &ast::inlined_item) { + ebml_w.start_tag(c::tag_table as uint); + let new_ebml_w = copy *ebml_w; + ast_util::visit_ids_for_inlined_item( + ii, + |id: ast::node_id| { + // Note: this will cause a copy of ebml_w, which is bad as + // it is mutable. But I believe it's harmless since we generate + // balanced EBML. + let mut new_ebml_w = copy new_ebml_w; + encode_side_tables_for_id(ecx, maps, &mut new_ebml_w, id) + }); + ebml_w.end_tag(); +} + +#[cfg(stage0)] fn encode_side_tables_for_id(ecx: @e::EncodeContext, maps: Maps, ebml_w: &writer::Encoder, @@ -1028,6 +1402,136 @@ fn encode_side_tables_for_id(ecx: @e::EncodeContext, } } +#[cfg(not(stage0))] +fn encode_side_tables_for_id(ecx: @e::EncodeContext, + maps: Maps, + ebml_w: &mut writer::Encoder, + id: ast::node_id) { + let tcx = ecx.tcx; + + debug!("Encoding side tables for id %d", id); + + for tcx.def_map.find(&id).each |def| { + do ebml_w.tag(c::tag_table_def) |ebml_w| { + ebml_w.id(id); + do ebml_w.tag(c::tag_table_val) |ebml_w| { + (*def).encode(ebml_w) + } + } + } + + for tcx.node_types.find(&(id as uint)).each |&ty| { + do ebml_w.tag(c::tag_table_node_type) |ebml_w| { + ebml_w.id(id); + do ebml_w.tag(c::tag_table_val) |ebml_w| { + ebml_w.emit_ty(ecx, *ty); + } + } + } + + for tcx.node_type_substs.find(&id).each |tys| { + do ebml_w.tag(c::tag_table_node_type_subst) |ebml_w| { + ebml_w.id(id); + do ebml_w.tag(c::tag_table_val) |ebml_w| { + // FIXME(#5562): removing this copy causes a segfault + // before stage2 + ebml_w.emit_tys(ecx, /*bad*/copy **tys) + } + } + } + + for tcx.freevars.find(&id).each |&fv| { + do ebml_w.tag(c::tag_table_freevars) |ebml_w| { + ebml_w.id(id); + do ebml_w.tag(c::tag_table_val) |ebml_w| { + do ebml_w.emit_from_vec(**fv) |ebml_w, fv_entry| { + encode_freevar_entry(ebml_w, *fv_entry) + } + } + } + } + + let lid = ast::def_id { crate: ast::local_crate, node: id }; + for tcx.tcache.find(&lid).each |&tpbt| { + do ebml_w.tag(c::tag_table_tcache) |ebml_w| { + ebml_w.id(id); + do ebml_w.tag(c::tag_table_val) |ebml_w| { + ebml_w.emit_tpbt(ecx, *tpbt); + } + } + } + + for tcx.ty_param_defs.find(&id).each |&type_param_def| { + do ebml_w.tag(c::tag_table_param_defs) |ebml_w| { + ebml_w.id(id); + do ebml_w.tag(c::tag_table_val) |ebml_w| { + ebml_w.emit_type_param_def(ecx, type_param_def) + } + } + } + + if maps.mutbl_map.contains(&id) { + do ebml_w.tag(c::tag_table_mutbl) |ebml_w| { + ebml_w.id(id); + } + } + + for maps.last_use_map.find(&id).each |&m| { + do ebml_w.tag(c::tag_table_last_use) |ebml_w| { + ebml_w.id(id); + do ebml_w.tag(c::tag_table_val) |ebml_w| { + do ebml_w.emit_from_vec(/*bad*/ copy **m) |ebml_w, id| { + id.encode(ebml_w); + } + } + } + } + + for maps.method_map.find(&id).each |&mme| { + do ebml_w.tag(c::tag_table_method_map) |ebml_w| { + ebml_w.id(id); + do ebml_w.tag(c::tag_table_val) |ebml_w| { + encode_method_map_entry(ecx, ebml_w, *mme) + } + } + } + + for maps.vtable_map.find(&id).each |&dr| { + do ebml_w.tag(c::tag_table_vtable_map) |ebml_w| { + ebml_w.id(id); + do ebml_w.tag(c::tag_table_val) |ebml_w| { + encode_vtable_res(ecx, ebml_w, *dr); + } + } + } + + for tcx.adjustments.find(&id).each |adj| { + do ebml_w.tag(c::tag_table_adjustments) |ebml_w| { + ebml_w.id(id); + do ebml_w.tag(c::tag_table_val) |ebml_w| { + (**adj).encode(ebml_w) + } + } + } + + if maps.moves_map.contains(&id) { + do ebml_w.tag(c::tag_table_moves_map) |ebml_w| { + ebml_w.id(id); + } + } + + for maps.capture_map.find(&id).each |&cap_vars| { + do ebml_w.tag(c::tag_table_capture_map) |ebml_w| { + ebml_w.id(id); + do ebml_w.tag(c::tag_table_val) |ebml_w| { + do ebml_w.emit_from_vec(*cap_vars) |ebml_w, cap_var| { + cap_var.encode(ebml_w); + } + } + } + } +} + trait doc_decoder_helpers { fn as_int(&self) -> int; fn opt_child(&self, tag: c::astencode_tag) -> Option; @@ -1040,6 +1544,7 @@ impl doc_decoder_helpers for ebml::Doc { } } +#[cfg(stage0)] trait ebml_decoder_decoder_helpers { fn read_arg(&self, xcx: @ExtendedDecodeContext) -> ty::arg; fn read_ty(&self, xcx: @ExtendedDecodeContext) -> ty::t; @@ -1052,7 +1557,24 @@ trait ebml_decoder_decoder_helpers { did: ast::def_id) -> ast::def_id; } +#[cfg(not(stage0))] +trait ebml_decoder_decoder_helpers { + fn read_arg(&mut self, xcx: @ExtendedDecodeContext) -> ty::arg; + fn read_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::t; + fn read_tys(&mut self, xcx: @ExtendedDecodeContext) -> ~[ty::t]; + fn read_type_param_def(&mut self, xcx: @ExtendedDecodeContext) + -> ty::TypeParameterDef; + fn read_ty_param_bounds_and_ty(&mut self, xcx: @ExtendedDecodeContext) + -> ty::ty_param_bounds_and_ty; + fn convert_def_id(&mut self, + xcx: @ExtendedDecodeContext, + source: DefIdSource, + did: ast::def_id) + -> ast::def_id; +} + impl ebml_decoder_decoder_helpers for reader::Decoder { + #[cfg(stage0)] fn read_arg(&self, xcx: @ExtendedDecodeContext) -> ty::arg { do self.read_opaque |doc| { tydecode::parse_arg_data( @@ -1061,6 +1583,19 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } + #[cfg(not(stage0))] + fn read_arg(&mut self, xcx: @ExtendedDecodeContext) -> ty::arg { + do self.read_opaque |this, doc| { + tydecode::parse_arg_data( + doc.data, + xcx.dcx.cdata.cnum, + doc.start, + xcx.dcx.tcx, + |s, a| this.convert_def_id(xcx, s, a)) + } + } + + #[cfg(stage0)] fn read_ty(&self, xcx: @ExtendedDecodeContext) -> ty::t { // Note: regions types embed local node ids. In principle, we // should translate these node ids into the new decode @@ -1088,11 +1623,50 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } + #[cfg(not(stage0))] + fn read_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::t { + // Note: regions types embed local node ids. In principle, we + // should translate these node ids into the new decode + // context. However, we do not bother, because region types + // are not used during trans. + + return do self.read_opaque |this, doc| { + let ty = tydecode::parse_ty_data( + doc.data, + xcx.dcx.cdata.cnum, + doc.start, + xcx.dcx.tcx, + |s, a| this.convert_def_id(xcx, s, a)); + + debug!("read_ty(%s) = %s", + type_string(doc), + ty_to_str(xcx.dcx.tcx, ty)); + + ty + }; + + fn type_string(doc: ebml::Doc) -> ~str { + let mut str = ~""; + for uint::range(doc.start, doc.end) |i| { + str::push_char(&mut str, doc.data[i] as char); + } + str + } + } + + #[cfg(stage0)] fn read_tys(&self, xcx: @ExtendedDecodeContext) -> ~[ty::t] { self.read_to_vec(|| self.read_ty(xcx) ) } - fn read_type_param_def(&self, xcx: @ExtendedDecodeContext) -> ty::TypeParameterDef { + #[cfg(not(stage0))] + fn read_tys(&mut self, xcx: @ExtendedDecodeContext) -> ~[ty::t] { + self.read_to_vec(|this| this.read_ty(xcx) ) + } + + #[cfg(stage0)] + fn read_type_param_def(&self, xcx: @ExtendedDecodeContext) + -> ty::TypeParameterDef { do self.read_opaque |doc| { tydecode::parse_type_param_def_data( doc.data, doc.start, xcx.dcx.cdata.cnum, xcx.dcx.tcx, @@ -1100,20 +1674,34 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } + #[cfg(not(stage0))] + fn read_type_param_def(&mut self, xcx: @ExtendedDecodeContext) + -> ty::TypeParameterDef { + do self.read_opaque |this, doc| { + tydecode::parse_type_param_def_data( + doc.data, + doc.start, + xcx.dcx.cdata.cnum, + xcx.dcx.tcx, + |s, a| this.convert_def_id(xcx, s, a)) + } + } + #[cfg(stage0)] fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) - -> ty::ty_param_bounds_and_ty - { + -> ty::ty_param_bounds_and_ty { do self.read_struct("ty_param_bounds_and_ty", 2) { ty::ty_param_bounds_and_ty { - generics: do self.read_struct("Generics", 2) { - ty::Generics { - type_param_defs: self.read_field("type_param_defs", 0, || { - @self.read_to_vec(|| self.read_type_param_def(xcx)) - }), - region_param: self.read_field(~"region_param", 1, || { - Decodable::decode(self) - }) + generics: do self.read_field("generics", 0) { + do self.read_struct("Generics", 2) { + ty::Generics { + type_param_defs: self.read_field("type_param_defs", 0, || { + @self.read_to_vec(|| self.read_type_param_def(xcx)) + }), + region_param: self.read_field(~"region_param", 1, || { + Decodable::decode(self) + }) + } } }, ty: self.read_field(~"ty", 1, || { @@ -1123,34 +1711,71 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) - -> ty::ty_param_bounds_and_ty - { - do self.read_struct("ty_param_bounds_and_ty", 2) { + #[cfg(not(stage0))] + fn read_ty_param_bounds_and_ty(&mut self, xcx: @ExtendedDecodeContext) + -> ty::ty_param_bounds_and_ty { + do self.read_struct("ty_param_bounds_and_ty", 2) |this| { ty::ty_param_bounds_and_ty { - generics: do self.read_struct("Generics", 2) { - ty::Generics { - type_param_defs: self.read_struct_field("type_param_defs", 0, || { - @self.read_to_vec(|| self.read_type_param_def(xcx)) - }), - region_param: self.read_struct_field(~"region_param", 1, || { - Decodable::decode(self) - }) + generics: do this.read_struct_field("generics", 0) |this| { + do this.read_struct("Generics", 2) |this| { + ty::Generics { + type_param_defs: + this.read_struct_field("type_param_defs", + 0, + |this| { + @this.read_to_vec(|this| + this.read_type_param_def(xcx)) + }), + region_param: + this.read_struct_field("region_param", + 1, + |this| { + Decodable::decode(this) + }) + } } }, - ty: self.read_struct_field("ty", 1, || { - self.read_ty(xcx) + ty: this.read_struct_field("ty", 1, |this| { + this.read_ty(xcx) }) } } } - fn convert_def_id(&self, xcx: @ExtendedDecodeContext, + #[cfg(stage0)] + fn convert_def_id(&self, + xcx: @ExtendedDecodeContext, source: tydecode::DefIdSource, - did: ast::def_id) -> ast::def_id { + did: ast::def_id) + -> ast::def_id { + /*! + * + * Converts a def-id that appears in a type. The correct + * translation will depend on what kind of def-id this is. + * This is a subtle point: type definitions are not + * inlined into the current crate, so if the def-id names + * a nominal type or type alias, then it should be + * translated to refer to the source crate. + * + * However, *type parameters* are cloned along with the function + * they are attached to. So we should translate those def-ids + * to refer to the new, cloned copy of the type parameter. + */ + + let r = match source { + NominalType | TypeWithId => xcx.tr_def_id(did), + TypeParameter => xcx.tr_intern_def_id(did) + }; + debug!("convert_def_id(source=%?, did=%?)=%?", source, did, r); + return r; + } + + #[cfg(not(stage0))] + fn convert_def_id(&mut self, + xcx: @ExtendedDecodeContext, + source: tydecode::DefIdSource, + did: ast::def_id) + -> ast::def_id { /*! * * Converts a def-id that appears in a type. The correct @@ -1174,6 +1799,7 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } +#[cfg(stage0)] fn decode_side_tables(xcx: @ExtendedDecodeContext, ast_doc: ebml::Doc) { let dcx = xcx.dcx; @@ -1248,21 +1874,97 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext, } } +#[cfg(not(stage0))] +fn decode_side_tables(xcx: @ExtendedDecodeContext, + ast_doc: ebml::Doc) { + let dcx = xcx.dcx; + let tbl_doc = ast_doc.get(c::tag_table as uint); + for reader::docs(tbl_doc) |tag, entry_doc| { + let id0 = entry_doc.get(c::tag_table_id as uint).as_int(); + let id = xcx.tr_id(id0); + + debug!(">> Side table document with tag 0x%x \ + found for id %d (orig %d)", + tag, id, id0); + + if tag == (c::tag_table_mutbl as uint) { + dcx.maps.mutbl_map.insert(id); + } else if tag == (c::tag_table_moves_map as uint) { + dcx.maps.moves_map.insert(id); + } else { + let val_doc = entry_doc.get(c::tag_table_val as uint); + let mut val_dsr = reader::Decoder(val_doc); + let val_dsr = &mut val_dsr; + if tag == (c::tag_table_def as uint) { + let def = decode_def(xcx, val_doc); + dcx.tcx.def_map.insert(id, def); + } else if tag == (c::tag_table_node_type as uint) { + let ty = val_dsr.read_ty(xcx); + debug!("inserting ty for node %?: %s", + id, ty_to_str(dcx.tcx, ty)); + dcx.tcx.node_types.insert(id as uint, ty); + } else if tag == (c::tag_table_node_type_subst as uint) { + let tys = val_dsr.read_tys(xcx); + dcx.tcx.node_type_substs.insert(id, tys); + } else if tag == (c::tag_table_freevars as uint) { + let fv_info = @val_dsr.read_to_vec(|val_dsr| { + @val_dsr.read_freevar_entry(xcx) + }); + dcx.tcx.freevars.insert(id, fv_info); + } else if tag == (c::tag_table_tcache as uint) { + let tpbt = val_dsr.read_ty_param_bounds_and_ty(xcx); + let lid = ast::def_id { crate: ast::local_crate, node: id }; + dcx.tcx.tcache.insert(lid, tpbt); + } else if tag == (c::tag_table_param_defs as uint) { + let bounds = val_dsr.read_type_param_def(xcx); + dcx.tcx.ty_param_defs.insert(id, bounds); + } else if tag == (c::tag_table_last_use as uint) { + let ids = val_dsr.read_to_vec(|val_dsr| { + xcx.tr_id(val_dsr.read_int()) + }); + dcx.maps.last_use_map.insert(id, @mut ids); + } else if tag == (c::tag_table_method_map as uint) { + dcx.maps.method_map.insert( + id, + val_dsr.read_method_map_entry(xcx)); + } else if tag == (c::tag_table_vtable_map as uint) { + dcx.maps.vtable_map.insert(id, + val_dsr.read_vtable_res(xcx)); + } else if tag == (c::tag_table_adjustments as uint) { + let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr); + adj.tr(xcx); + dcx.tcx.adjustments.insert(id, adj); + } else if tag == (c::tag_table_capture_map as uint) { + let cvars = + at_vec::from_owned( + val_dsr.read_to_vec( + |val_dsr| val_dsr.read_capture_var(xcx))); + dcx.maps.capture_map.insert(id, cvars); + } else { + xcx.dcx.tcx.sess.bug( + fmt!("unknown tag found in side tables: %x", tag)); + } + } + + debug!(">< Side table doc loaded"); + } +} + // ______________________________________________________________________ // Testing of astencode_gen #[cfg(test)] -fn encode_item_ast(ebml_w: &writer::Encoder, item: @ast::item) { - do ebml_w.wr_tag(c::tag_tree as uint) { - (*item).encode(ebml_w) - } +fn encode_item_ast(ebml_w: &mut writer::Encoder, item: @ast::item) { + ebml_w.start_tag(c::tag_tree as uint); + (*item).encode(ebml_w); + ebml_w.end_tag(); } #[cfg(test)] fn decode_item_ast(par_doc: ebml::Doc) -> @ast::item { let chi_doc = par_doc.get(c::tag_tree as uint); - let d = &reader::Decoder(chi_doc); - @Decodable::decode(d) + let mut d = reader::Decoder(chi_doc); + @Decodable::decode(&mut d) } #[cfg(test)] @@ -1303,8 +2005,8 @@ fn roundtrip(in_item: Option<@ast::item>) { let in_item = in_item.get(); let bytes = do io::with_bytes_writer |wr| { - let ebml_w = writer::Encoder(wr); - encode_item_ast(&ebml_w, in_item); + let mut ebml_w = writer::Encoder(wr); + encode_item_ast(&mut ebml_w, in_item); }; let ebml_doc = reader::Doc(@bytes); let out_item = decode_item_ast(ebml_doc); diff --git a/src/libstd/arena.rs b/src/libstd/arena.rs index bea7935d5c3a4..0e9b2ed3da89c 100644 --- a/src/libstd/arena.rs +++ b/src/libstd/arena.rs @@ -348,7 +348,7 @@ pub impl Arena { #[test] fn test_arena_destructors() { - let arena = Arena(); + let mut arena = Arena(); for uint::range(0, 10) |i| { // Arena allocate something with drop glue to make sure it // doesn't leak. @@ -363,7 +363,7 @@ fn test_arena_destructors() { #[should_fail] #[ignore(cfg(windows))] fn test_arena_destructors_fail() { - let arena = Arena(); + let mut arena = Arena(); // Put some stuff in the arena. for uint::range(0, 10) |i| { // Arena allocate something with drop glue to make sure it diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index 2598e96a141e2..41c5a0f7690cb 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -36,13 +36,27 @@ pub struct TaggedDoc { } pub enum EbmlEncoderTag { - EsUint, EsU64, EsU32, EsU16, EsU8, - EsInt, EsI64, EsI32, EsI16, EsI8, - EsBool, - EsStr, - EsF64, EsF32, EsFloat, - EsEnum, EsEnumVid, EsEnumBody, - EsVec, EsVecLen, EsVecElt, + EsUint, // 0 + EsU64, // 1 + EsU32, // 2 + EsU16, // 3 + EsU8, // 4 + EsInt, // 5 + EsI64, // 6 + EsI32, // 7 + EsI16, // 8 + EsI8, // 9 + EsBool, // 10 + EsStr, // 11 + EsF64, // 12 + EsF32, // 13 + EsFloat, // 14 + EsEnum, // 15 + EsEnumVid, // 16 + EsEnumBody, // 17 + EsVec, // 18 + EsVecLen, // 19 + EsVecElt, // 20 EsOpaque, @@ -249,17 +263,27 @@ pub mod reader { pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 } pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 } - + #[cfg(stage0)] pub struct Decoder { priv mut parent: Doc, priv mut pos: uint, } + #[cfg(not(stage0))] + pub struct Decoder { + priv parent: Doc, + priv pos: uint, + } + pub fn Decoder(d: Doc) -> Decoder { - Decoder { parent: d, pos: d.start } + Decoder { + parent: d, + pos: d.start + } } priv impl Decoder { + #[cfg(stage0)] fn _check_label(&self, lbl: &str) { if self.pos < self.parent.end { let TaggedDoc { tag: r_tag, doc: r_doc } = @@ -269,13 +293,33 @@ pub mod reader { self.pos = r_doc.end; let str = doc_as_str(r_doc); if lbl != str { - fail!(fmt!("Expected label %s but found %s", lbl, - str)); + fail!(fmt!("Expected label %s but found %s", + lbl, + str)); + } + } + } + } + + #[cfg(not(stage0))] + fn _check_label(&mut self, lbl: &str) { + if self.pos < self.parent.end { + let TaggedDoc { tag: r_tag, doc: r_doc } = + doc_at(self.parent.data, self.pos); + + if r_tag == (EsLabel as uint) { + self.pos = r_doc.end; + let str = doc_as_str(r_doc); + if lbl != str { + fail!(fmt!("Expected label %s but found %s", + lbl, + str)); } } } } + #[cfg(stage0)] fn next_doc(&self, exp_tag: EbmlEncoderTag) -> Doc { debug!(". next_doc(exp_tag=%?)", exp_tag); if self.pos >= self.parent.end { @@ -298,6 +342,30 @@ pub mod reader { r_doc } + #[cfg(not(stage0))] + fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> Doc { + debug!(". next_doc(exp_tag=%?)", exp_tag); + if self.pos >= self.parent.end { + fail!(~"no more documents in current node!"); + } + let TaggedDoc { tag: r_tag, doc: r_doc } = + doc_at(self.parent.data, self.pos); + debug!("self.parent=%?-%? self.pos=%? r_tag=%? r_doc=%?-%?", + copy self.parent.start, copy self.parent.end, + copy self.pos, r_tag, r_doc.start, r_doc.end); + if r_tag != (exp_tag as uint) { + fail!(fmt!("expected EBML doc with tag %? but found tag %?", + exp_tag, r_tag)); + } + if r_doc.end > self.parent.end { + fail!(fmt!("invalid EBML, child extends to 0x%x, \ + parent to 0x%x", r_doc.end, self.parent.end)); + } + self.pos = r_doc.end; + r_doc + } + + #[cfg(stage0)] fn push_doc(&self, d: Doc, f: &fn() -> T) -> T { let old_parent = self.parent; let old_pos = self.pos; @@ -309,21 +377,58 @@ pub mod reader { r } + #[cfg(not(stage0))] + fn push_doc(&mut self, d: Doc, f: &fn() -> T) -> T { + let old_parent = self.parent; + let old_pos = self.pos; + self.parent = d; + self.pos = d.start; + let r = f(); + self.parent = old_parent; + self.pos = old_pos; + r + } + + #[cfg(stage0)] fn _next_uint(&self, exp_tag: EbmlEncoderTag) -> uint { let r = doc_as_u32(self.next_doc(exp_tag)); debug!("_next_uint exp_tag=%? result=%?", exp_tag, r); r as uint } + + #[cfg(not(stage0))] + fn _next_uint(&mut self, exp_tag: EbmlEncoderTag) -> uint { + let r = doc_as_u32(self.next_doc(exp_tag)); + debug!("_next_uint exp_tag=%? result=%?", exp_tag, r); + r as uint + } } pub impl Decoder { + #[cfg(stage0)] fn read_opaque(&self, op: &fn(Doc) -> R) -> R { do self.push_doc(self.next_doc(EsOpaque)) { op(copy self.parent) } } + + #[cfg(not(stage0))] + fn read_opaque(&mut self, op: &fn(&mut Decoder, Doc) -> R) -> R { + let doc = self.next_doc(EsOpaque); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = doc.start; + + let result = op(self, doc); + + self.parent = old_parent; + self.pos = old_pos; + result + } } + #[cfg(stage0)] impl serialize::Decoder for Decoder { fn read_nil(&self) -> () { () } @@ -339,10 +444,18 @@ pub mod reader { v as uint } - fn read_i64(&self) -> i64 { doc_as_u64(self.next_doc(EsI64)) as i64 } - fn read_i32(&self) -> i32 { doc_as_u32(self.next_doc(EsI32)) as i32 } - fn read_i16(&self) -> i16 { doc_as_u16(self.next_doc(EsI16)) as i16 } - fn read_i8 (&self) -> i8 { doc_as_u8 (self.next_doc(EsI8 )) as i8 } + fn read_i64(&self) -> i64 { + doc_as_u64(self.next_doc(EsI64)) as i64 + } + fn read_i32(&self) -> i32 { + doc_as_u32(self.next_doc(EsI32)) as i32 + } + fn read_i16(&self) -> i16 { + doc_as_u16(self.next_doc(EsI16)) as i16 + } + fn read_i8 (&self) -> i8 { + doc_as_u8(self.next_doc(EsI8 )) as i8 + } fn read_int(&self) -> int { let v = doc_as_u64(self.next_doc(EsInt)) as i64; if v > (int::max_value as i64) || v < (int::min_value as i64) { @@ -351,8 +464,9 @@ pub mod reader { v as int } - fn read_bool(&self) -> bool { doc_as_u8(self.next_doc(EsBool)) - as bool } + fn read_bool(&self) -> bool { + doc_as_u8(self.next_doc(EsBool)) as bool + } fn read_f64(&self) -> f64 { fail!(~"read_f64()"); } fn read_f32(&self) -> f32 { fail!(~"read_f32()"); } @@ -367,7 +481,10 @@ pub mod reader { self.push_doc(self.next_doc(EsEnum), f) } - fn read_enum_variant(&self, _names: &[&str], f: &fn(uint) -> T) -> T { + fn read_enum_variant(&self, + _: &[&str], + f: &fn(uint) -> T) + -> T { debug!("read_enum_variant()"); let idx = self._next_uint(EsEnumVid); debug!(" idx=%u", idx); @@ -376,12 +493,17 @@ pub mod reader { } } - fn read_enum_variant_arg(&self, idx: uint, f: &fn() -> T) -> T { + fn read_enum_variant_arg(&self, + idx: uint, + f: &fn() -> T) -> T { debug!("read_enum_variant_arg(idx=%u)", idx); f() } - fn read_enum_struct_variant(&self, _names: &[&str], f: &fn(uint) -> T) -> T { + fn read_enum_struct_variant(&self, + _: &[&str], + f: &fn(uint) -> T) + -> T { debug!("read_enum_struct_variant()"); let idx = self._next_uint(EsEnumVid); debug!(" idx=%u", idx); @@ -390,32 +512,34 @@ pub mod reader { } } - fn read_enum_struct_variant_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + fn read_enum_struct_variant_field(&self, + name: &str, + idx: uint, + f: &fn() -> T) + -> T { debug!("read_enum_struct_variant_arg(name=%?, idx=%u)", name, idx); f() } - fn read_struct(&self, name: &str, _len: uint, f: &fn() -> T) -> T { + fn read_struct(&self, + name: &str, + _: uint, + f: &fn() -> T) + -> T { debug!("read_struct(name=%s)", name); f() } - #[cfg(stage0)] - fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + fn read_field(&self, + name: &str, + idx: uint, + f: &fn() -> T) + -> T { debug!("read_field(name=%?, idx=%u)", name, idx); self._check_label(name); f() } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn read_struct_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { - debug!("read_struct_field(name=%?, idx=%u)", name, idx); - self._check_label(name); - f() - } - fn read_tuple(&self, f: &fn(uint) -> T) -> T { debug!("read_tuple()"); self.read_seq(f) @@ -426,12 +550,18 @@ pub mod reader { self.read_seq_elt(idx, f) } - fn read_tuple_struct(&self, name: &str, f: &fn(uint) -> T) -> T { + fn read_tuple_struct(&self, + name: &str, + f: &fn(uint) -> T) + -> T { debug!("read_tuple_struct(name=%?)", name); self.read_tuple(f) } - fn read_tuple_struct_arg(&self, idx: uint, f: &fn() -> T) -> T { + fn read_tuple_struct_arg(&self, + idx: uint, + f: &fn() -> T) + -> T { debug!("read_tuple_struct_arg(idx=%u)", idx); self.read_tuple_arg(idx, f) } @@ -478,6 +608,245 @@ pub mod reader { fail!(~"read_map_elt_val is unimplemented"); } } + + #[cfg(not(stage0))] + impl serialize::Decoder for Decoder { + fn read_nil(&mut self) -> () { () } + + fn read_u64(&mut self) -> u64 { doc_as_u64(self.next_doc(EsU64)) } + fn read_u32(&mut self) -> u32 { doc_as_u32(self.next_doc(EsU32)) } + fn read_u16(&mut self) -> u16 { doc_as_u16(self.next_doc(EsU16)) } + fn read_u8 (&mut self) -> u8 { doc_as_u8 (self.next_doc(EsU8 )) } + fn read_uint(&mut self) -> uint { + let v = doc_as_u64(self.next_doc(EsUint)); + if v > (::core::uint::max_value as u64) { + fail!(fmt!("uint %? too large for this architecture", v)); + } + v as uint + } + + fn read_i64(&mut self) -> i64 { + doc_as_u64(self.next_doc(EsI64)) as i64 + } + fn read_i32(&mut self) -> i32 { + doc_as_u32(self.next_doc(EsI32)) as i32 + } + fn read_i16(&mut self) -> i16 { + doc_as_u16(self.next_doc(EsI16)) as i16 + } + fn read_i8 (&mut self) -> i8 { + doc_as_u8(self.next_doc(EsI8 )) as i8 + } + fn read_int(&mut self) -> int { + let v = doc_as_u64(self.next_doc(EsInt)) as i64; + if v > (int::max_value as i64) || v < (int::min_value as i64) { + fail!(fmt!("int %? out of range for this architecture", v)); + } + v as int + } + + fn read_bool(&mut self) -> bool { + doc_as_u8(self.next_doc(EsBool)) as bool + } + + fn read_f64(&mut self) -> f64 { fail!(~"read_f64()"); } + fn read_f32(&mut self) -> f32 { fail!(~"read_f32()"); } + fn read_float(&mut self) -> float { fail!(~"read_float()"); } + fn read_char(&mut self) -> char { fail!(~"read_char()"); } + fn read_str(&mut self) -> ~str { doc_as_str(self.next_doc(EsStr)) } + + // Compound types: + fn read_enum(&mut self, + name: &str, + f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_enum(%s)", name); + self._check_label(name); + + let doc = self.next_doc(EsEnum); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = f(self); + + self.parent = old_parent; + self.pos = old_pos; + result + } + + fn read_enum_variant(&mut self, + _: &[&str], + f: &fn(&mut Decoder, uint) -> T) + -> T { + debug!("read_enum_variant()"); + let idx = self._next_uint(EsEnumVid); + debug!(" idx=%u", idx); + + let doc = self.next_doc(EsEnumBody); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = f(self, idx); + + self.parent = old_parent; + self.pos = old_pos; + result + } + + fn read_enum_variant_arg(&mut self, + idx: uint, + f: &fn(&mut Decoder) -> T) -> T { + debug!("read_enum_variant_arg(idx=%u)", idx); + f(self) + } + + fn read_enum_struct_variant(&mut self, + _: &[&str], + f: &fn(&mut Decoder, uint) -> T) + -> T { + debug!("read_enum_struct_variant()"); + let idx = self._next_uint(EsEnumVid); + debug!(" idx=%u", idx); + + let doc = self.next_doc(EsEnumBody); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = f(self, idx); + + self.parent = old_parent; + self.pos = old_pos; + result + } + + fn read_enum_struct_variant_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_enum_struct_variant_arg(name=%?, idx=%u)", name, idx); + f(self) + } + + fn read_struct(&mut self, + name: &str, + _: uint, + f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_struct(name=%s)", name); + f(self) + } + + fn read_struct_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_struct_field(name=%?, idx=%u)", name, idx); + self._check_label(name); + f(self) + } + + fn read_tuple(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { + debug!("read_tuple()"); + self.read_seq(f) + } + + fn read_tuple_arg(&mut self, idx: uint, f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_tuple_arg(idx=%u)", idx); + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&mut self, + name: &str, + f: &fn(&mut Decoder, uint) -> T) + -> T { + debug!("read_tuple_struct(name=%?)", name); + self.read_tuple(f) + } + + fn read_tuple_struct_arg(&mut self, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_tuple_struct_arg(idx=%u)", idx); + self.read_tuple_arg(idx, f) + } + + fn read_option(&mut self, f: &fn(&mut Decoder, bool) -> T) -> T { + debug!("read_option()"); + do self.read_enum("Option") |this| { + do this.read_enum_variant(["None", "Some"]) |this, idx| { + match idx { + 0 => f(this, false), + 1 => f(this, true), + _ => fail!(), + } + } + } + } + + fn read_seq(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { + debug!("read_seq()"); + let doc = self.next_doc(EsVec); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let len = self._next_uint(EsVecLen); + debug!(" len=%u", len); + let result = f(self, len); + + self.parent = old_parent; + self.pos = old_pos; + result + } + + fn read_seq_elt(&mut self, idx: uint, f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_seq_elt(idx=%u)", idx); + let doc = self.next_doc(EsVecElt); + + let (old_parent, old_pos) = (self.parent, self.pos); + self.parent = doc; + self.pos = self.parent.start; + + let result = f(self); + + self.parent = old_parent; + self.pos = old_pos; + result + } + + fn read_map(&mut self, _: &fn(&mut Decoder, uint) -> T) -> T { + debug!("read_map()"); + fail!(~"read_map is unimplemented"); + } + + fn read_map_elt_key(&mut self, + idx: uint, + _: &fn(&mut Decoder) -> T) + -> T { + debug!("read_map_elt_key(idx=%u)", idx); + fail!(~"read_map_elt_val is unimplemented"); + } + + fn read_map_elt_val(&mut self, + idx: uint, + _: &fn(&mut Decoder) -> T) + -> T { + debug!("read_map_elt_val(idx=%u)", idx); + fail!(~"read_map_elt_val is unimplemented"); + } + } } pub mod writer { @@ -522,6 +891,7 @@ pub mod writer { } // FIXME (#2741): Provide a function to write the standard ebml header. + #[cfg(stage0)] pub impl Encoder { fn start_tag(&self, tag_id: uint) { debug!("Start tag %u", tag_id); @@ -617,13 +987,111 @@ pub mod writer { } } + // FIXME (#2741): Provide a function to write the standard ebml header. + #[cfg(not(stage0))] + pub impl Encoder { + fn start_tag(&mut self, tag_id: uint) { + debug!("Start tag %u", tag_id); + + // Write the enum ID: + write_vuint(self.writer, tag_id); + + // Write a placeholder four-byte size. + self.size_positions.push(self.writer.tell()); + let zeroes: &[u8] = &[0u8, 0u8, 0u8, 0u8]; + self.writer.write(zeroes); + } + + fn end_tag(&mut self) { + let last_size_pos = self.size_positions.pop(); + let cur_pos = self.writer.tell(); + self.writer.seek(last_size_pos as int, io::SeekSet); + let size = (cur_pos - last_size_pos - 4u); + write_sized_vuint(self.writer, size, 4u); + self.writer.seek(cur_pos as int, io::SeekSet); + + debug!("End tag (size = %u)", size); + } + + fn wr_tag(&mut self, tag_id: uint, blk: &fn()) { + self.start_tag(tag_id); + blk(); + self.end_tag(); + } + + fn wr_tagged_bytes(&mut self, tag_id: uint, b: &[u8]) { + write_vuint(self.writer, tag_id); + write_vuint(self.writer, vec::len(b)); + self.writer.write(b); + } + + fn wr_tagged_u64(&mut self, tag_id: uint, v: u64) { + do io::u64_to_be_bytes(v, 8u) |v| { + self.wr_tagged_bytes(tag_id, v); + } + } + + fn wr_tagged_u32(&mut self, tag_id: uint, v: u32) { + do io::u64_to_be_bytes(v as u64, 4u) |v| { + self.wr_tagged_bytes(tag_id, v); + } + } + + fn wr_tagged_u16(&mut self, tag_id: uint, v: u16) { + do io::u64_to_be_bytes(v as u64, 2u) |v| { + self.wr_tagged_bytes(tag_id, v); + } + } + + fn wr_tagged_u8(&mut self, tag_id: uint, v: u8) { + self.wr_tagged_bytes(tag_id, &[v]); + } + + fn wr_tagged_i64(&mut self, tag_id: uint, v: i64) { + do io::u64_to_be_bytes(v as u64, 8u) |v| { + self.wr_tagged_bytes(tag_id, v); + } + } + + fn wr_tagged_i32(&mut self, tag_id: uint, v: i32) { + do io::u64_to_be_bytes(v as u64, 4u) |v| { + self.wr_tagged_bytes(tag_id, v); + } + } + + fn wr_tagged_i16(&mut self, tag_id: uint, v: i16) { + do io::u64_to_be_bytes(v as u64, 2u) |v| { + self.wr_tagged_bytes(tag_id, v); + } + } + + fn wr_tagged_i8(&mut self, tag_id: uint, v: i8) { + self.wr_tagged_bytes(tag_id, &[v as u8]); + } + + fn wr_tagged_str(&mut self, tag_id: uint, v: &str) { + str::byte_slice(v, |b| self.wr_tagged_bytes(tag_id, b)); + } + + fn wr_bytes(&mut self, b: &[u8]) { + debug!("Write %u bytes", vec::len(b)); + self.writer.write(b); + } + + fn wr_str(&mut self, s: &str) { + debug!("Write str: %?", s); + self.writer.write(str::to_bytes(s)); + } + } + // FIXME (#2743): optionally perform "relaxations" on end_tag to more // efficiently encode sizes; this is a fixed point iteration // Set to true to generate more debugging in EBML code. // Totally lame approach. - static debug: bool = false; + static debug: bool = true; + #[cfg(stage0)] priv impl Encoder { // used internally to emit things like the vector length and so on fn _emit_tagged_uint(&self, t: EbmlEncoderTag, v: uint) { @@ -642,6 +1110,26 @@ pub mod writer { } } + #[cfg(not(stage0))] + priv impl Encoder { + // used internally to emit things like the vector length and so on + fn _emit_tagged_uint(&mut self, t: EbmlEncoderTag, v: uint) { + assert!(v <= 0xFFFF_FFFF_u); + self.wr_tagged_u32(t as uint, v as u32); + } + + fn _emit_label(&mut self, label: &str) { + // There are various strings that we have access to, such as + // the name of a record field, which do not actually appear in + // the encoded EBML (normally). This is just for + // efficiency. When debugging, though, we can emit such + // labels and then they will be checked by decoder to + // try and check failures more quickly. + if debug { self.wr_tagged_str(EsLabel as uint, label) } + } + } + + #[cfg(stage0)] pub impl Encoder { fn emit_opaque(&self, f: &fn()) { do self.wr_tag(EsOpaque as uint) { @@ -650,24 +1138,50 @@ pub mod writer { } } + #[cfg(not(stage0))] + pub impl Encoder { + fn emit_opaque(&mut self, f: &fn(&mut Encoder)) { + self.start_tag(EsOpaque as uint); + f(self); + self.end_tag(); + } + } + + #[cfg(stage0)] impl ::serialize::Encoder for Encoder { fn emit_nil(&self) {} fn emit_uint(&self, v: uint) { self.wr_tagged_u64(EsUint as uint, v as u64); } - fn emit_u64(&self, v: u64) { self.wr_tagged_u64(EsU64 as uint, v); } - fn emit_u32(&self, v: u32) { self.wr_tagged_u32(EsU32 as uint, v); } - fn emit_u16(&self, v: u16) { self.wr_tagged_u16(EsU16 as uint, v); } - fn emit_u8(&self, v: u8) { self.wr_tagged_u8 (EsU8 as uint, v); } + fn emit_u64(&self, v: u64) { + self.wr_tagged_u64(EsU64 as uint, v); + } + fn emit_u32(&self, v: u32) { + self.wr_tagged_u32(EsU32 as uint, v); + } + fn emit_u16(&self, v: u16) { + self.wr_tagged_u16(EsU16 as uint, v); + } + fn emit_u8(&self, v: u8) { + self.wr_tagged_u8(EsU8 as uint, v); + } fn emit_int(&self, v: int) { self.wr_tagged_i64(EsInt as uint, v as i64); } - fn emit_i64(&self, v: i64) { self.wr_tagged_i64(EsI64 as uint, v); } - fn emit_i32(&self, v: i32) { self.wr_tagged_i32(EsI32 as uint, v); } - fn emit_i16(&self, v: i16) { self.wr_tagged_i16(EsI16 as uint, v); } - fn emit_i8(&self, v: i8) { self.wr_tagged_i8 (EsI8 as uint, v); } + fn emit_i64(&self, v: i64) { + self.wr_tagged_i64(EsI64 as uint, v); + } + fn emit_i32(&self, v: i32) { + self.wr_tagged_i32(EsI32 as uint, v); + } + fn emit_i16(&self, v: i16) { + self.wr_tagged_i16(EsI16 as uint, v); + } + fn emit_i8(&self, v: i8) { + self.wr_tagged_i8(EsI8 as uint, v); + } fn emit_bool(&self, v: bool) { self.wr_tagged_u8(EsBool as uint, v as u8) @@ -697,41 +1211,56 @@ pub mod writer { self.wr_tag(EsEnum as uint, f) } - fn emit_enum_variant(&self, _v_name: &str, v_id: uint, _cnt: uint, + fn emit_enum_variant(&self, + _: &str, + v_id: uint, + _: uint, f: &fn()) { self._emit_tagged_uint(EsEnumVid, v_id); self.wr_tag(EsEnumBody as uint, f) } - fn emit_enum_variant_arg(&self, _idx: uint, f: &fn()) { f() } + fn emit_enum_variant_arg(&self, _: uint, f: &fn()) { + f() + } - fn emit_enum_struct_variant(&self, v_name: &str, v_id: uint, cnt: uint, f: &fn()) { + fn emit_enum_struct_variant(&self, + v_name: &str, + v_id: uint, + cnt: uint, + f: &fn()) { self.emit_enum_variant(v_name, v_id, cnt, f) } - fn emit_enum_struct_variant_field(&self, _f_name: &str, idx: uint, f: &fn()) { + fn emit_enum_struct_variant_field(&self, + _: &str, + idx: uint, + f: &fn()) { self.emit_enum_variant_arg(idx, f) } - fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) { f() } - #[cfg(stage0)] - fn emit_field(&self, name: &str, _idx: uint, f: &fn()) { - self._emit_label(name); + fn emit_struct(&self, _: &str, _len: uint, f: &fn()) { f() } - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn emit_struct_field(&self, name: &str, _idx: uint, f: &fn()) { + + fn emit_field(&self, name: &str, _idx: uint, f: &fn()) { self._emit_label(name); f() } - fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_tuple(&self, len: uint, f: &fn()) { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&self, idx: uint, f: &fn()) { + self.emit_seq_elt(idx, f) + } - fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { + self.emit_seq_elt(idx, f) + } fn emit_option(&self, f: &fn()) { self.emit_enum("Option", f); @@ -766,6 +1295,167 @@ pub mod writer { fail!(~"emit_map_elt_val is unimplemented"); } } + + #[cfg(not(stage0))] + impl ::serialize::Encoder for Encoder { + fn emit_nil(&mut self) {} + + fn emit_uint(&mut self, v: uint) { + self.wr_tagged_u64(EsUint as uint, v as u64); + } + fn emit_u64(&mut self, v: u64) { + self.wr_tagged_u64(EsU64 as uint, v); + } + fn emit_u32(&mut self, v: u32) { + self.wr_tagged_u32(EsU32 as uint, v); + } + fn emit_u16(&mut self, v: u16) { + self.wr_tagged_u16(EsU16 as uint, v); + } + fn emit_u8(&mut self, v: u8) { + self.wr_tagged_u8(EsU8 as uint, v); + } + + fn emit_int(&mut self, v: int) { + self.wr_tagged_i64(EsInt as uint, v as i64); + } + fn emit_i64(&mut self, v: i64) { + self.wr_tagged_i64(EsI64 as uint, v); + } + fn emit_i32(&mut self, v: i32) { + self.wr_tagged_i32(EsI32 as uint, v); + } + fn emit_i16(&mut self, v: i16) { + self.wr_tagged_i16(EsI16 as uint, v); + } + fn emit_i8(&mut self, v: i8) { + self.wr_tagged_i8(EsI8 as uint, v); + } + + fn emit_bool(&mut self, v: bool) { + self.wr_tagged_u8(EsBool as uint, v as u8) + } + + // FIXME (#2742): implement these + fn emit_f64(&mut self, _v: f64) { + fail!(~"Unimplemented: serializing an f64"); + } + fn emit_f32(&mut self, _v: f32) { + fail!(~"Unimplemented: serializing an f32"); + } + fn emit_float(&mut self, _v: float) { + fail!(~"Unimplemented: serializing a float"); + } + + fn emit_char(&mut self, _v: char) { + fail!(~"Unimplemented: serializing a char"); + } + + fn emit_str(&mut self, v: &str) { + self.wr_tagged_str(EsStr as uint, v) + } + + fn emit_enum(&mut self, name: &str, f: &fn(&mut Encoder)) { + self._emit_label(name); + self.start_tag(EsEnum as uint); + f(self); + self.end_tag(); + } + + fn emit_enum_variant(&mut self, + _: &str, + v_id: uint, + _: uint, + f: &fn(&mut Encoder)) { + self._emit_tagged_uint(EsEnumVid, v_id); + self.start_tag(EsEnumBody as uint); + f(self); + self.end_tag(); + } + + fn emit_enum_variant_arg(&mut self, _: uint, f: &fn(&mut Encoder)) { + f(self) + } + + fn emit_enum_struct_variant(&mut self, + v_name: &str, + v_id: uint, + cnt: uint, + f: &fn(&mut Encoder)) { + self.emit_enum_variant(v_name, v_id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: &fn(&mut Encoder)) { + self.emit_enum_variant_arg(idx, f) + } + + fn emit_struct(&mut self, _: &str, _len: uint, f: &fn(&mut Encoder)) { + f(self) + } + + fn emit_struct_field(&mut self, + name: &str, + _: uint, + f: &fn(&mut Encoder)) { + self._emit_label(name); + f(self) + } + + fn emit_tuple(&mut self, len: uint, f: &fn(&mut Encoder)) { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, + _: &str, + len: uint, + f: &fn(&mut Encoder)) { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: &fn(&mut Encoder)) { + self.emit_enum("Option", f); + } + fn emit_option_none(&mut self) { + self.emit_enum_variant("None", 0, 0, |_| ()) + } + fn emit_option_some(&mut self, f: &fn(&mut Encoder)) { + self.emit_enum_variant("Some", 1, 1, f) + } + + fn emit_seq(&mut self, len: uint, f: &fn(&mut Encoder)) { + self.start_tag(EsVec as uint); + self._emit_tagged_uint(EsVecLen, len); + f(self); + self.end_tag(); + } + + fn emit_seq_elt(&mut self, _idx: uint, f: &fn(&mut Encoder)) { + self.start_tag(EsVecElt as uint); + f(self); + self.end_tag(); + } + + fn emit_map(&mut self, _len: uint, _f: &fn(&mut Encoder)) { + fail!(~"emit_map is unimplemented"); + } + + fn emit_map_elt_key(&mut self, _idx: uint, _f: &fn(&mut Encoder)) { + fail!(~"emit_map_elt_key is unimplemented"); + } + + fn emit_map_elt_val(&mut self, _idx: uint, _f: &fn(&mut Encoder)) { + fail!(~"emit_map_elt_val is unimplemented"); + } + } } // ___________________________________________________________________________ @@ -786,12 +1476,12 @@ mod tests { fn test_v(v: Option) { debug!("v == %?", v); let bytes = do io::with_bytes_writer |wr| { - let ebml_w = writer::Encoder(wr); - v.encode(&ebml_w) + let mut ebml_w = writer::Encoder(wr); + v.encode(&mut ebml_w) }; let ebml_doc = reader::Doc(@bytes); - let deser = reader::Decoder(ebml_doc); - let v1 = serialize::Decodable::decode(&deser); + let mut deser = reader::Decoder(ebml_doc); + let v1 = serialize::Decodable::decode(&mut deser); debug!("v1 == %?", v1); assert!(v == v1); } diff --git a/src/libstd/flatpipes.rs b/src/libstd/flatpipes.rs index bd0acb849fcac..55ea9c2948b01 100644 --- a/src/libstd/flatpipes.rs +++ b/src/libstd/flatpipes.rs @@ -438,8 +438,11 @@ pub mod flatteners { SerializingFlattener */ + #[cfg(stage0)] pub fn deserialize_buffer>(buf: &[u8]) -> T { + T: Decodable>( + buf: &[u8]) + -> T { let buf = vec::from_slice(buf); let buf_reader = @BufReader::new(buf); let reader = buf_reader as @Reader; @@ -447,14 +450,40 @@ pub mod flatteners { Decodable::decode(&deser) } + #[cfg(not(stage0))] + pub fn deserialize_buffer>( + buf: &[u8]) + -> T { + let buf = vec::from_slice(buf); + let buf_reader = @BufReader::new(buf); + let reader = buf_reader as @Reader; + let mut deser: D = FromReader::from_reader(reader); + Decodable::decode(&mut deser) + } + + #[cfg(stage0)] pub fn serialize_value>(val: &T) -> ~[u8] { + T: Encodable>( + val: &T) + -> ~[u8] { do io::with_bytes_writer |writer| { let ser = FromWriter::from_writer(writer); val.encode(&ser); } } + #[cfg(not(stage0))] + pub fn serialize_value>( + val: &T) + -> ~[u8] { + do io::with_bytes_writer |writer| { + let mut ser = FromWriter::from_writer(writer); + val.encode(&mut ser); + } + } + pub trait FromReader { fn from_reader(r: @Reader) -> Self; } diff --git a/src/libstd/json.rs b/src/libstd/json.rs index 7353bec7333c5..6951ee377c92a 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -72,9 +72,12 @@ pub struct Encoder { } pub fn Encoder(wr: @io::Writer) -> Encoder { - Encoder { wr: wr } + Encoder { + wr: wr + } } +#[cfg(stage0)] impl serialize::Encoder for Encoder { fn emit_nil(&self) { self.wr.write_str("null") } @@ -109,7 +112,11 @@ impl serialize::Encoder for Encoder { fn emit_enum(&self, _name: &str, f: &fn()) { f() } - fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) { + fn emit_enum_variant(&self, + name: &str, + _id: uint, + cnt: uint, + f: &fn()) { // enums are encoded as strings or vectors: // Bunny => "Bunny" // Kangaroo(34,"William") => ["Kangaroo",[34,"William"]] @@ -130,19 +137,27 @@ impl serialize::Encoder for Encoder { f(); } - fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) { + fn emit_enum_struct_variant(&self, + name: &str, + id: uint, + cnt: uint, + f: &fn()) { self.emit_enum_variant(name, id, cnt, f) } - fn emit_enum_struct_variant_field(&self, _field: &str, idx: uint, f: &fn()) { + fn emit_enum_struct_variant_field(&self, + _: &str, + idx: uint, + f: &fn()) { self.emit_enum_variant_arg(idx, f) } - fn emit_struct(&self, _name: &str, _len: uint, f: &fn()) { + fn emit_struct(&self, _: &str, _: uint, f: &fn()) { self.wr.write_char('{'); f(); self.wr.write_char('}'); } + #[cfg(stage0)] fn emit_field(&self, name: &str, idx: uint, f: &fn()) { if idx != 0 { self.wr.write_char(','); } @@ -150,6 +165,7 @@ impl serialize::Encoder for Encoder { self.wr.write_char(':'); f(); } + #[cfg(stage1)] #[cfg(stage2)] #[cfg(stage3)] @@ -161,10 +177,16 @@ impl serialize::Encoder for Encoder { } fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_tuple_arg(&self, idx: uint, f: &fn()) { + self.emit_seq_elt(idx, f) + } - fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { + self.emit_seq_elt(idx, f) + } fn emit_option(&self, f: &fn()) { f(); } fn emit_option_none(&self) { self.emit_nil(); } @@ -198,15 +220,163 @@ impl serialize::Encoder for Encoder { } } +#[cfg(not(stage0))] +impl serialize::Encoder for Encoder { + fn emit_nil(&mut self) { self.wr.write_str("null") } + + fn emit_uint(&mut self, v: uint) { self.emit_float(v as float); } + fn emit_u64(&mut self, v: u64) { self.emit_float(v as float); } + fn emit_u32(&mut self, v: u32) { self.emit_float(v as float); } + fn emit_u16(&mut self, v: u16) { self.emit_float(v as float); } + fn emit_u8(&mut self, v: u8) { self.emit_float(v as float); } + + fn emit_int(&mut self, v: int) { self.emit_float(v as float); } + fn emit_i64(&mut self, v: i64) { self.emit_float(v as float); } + fn emit_i32(&mut self, v: i32) { self.emit_float(v as float); } + fn emit_i16(&mut self, v: i16) { self.emit_float(v as float); } + fn emit_i8(&mut self, v: i8) { self.emit_float(v as float); } + + fn emit_bool(&mut self, v: bool) { + if v { + self.wr.write_str("true"); + } else { + self.wr.write_str("false"); + } + } + + fn emit_f64(&mut self, v: f64) { self.emit_float(v as float); } + fn emit_f32(&mut self, v: f32) { self.emit_float(v as float); } + fn emit_float(&mut self, v: float) { + self.wr.write_str(float::to_str_digits(v, 6u)); + } + + fn emit_char(&mut self, v: char) { self.emit_str(str::from_char(v)) } + fn emit_str(&mut self, v: &str) { self.wr.write_str(escape_str(v)) } + + fn emit_enum(&mut self, _name: &str, f: &fn(&mut Encoder)) { f(self) } + + fn emit_enum_variant(&mut self, + name: &str, + _id: uint, + cnt: uint, + f: &fn(&mut Encoder)) { + // enums are encoded as strings or vectors: + // Bunny => "Bunny" + // Kangaroo(34,"William") => ["Kangaroo",[34,"William"]] + + if cnt == 0 { + self.wr.write_str(escape_str(name)); + } else { + self.wr.write_char('['); + self.wr.write_str(escape_str(name)); + self.wr.write_char(','); + f(self); + self.wr.write_char(']'); + } + } + + fn emit_enum_variant_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { + if idx != 0 { + self.wr.write_char(','); + } + f(self); + } + + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: &fn(&mut Encoder)) { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: &fn(&mut Encoder)) { + self.emit_enum_variant_arg(idx, f) + } + + fn emit_struct(&mut self, _: &str, _: uint, f: &fn(&mut Encoder)) { + self.wr.write_char('{'); + f(self); + self.wr.write_char('}'); + } + + fn emit_struct_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut Encoder)) { + if idx != 0 { self.wr.write_char(','); } + self.wr.write_str(escape_str(name)); + self.wr.write_char(':'); + f(self); + } + + fn emit_tuple(&mut self, len: uint, f: &fn(&mut Encoder)) { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, + _name: &str, + len: uint, + f: &fn(&mut Encoder)) { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, idx: uint, f: &fn(&mut Encoder)) { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: &fn(&mut Encoder)) { f(self); } + fn emit_option_none(&mut self) { self.emit_nil(); } + fn emit_option_some(&mut self, f: &fn(&mut Encoder)) { f(self); } + + fn emit_seq(&mut self, _len: uint, f: &fn(&mut Encoder)) { + self.wr.write_char('['); + f(self); + self.wr.write_char(']'); + } + + fn emit_seq_elt(&mut self, idx: uint, f: &fn(&mut Encoder)) { + if idx != 0 { + self.wr.write_char(','); + } + f(self) + } + + fn emit_map(&mut self, _len: uint, f: &fn(&mut Encoder)) { + self.wr.write_char('{'); + f(self); + self.wr.write_char('}'); + } + + fn emit_map_elt_key(&mut self, idx: uint, f: &fn(&mut Encoder)) { + if idx != 0 { self.wr.write_char(','); } + f(self) + } + + fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut Encoder)) { + self.wr.write_char(':'); + f(self) + } +} + pub struct PrettyEncoder { priv wr: @io::Writer, priv mut indent: uint, } pub fn PrettyEncoder(wr: @io::Writer) -> PrettyEncoder { - PrettyEncoder { wr: wr, indent: 0 } + PrettyEncoder { + wr: wr, + indent: 0, + } } +#[cfg(stage0)] impl serialize::Encoder for PrettyEncoder { fn emit_nil(&self) { self.wr.write_str("null") } @@ -241,7 +411,11 @@ impl serialize::Encoder for PrettyEncoder { fn emit_enum(&self, _name: &str, f: &fn()) { f() } - fn emit_enum_variant(&self, name: &str, _id: uint, cnt: uint, f: &fn()) { + fn emit_enum_variant(&self, + name: &str, + _: uint, + cnt: uint, + f: &fn()) { if cnt == 0 { self.wr.write_str(escape_str(name)); } else { @@ -267,11 +441,18 @@ impl serialize::Encoder for PrettyEncoder { f() } - fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) { + fn emit_enum_struct_variant(&self, + name: &str, + id: uint, + cnt: uint, + f: &fn()) { self.emit_enum_variant(name, id, cnt, f) } - fn emit_enum_struct_variant_field(&self, _field: &str, idx: uint, f: &fn()) { + fn emit_enum_struct_variant_field(&self, + _: &str, + idx: uint, + f: &fn()) { self.emit_enum_variant_arg(idx, f) } @@ -289,6 +470,7 @@ impl serialize::Encoder for PrettyEncoder { self.wr.write_char('}'); } } + #[cfg(stage0)] fn emit_field(&self, name: &str, idx: uint, f: &fn()) { if idx == 0 { @@ -301,6 +483,7 @@ impl serialize::Encoder for PrettyEncoder { self.wr.write_str(": "); f(); } + #[cfg(stage1)] #[cfg(stage2)] #[cfg(stage3)] @@ -316,11 +499,19 @@ impl serialize::Encoder for PrettyEncoder { f(); } - fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_tuple(&self, len: uint, f: &fn()) { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&self, idx: uint, f: &fn()) { + self.emit_seq_elt(idx, f) + } - fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { self.emit_seq_elt(idx, f) } + fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { + self.emit_seq_elt(idx, f) + } fn emit_option(&self, f: &fn()) { f(); } fn emit_option_none(&self) { self.emit_nil(); } @@ -339,6 +530,7 @@ impl serialize::Encoder for PrettyEncoder { self.wr.write_char(']'); } } + fn emit_seq_elt(&self, idx: uint, f: &fn()) { if idx == 0 { self.wr.write_char('\n'); @@ -362,6 +554,7 @@ impl serialize::Encoder for PrettyEncoder { self.wr.write_char('}'); } } + fn emit_map_elt_key(&self, idx: uint, f: &fn()) { if idx == 0 { self.wr.write_char('\n'); @@ -378,6 +571,201 @@ impl serialize::Encoder for PrettyEncoder { } } +#[cfg(not(stage0))] +impl serialize::Encoder for PrettyEncoder { + fn emit_nil(&mut self) { self.wr.write_str("null") } + + fn emit_uint(&mut self, v: uint) { self.emit_float(v as float); } + fn emit_u64(&mut self, v: u64) { self.emit_float(v as float); } + fn emit_u32(&mut self, v: u32) { self.emit_float(v as float); } + fn emit_u16(&mut self, v: u16) { self.emit_float(v as float); } + fn emit_u8(&mut self, v: u8) { self.emit_float(v as float); } + + fn emit_int(&mut self, v: int) { self.emit_float(v as float); } + fn emit_i64(&mut self, v: i64) { self.emit_float(v as float); } + fn emit_i32(&mut self, v: i32) { self.emit_float(v as float); } + fn emit_i16(&mut self, v: i16) { self.emit_float(v as float); } + fn emit_i8(&mut self, v: i8) { self.emit_float(v as float); } + + fn emit_bool(&mut self, v: bool) { + if v { + self.wr.write_str("true"); + } else { + self.wr.write_str("false"); + } + } + + fn emit_f64(&mut self, v: f64) { self.emit_float(v as float); } + fn emit_f32(&mut self, v: f32) { self.emit_float(v as float); } + fn emit_float(&mut self, v: float) { + self.wr.write_str(float::to_str_digits(v, 6u)); + } + + fn emit_char(&mut self, v: char) { self.emit_str(str::from_char(v)) } + fn emit_str(&mut self, v: &str) { self.wr.write_str(escape_str(v)); } + + fn emit_enum(&mut self, _name: &str, f: &fn(&mut PrettyEncoder)) { + f(self) + } + + fn emit_enum_variant(&mut self, + name: &str, + _: uint, + cnt: uint, + f: &fn(&mut PrettyEncoder)) { + if cnt == 0 { + self.wr.write_str(escape_str(name)); + } else { + self.wr.write_char('['); + self.indent += 2; + self.wr.write_char('\n'); + self.wr.write_str(spaces(self.indent)); + self.wr.write_str(escape_str(name)); + self.wr.write_str(",\n"); + f(self); + self.wr.write_char('\n'); + self.indent -= 2; + self.wr.write_str(spaces(self.indent)); + self.wr.write_char(']'); + } + } + + fn emit_enum_variant_arg(&mut self, + idx: uint, + f: &fn(&mut PrettyEncoder)) { + if idx != 0 { + self.wr.write_str(",\n"); + } + self.wr.write_str(spaces(self.indent)); + f(self) + } + + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: &fn(&mut PrettyEncoder)) { + self.emit_enum_variant(name, id, cnt, f) + } + + fn emit_enum_struct_variant_field(&mut self, + _: &str, + idx: uint, + f: &fn(&mut PrettyEncoder)) { + self.emit_enum_variant_arg(idx, f) + } + + + fn emit_struct(&mut self, + _: &str, + len: uint, + f: &fn(&mut PrettyEncoder)) { + if len == 0 { + self.wr.write_str("{}"); + } else { + self.wr.write_char('{'); + self.indent += 2; + f(self); + self.wr.write_char('\n'); + self.indent -= 2; + self.wr.write_str(spaces(self.indent)); + self.wr.write_char('}'); + } + } + + fn emit_struct_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut PrettyEncoder)) { + if idx == 0 { + self.wr.write_char('\n'); + } else { + self.wr.write_str(",\n"); + } + self.wr.write_str(spaces(self.indent)); + self.wr.write_str(escape_str(name)); + self.wr.write_str(": "); + f(self); + } + + fn emit_tuple(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { + self.emit_seq(len, f) + } + fn emit_tuple_arg(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { + self.emit_seq_elt(idx, f) + } + + fn emit_tuple_struct(&mut self, + _: &str, + len: uint, + f: &fn(&mut PrettyEncoder)) { + self.emit_seq(len, f) + } + fn emit_tuple_struct_arg(&mut self, + idx: uint, + f: &fn(&mut PrettyEncoder)) { + self.emit_seq_elt(idx, f) + } + + fn emit_option(&mut self, f: &fn(&mut PrettyEncoder)) { f(self); } + fn emit_option_none(&mut self) { self.emit_nil(); } + fn emit_option_some(&mut self, f: &fn(&mut PrettyEncoder)) { f(self); } + + fn emit_seq(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { + if len == 0 { + self.wr.write_str("[]"); + } else { + self.wr.write_char('['); + self.indent += 2; + f(self); + self.wr.write_char('\n'); + self.indent -= 2; + self.wr.write_str(spaces(self.indent)); + self.wr.write_char(']'); + } + } + + fn emit_seq_elt(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { + if idx == 0 { + self.wr.write_char('\n'); + } else { + self.wr.write_str(",\n"); + } + self.wr.write_str(spaces(self.indent)); + f(self) + } + + fn emit_map(&mut self, len: uint, f: &fn(&mut PrettyEncoder)) { + if len == 0 { + self.wr.write_str("{}"); + } else { + self.wr.write_char('{'); + self.indent += 2; + f(self); + self.wr.write_char('\n'); + self.indent -= 2; + self.wr.write_str(spaces(self.indent)); + self.wr.write_char('}'); + } + } + + fn emit_map_elt_key(&mut self, idx: uint, f: &fn(&mut PrettyEncoder)) { + if idx == 0 { + self.wr.write_char('\n'); + } else { + self.wr.write_str(",\n"); + } + self.wr.write_str(spaces(self.indent)); + f(self); + } + + fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut PrettyEncoder)) { + self.wr.write_str(": "); + f(self); + } +} + +#[cfg(stage0)] impl serialize::Encodable for Json { fn encode(&self, e: &E) { match *self { @@ -391,9 +779,32 @@ impl serialize::Encodable for Json { } } +#[cfg(not(stage0))] +impl serialize::Encodable for Json { + fn encode(&self, e: &mut E) { + match *self { + Number(v) => v.encode(e), + String(ref v) => v.encode(e), + Boolean(v) => v.encode(e), + List(ref v) => v.encode(e), + Object(ref v) => v.encode(e), + Null => e.emit_nil(), + } + } +} + /// Encodes a json value into a io::writer +#[cfg(stage0)] pub fn to_writer(wr: @io::Writer, json: &Json) { - json.encode(&Encoder(wr)) + let encoder = Encoder(wr); + json.encode(&encoder) +} + +/// Encodes a json value into a io::writer +#[cfg(not(stage0))] +pub fn to_writer(wr: @io::Writer, json: &Json) { + let mut encoder = Encoder(wr); + json.encode(&mut encoder) } /// Encodes a json value into a string @@ -402,8 +813,17 @@ pub fn to_str(json: &Json) -> ~str { } /// Encodes a json value into a io::writer +#[cfg(stage0)] pub fn to_pretty_writer(wr: @io::Writer, json: &Json) { - json.encode(&PrettyEncoder(wr)) + let encoder = PrettyEncoder(wr); + json.encode(&encoder) +} + +/// Encodes a json value into a io::writer +#[cfg(not(stage0))] +pub fn to_pretty_writer(wr: @io::Writer, json: &Json) { + let mut encoder = PrettyEncoder(wr); + json.encode(&mut encoder) } /// Encodes a json value into a string @@ -794,9 +1214,12 @@ pub struct Decoder { } pub fn Decoder(json: Json) -> Decoder { - Decoder { stack: ~[json] } + Decoder { + stack: ~[json] + } } +#[cfg(stage0)] impl serialize::Decoder for Decoder { fn read_nil(&self) -> () { debug!("read_nil"); @@ -856,7 +1279,10 @@ impl serialize::Decoder for Decoder { f() } - fn read_enum_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T { + fn read_enum_variant(&self, + names: &[&str], + f: &fn(uint) -> T) + -> T { debug!("read_enum_variant(names=%?)", names); let name = match self.stack.pop() { String(s) => s, @@ -883,13 +1309,20 @@ impl serialize::Decoder for Decoder { f() } - fn read_enum_struct_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T { + fn read_enum_struct_variant(&self, + names: &[&str], + f: &fn(uint) -> T) + -> T { debug!("read_enum_struct_variant(names=%?)", names); self.read_enum_variant(names, f) } - fn read_enum_struct_variant_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + fn read_enum_struct_variant_field(&self, + name: &str, + idx: uint, + f: &fn() -> T) + -> T { debug!("read_enum_struct_variant_field(name=%?, idx=%u)", name, idx); self.read_enum_variant_arg(idx, f) } @@ -924,7 +1357,11 @@ impl serialize::Decoder for Decoder { #[cfg(stage1)] #[cfg(stage2)] #[cfg(stage3)] - fn read_struct_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { + fn read_struct_field(&self, + name: &str, + idx: uint, + f: &fn() -> T) + -> T { debug!("read_struct_field(name=%?, idx=%u)", name, idx); match self.stack.pop() { Object(obj) => { @@ -1018,6 +1455,262 @@ impl serialize::Decoder for Decoder { } } +#[cfg(not(stage0))] +impl serialize::Decoder for Decoder { + fn read_nil(&mut self) -> () { + debug!("read_nil"); + match self.stack.pop() { + Null => (), + value => fail!(fmt!("not a null: %?", value)) + } + } + + fn read_u64(&mut self) -> u64 { self.read_float() as u64 } + fn read_u32(&mut self) -> u32 { self.read_float() as u32 } + fn read_u16(&mut self) -> u16 { self.read_float() as u16 } + fn read_u8 (&mut self) -> u8 { self.read_float() as u8 } + fn read_uint(&mut self) -> uint { self.read_float() as uint } + + fn read_i64(&mut self) -> i64 { self.read_float() as i64 } + fn read_i32(&mut self) -> i32 { self.read_float() as i32 } + fn read_i16(&mut self) -> i16 { self.read_float() as i16 } + fn read_i8 (&mut self) -> i8 { self.read_float() as i8 } + fn read_int(&mut self) -> int { self.read_float() as int } + + fn read_bool(&mut self) -> bool { + debug!("read_bool"); + match self.stack.pop() { + Boolean(b) => b, + value => fail!(fmt!("not a boolean: %?", value)) + } + } + + fn read_f64(&mut self) -> f64 { self.read_float() as f64 } + fn read_f32(&mut self) -> f32 { self.read_float() as f32 } + fn read_float(&mut self) -> float { + debug!("read_float"); + match self.stack.pop() { + Number(f) => f, + value => fail!(fmt!("not a number: %?", value)) + } + } + + fn read_char(&mut self) -> char { + let mut v = ~[]; + for str::each_char(self.read_str()) |c| { v.push(c) } + if v.len() != 1 { fail!(~"string must have one character") } + v[0] + } + + fn read_str(&mut self) -> ~str { + debug!("read_str"); + match self.stack.pop() { + String(s) => s, + json => fail!(fmt!("not a string: %?", json)) + } + } + + fn read_enum(&mut self, name: &str, f: &fn(&mut Decoder) -> T) -> T { + debug!("read_enum(%s)", name); + f(self) + } + + fn read_enum_variant(&mut self, + names: &[&str], + f: &fn(&mut Decoder, uint) -> T) + -> T { + debug!("read_enum_variant(names=%?)", names); + let name = match self.stack.pop() { + String(s) => s, + List(list) => { + do vec::consume_reverse(list) |_i, v| { + self.stack.push(v); + } + match self.stack.pop() { + String(s) => s, + value => fail!(fmt!("invalid variant name: %?", value)), + } + } + ref json => fail!(fmt!("invalid variant: %?", *json)), + }; + let idx = match vec::position(names, |n| str::eq_slice(*n, name)) { + Some(idx) => idx, + None => fail!(fmt!("Unknown variant name: %?", name)), + }; + f(self, idx) + } + + fn read_enum_variant_arg(&mut self, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_enum_variant_arg(idx=%u)", idx); + f(self) + } + + fn read_enum_struct_variant(&mut self, + names: &[&str], + f: &fn(&mut Decoder, uint) -> T) + -> T { + debug!("read_enum_struct_variant(names=%?)", names); + self.read_enum_variant(names, f) + } + + + fn read_enum_struct_variant_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_enum_struct_variant_field(name=%?, idx=%u)", name, idx); + self.read_enum_variant_arg(idx, f) + } + + fn read_struct(&mut self, + name: &str, + len: uint, + f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_struct(name=%s, len=%u)", name, len); + let value = f(self); + self.stack.pop(); + value + } + + #[cfg(stage0)] + fn read_field(&mut self, name: &str, idx: uint, f: &fn() -> T) -> T { + debug!("read_field(name=%?, idx=%u)", name, idx); + match self.stack.pop() { + Object(obj) => { + let mut obj = obj; + let value = match obj.pop(&name.to_owned()) { + None => fail!(fmt!("no such field: %s", name)), + Some(json) => { + self.stack.push(json); + f() + } + }; + self.stack.push(Object(obj)); + value + } + value => fail!(fmt!("not an object: %?", value)) + } + } + + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn read_struct_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_struct_field(name=%?, idx=%u)", name, idx); + match self.stack.pop() { + Object(obj) => { + let mut obj = obj; + let value = match obj.pop(&name.to_owned()) { + None => fail!(fmt!("no such field: %s", name)), + Some(json) => { + self.stack.push(json); + f(self) + } + }; + self.stack.push(Object(obj)); + value + } + value => fail!(fmt!("not an object: %?", value)) + } + } + + fn read_tuple(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { + debug!("read_tuple()"); + self.read_seq(f) + } + + fn read_tuple_arg(&mut self, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_tuple_arg(idx=%u)", idx); + self.read_seq_elt(idx, f) + } + + fn read_tuple_struct(&mut self, + name: &str, + f: &fn(&mut Decoder, uint) -> T) + -> T { + debug!("read_tuple_struct(name=%?)", name); + self.read_tuple(f) + } + + fn read_tuple_struct_arg(&mut self, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_tuple_struct_arg(idx=%u)", idx); + self.read_tuple_arg(idx, f) + } + + fn read_option(&mut self, f: &fn(&mut Decoder, bool) -> T) -> T { + match self.stack.pop() { + Null => f(self, false), + value => { self.stack.push(value); f(self, true) } + } + } + + fn read_seq(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { + debug!("read_seq()"); + let len = match self.stack.pop() { + List(list) => { + let len = list.len(); + do vec::consume_reverse(list) |_i, v| { + self.stack.push(v); + } + len + } + _ => fail!(~"not a list"), + }; + f(self, len) + } + + fn read_seq_elt(&mut self, idx: uint, f: &fn(&mut Decoder) -> T) -> T { + debug!("read_seq_elt(idx=%u)", idx); + f(self) + } + + fn read_map(&mut self, f: &fn(&mut Decoder, uint) -> T) -> T { + debug!("read_map()"); + let len = match self.stack.pop() { + Object(obj) => { + let mut obj = obj; + let len = obj.len(); + do obj.consume |key, value| { + self.stack.push(value); + self.stack.push(String(key)); + } + len + } + json => fail!(fmt!("not an object: %?", json)), + }; + f(self, len) + } + + fn read_map_elt_key(&mut self, + idx: uint, + f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_map_elt_key(idx=%u)", idx); + f(self) + } + + fn read_map_elt_val(&mut self, idx: uint, f: &fn(&mut Decoder) -> T) + -> T { + debug!("read_map_elt_val(idx=%u)", idx); + f(self) + } +} + impl Eq for Json { fn eq(&self, other: &Json) -> bool { match (self) { @@ -1452,15 +2145,15 @@ mod tests { let animal = Dog; assert_eq!( do io::with_str_writer |wr| { - let encoder = Encoder(wr); - animal.encode(&encoder); + let mut encoder = Encoder(wr); + animal.encode(&mut encoder); }, ~"\"Dog\"" ); assert_eq!( do io::with_str_writer |wr| { - let encoder = PrettyEncoder(wr); - animal.encode(&encoder); + let mut encoder = PrettyEncoder(wr); + animal.encode(&mut encoder); }, ~"\"Dog\"" ); @@ -1468,15 +2161,15 @@ mod tests { let animal = Frog(~"Henry", 349); assert_eq!( do io::with_str_writer |wr| { - let encoder = Encoder(wr); - animal.encode(&encoder); + let mut encoder = Encoder(wr); + animal.encode(&mut encoder); }, ~"[\"Frog\",\"Henry\",349]" ); assert_eq!( do io::with_str_writer |wr| { - let encoder = PrettyEncoder(wr); - animal.encode(&encoder); + let mut encoder = PrettyEncoder(wr); + animal.encode(&mut encoder); }, ~"\ [\n \ @@ -1491,15 +2184,15 @@ mod tests { fn test_write_some() { let value = Some(~"jodhpurs"); let s = do io::with_str_writer |wr| { - let encoder = Encoder(wr); - value.encode(&encoder); + let mut encoder = Encoder(wr); + value.encode(&mut encoder); }; assert_eq!(s, ~"\"jodhpurs\""); let value = Some(~"jodhpurs"); let s = do io::with_str_writer |wr| { - let encoder = PrettyEncoder(wr); - value.encode(&encoder); + let mut encoder = PrettyEncoder(wr); + value.encode(&mut encoder); }; assert_eq!(s, ~"\"jodhpurs\""); } @@ -1508,14 +2201,14 @@ mod tests { fn test_write_none() { let value: Option<~str> = None; let s = do io::with_str_writer |wr| { - let encoder = Encoder(wr); - value.encode(&encoder); + let mut encoder = Encoder(wr); + value.encode(&mut encoder); }; assert_eq!(s, ~"null"); let s = do io::with_str_writer |wr| { - let encoder = Encoder(wr); - value.encode(&encoder); + let mut encoder = Encoder(wr); + value.encode(&mut encoder); }; assert_eq!(s, ~"null"); } @@ -1563,13 +2256,16 @@ mod tests { #[test] fn test_decode_identifiers() { - let v: () = Decodable::decode(&Decoder(from_str(~"null").unwrap())); + let mut decoder = Decoder(from_str(~"null").unwrap()); + let v: () = Decodable::decode(&mut decoder); assert_eq!(v, ()); - let v: bool = Decodable::decode(&Decoder(from_str(~"true").unwrap())); + let mut decoder = Decoder(from_str(~"true").unwrap()); + let v: bool = Decodable::decode(&mut decoder); assert_eq!(v, true); - let v: bool = Decodable::decode(&Decoder(from_str(~"false").unwrap())); + let mut decoder = Decoder(from_str(~"false").unwrap()); + let v: bool = Decodable::decode(&mut decoder); assert_eq!(v, false); } @@ -1603,25 +2299,32 @@ mod tests { #[test] fn test_decode_numbers() { - let v: float = Decodable::decode(&Decoder(from_str(~"3").unwrap())); + let mut decoder = Decoder(from_str(~"3").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, 3f); - let v: float = Decodable::decode(&Decoder(from_str(~"3.1").unwrap())); + let mut decoder = Decoder(from_str(~"3.1").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, 3.1f); - let v: float = Decodable::decode(&Decoder(from_str(~"-1.2").unwrap())); + let mut decoder = Decoder(from_str(~"-1.2").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, -1.2f); - let v: float = Decodable::decode(&Decoder(from_str(~"0.4").unwrap())); + let mut decoder = Decoder(from_str(~"0.4").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, 0.4f); - let v: float = Decodable::decode(&Decoder(from_str(~"0.4e5").unwrap())); + let mut decoder = Decoder(from_str(~"0.4e5").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, 0.4e5f); - let v: float = Decodable::decode(&Decoder(from_str(~"0.4e15").unwrap())); + let mut decoder = Decoder(from_str(~"0.4e15").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, 0.4e15f); - let v: float = Decodable::decode(&Decoder(from_str(~"0.4e-01").unwrap())); + let mut decoder = Decoder(from_str(~"0.4e-01").unwrap()); + let v: float = Decodable::decode(&mut decoder); assert_eq!(v, 0.4e-01f); } @@ -1648,31 +2351,40 @@ mod tests { #[test] fn test_decode_str() { - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~""); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"foo\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"foo\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"foo"); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\\"\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\\"\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\""); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\b\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\b\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\x08"); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\n\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\n\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\n"); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\r\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\r\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\r"); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\t\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\t\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\t"); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\u12ab\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\u12ab\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\u12ab"); - let v: ~str = Decodable::decode(&Decoder(from_str(~"\"\\uAB12\"").unwrap())); + let mut decoder = Decoder(from_str(~"\"\\uAB12\"").unwrap()); + let v: ~str = Decodable::decode(&mut decoder); assert_eq!(v, ~"\uAB12"); } @@ -1704,23 +2416,28 @@ mod tests { #[test] fn test_decode_list() { - let v: ~[()] = Decodable::decode(&Decoder(from_str(~"[]").unwrap())); + let mut decoder = Decoder(from_str(~"[]").unwrap()); + let v: ~[()] = Decodable::decode(&mut decoder); assert_eq!(v, ~[]); - let v: ~[()] = Decodable::decode(&Decoder(from_str(~"[null]").unwrap())); + let mut decoder = Decoder(from_str(~"[null]").unwrap()); + let v: ~[()] = Decodable::decode(&mut decoder); assert_eq!(v, ~[()]); - - let v: ~[bool] = Decodable::decode(&Decoder(from_str(~"[true]").unwrap())); + let mut decoder = Decoder(from_str(~"[true]").unwrap()); + let v: ~[bool] = Decodable::decode(&mut decoder); assert_eq!(v, ~[true]); - let v: ~[bool] = Decodable::decode(&Decoder(from_str(~"[true]").unwrap())); + let mut decoder = Decoder(from_str(~"[true]").unwrap()); + let v: ~[bool] = Decodable::decode(&mut decoder); assert_eq!(v, ~[true]); - let v: ~[int] = Decodable::decode(&Decoder(from_str(~"[3, 1]").unwrap())); + let mut decoder = Decoder(from_str(~"[3, 1]").unwrap()); + let v: ~[int] = Decodable::decode(&mut decoder); assert_eq!(v, ~[3, 1]); - let v: ~[~[uint]] = Decodable::decode(&Decoder(from_str(~"[[3], [1, 2]]").unwrap())); + let mut decoder = Decoder(from_str(~"[[3], [1, 2]]").unwrap()); + let v: ~[~[uint]] = Decodable::decode(&mut decoder); assert_eq!(v, ~[~[3], ~[1, 2]]); } @@ -1822,7 +2539,8 @@ mod tests { { \"a\": null, \"b\": 2, \"c\": [\"abc\", \"xyz\"] } ] }"; - let v: Outer = Decodable::decode(&Decoder(from_str(s).unwrap())); + let mut decoder = Decoder(from_str(s).unwrap()); + let v: Outer = Decodable::decode(&mut decoder); assert_eq!( v, Outer { @@ -1835,31 +2553,32 @@ mod tests { #[test] fn test_decode_option() { - let decoder = Decoder(from_str(~"null").unwrap()); - let value: Option<~str> = Decodable::decode(&decoder); + let mut decoder = Decoder(from_str(~"null").unwrap()); + let value: Option<~str> = Decodable::decode(&mut decoder); assert_eq!(value, None); - let decoder = Decoder(from_str(~"\"jodhpurs\"").unwrap()); - let value: Option<~str> = Decodable::decode(&decoder); + let mut decoder = Decoder(from_str(~"\"jodhpurs\"").unwrap()); + let value: Option<~str> = Decodable::decode(&mut decoder); assert_eq!(value, Some(~"jodhpurs")); } #[test] fn test_decode_enum() { - let decoder = Decoder(from_str(~"\"Dog\"").unwrap()); - let value: Animal = Decodable::decode(&decoder); + let mut decoder = Decoder(from_str(~"\"Dog\"").unwrap()); + let value: Animal = Decodable::decode(&mut decoder); assert_eq!(value, Dog); - let decoder = Decoder(from_str(~"[\"Frog\",\"Henry\",349]").unwrap()); - let value: Animal = Decodable::decode(&decoder); + let mut decoder = + Decoder(from_str(~"[\"Frog\",\"Henry\",349]").unwrap()); + let value: Animal = Decodable::decode(&mut decoder); assert_eq!(value, Frog(~"Henry", 349)); } #[test] fn test_decode_map() { let s = ~"{\"a\": \"Dog\", \"b\": [\"Frog\", \"Henry\", 349]}"; - let decoder = Decoder(from_str(s).unwrap()); - let mut map: HashMap<~str, Animal> = Decodable::decode(&decoder); + let mut decoder = Decoder(from_str(s).unwrap()); + let mut map: HashMap<~str, Animal> = Decodable::decode(&mut decoder); assert_eq!(map.pop(&~"a"), Some(Dog)); assert_eq!(map.pop(&~"b"), Some(Frog(~"Henry", 349))); diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index 1ad581ba993e4..33efb2c6a5af4 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -25,6 +25,7 @@ use dlist::DList; #[cfg(stage3)] use treemap::{TreeMap, TreeSet}; +#[cfg(stage0)] pub trait Encoder { // Primitive types: fn emit_nil(&self); @@ -48,11 +49,22 @@ pub trait Encoder { // Compound types: fn emit_enum(&self, name: &str, f: &fn()); - fn emit_enum_variant(&self, v_name: &str, v_id: uint, len: uint, f: &fn()); + fn emit_enum_variant(&self, + v_name: &str, + v_id: uint, + len: uint, + f: &fn()); fn emit_enum_variant_arg(&self, a_idx: uint, f: &fn()); - fn emit_enum_struct_variant(&self, v_name: &str, v_id: uint, len: uint, f: &fn()); - fn emit_enum_struct_variant_field(&self, f_name: &str, f_idx: uint, f: &fn()); + fn emit_enum_struct_variant(&self, + v_name: &str, + v_id: uint, + len: uint, + f: &fn()); + fn emit_enum_struct_variant_field(&self, + f_name: &str, + f_idx: uint, + f: &fn()); fn emit_struct(&self, name: &str, len: uint, f: &fn()); #[cfg(stage0)] @@ -81,6 +93,73 @@ pub trait Encoder { fn emit_map_elt_val(&self, idx: uint, f: &fn()); } +#[cfg(not(stage0))] +pub trait Encoder { + // Primitive types: + fn emit_nil(&mut self); + fn emit_uint(&mut self, v: uint); + fn emit_u64(&mut self, v: u64); + fn emit_u32(&mut self, v: u32); + fn emit_u16(&mut self, v: u16); + fn emit_u8(&mut self, v: u8); + fn emit_int(&mut self, v: int); + fn emit_i64(&mut self, v: i64); + fn emit_i32(&mut self, v: i32); + fn emit_i16(&mut self, v: i16); + fn emit_i8(&mut self, v: i8); + fn emit_bool(&mut self, v: bool); + fn emit_float(&mut self, v: float); + fn emit_f64(&mut self, v: f64); + fn emit_f32(&mut self, v: f32); + fn emit_char(&mut self, v: char); + fn emit_str(&mut self, v: &str); + + // Compound types: + fn emit_enum(&mut self, name: &str, f: &fn(&mut Self)); + + fn emit_enum_variant(&mut self, + v_name: &str, + v_id: uint, + len: uint, + f: &fn(&mut Self)); + fn emit_enum_variant_arg(&mut self, a_idx: uint, f: &fn(&mut Self)); + + fn emit_enum_struct_variant(&mut self, + v_name: &str, + v_id: uint, + len: uint, + f: &fn(&mut Self)); + fn emit_enum_struct_variant_field(&mut self, + f_name: &str, + f_idx: uint, + f: &fn(&mut Self)); + + fn emit_struct(&mut self, name: &str, len: uint, f: &fn(&mut Self)); + fn emit_struct_field(&mut self, + f_name: &str, + f_idx: uint, + f: &fn(&mut Self)); + + fn emit_tuple(&mut self, len: uint, f: &fn(&mut Self)); + fn emit_tuple_arg(&mut self, idx: uint, f: &fn(&mut Self)); + + fn emit_tuple_struct(&mut self, name: &str, len: uint, f: &fn(&mut Self)); + fn emit_tuple_struct_arg(&mut self, f_idx: uint, f: &fn(&mut Self)); + + // Specialized types: + fn emit_option(&mut self, f: &fn(&mut Self)); + fn emit_option_none(&mut self); + fn emit_option_some(&mut self, f: &fn(&mut Self)); + + fn emit_seq(&mut self, len: uint, f: &fn(this: &mut Self)); + fn emit_seq_elt(&mut self, idx: uint, f: &fn(this: &mut Self)); + + fn emit_map(&mut self, len: uint, f: &fn(&mut Self)); + fn emit_map_elt_key(&mut self, idx: uint, f: &fn(&mut Self)); + fn emit_map_elt_val(&mut self, idx: uint, f: &fn(&mut Self)); +} + +#[cfg(stage0)] pub trait Decoder { // Primitive types: fn read_nil(&self) -> (); @@ -104,19 +183,37 @@ pub trait Decoder { // Compound types: fn read_enum(&self, name: &str, f: &fn() -> T) -> T; - fn read_enum_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T; + fn read_enum_variant(&self, + names: &[&str], + f: &fn(uint) -> T) + -> T; fn read_enum_variant_arg(&self, a_idx: uint, f: &fn() -> T) -> T; - fn read_enum_struct_variant(&self, names: &[&str], f: &fn(uint) -> T) -> T; - fn read_enum_struct_variant_field(&self, &f_name: &str, f_idx: uint, f: &fn() -> T) -> T; + fn read_enum_struct_variant(&self, + names: &[&str], + f: &fn(uint) -> T) + -> T; + fn read_enum_struct_variant_field(&self, + &f_name: &str, + f_idx: uint, + f: &fn() -> T) + -> T; fn read_struct(&self, s_name: &str, len: uint, f: &fn() -> T) -> T; #[cfg(stage0)] - fn read_field(&self, f_name: &str, f_idx: uint, f: &fn() -> T) -> T; + fn read_field(&self, + f_name: &str, + f_idx: uint, + f: &fn() -> T) + -> T; #[cfg(stage1)] #[cfg(stage2)] #[cfg(stage3)] - fn read_struct_field(&self, f_name: &str, f_idx: uint, f: &fn() -> T) -> T; + fn read_struct_field(&self, + f_name: &str, + f_idx: uint, + f: &fn() -> T) + -> T; fn read_tuple(&self, f: &fn(uint) -> T) -> T; fn read_tuple_arg(&self, a_idx: uint, f: &fn() -> T) -> T; @@ -135,215 +232,673 @@ pub trait Decoder { fn read_map_elt_val(&self, idx: uint, f: &fn() -> T) -> T; } +#[cfg(not(stage0))] +pub trait Decoder { + // Primitive types: + fn read_nil(&mut self) -> (); + fn read_uint(&mut self) -> uint; + fn read_u64(&mut self) -> u64; + fn read_u32(&mut self) -> u32; + fn read_u16(&mut self) -> u16; + fn read_u8(&mut self) -> u8; + fn read_int(&mut self) -> int; + fn read_i64(&mut self) -> i64; + fn read_i32(&mut self) -> i32; + fn read_i16(&mut self) -> i16; + fn read_i8(&mut self) -> i8; + fn read_bool(&mut self) -> bool; + fn read_f64(&mut self) -> f64; + fn read_f32(&mut self) -> f32; + fn read_float(&mut self) -> float; + fn read_char(&mut self) -> char; + fn read_str(&mut self) -> ~str; + + // Compound types: + fn read_enum(&mut self, name: &str, f: &fn(&mut Self) -> T) -> T; + + fn read_enum_variant(&mut self, + names: &[&str], + f: &fn(&mut Self, uint) -> T) + -> T; + fn read_enum_variant_arg(&mut self, + a_idx: uint, + f: &fn(&mut Self) -> T) + -> T; + + fn read_enum_struct_variant(&mut self, + names: &[&str], + f: &fn(&mut Self, uint) -> T) + -> T; + fn read_enum_struct_variant_field(&mut self, + &f_name: &str, + f_idx: uint, + f: &fn(&mut Self) -> T) + -> T; + + fn read_struct(&mut self, + s_name: &str, + len: uint, + f: &fn(&mut Self) -> T) + -> T; + #[cfg(stage0)] + fn read_field(&mut self, + f_name: &str, + f_idx: uint, + f: &fn() -> T) + -> T; + #[cfg(stage1)] + #[cfg(stage2)] + #[cfg(stage3)] + fn read_struct_field(&mut self, + f_name: &str, + f_idx: uint, + f: &fn(&mut Self) -> T) + -> T; + + fn read_tuple(&mut self, f: &fn(&mut Self, uint) -> T) -> T; + fn read_tuple_arg(&mut self, a_idx: uint, f: &fn(&mut Self) -> T) -> T; + + fn read_tuple_struct(&mut self, + s_name: &str, + f: &fn(&mut Self, uint) -> T) + -> T; + fn read_tuple_struct_arg(&mut self, + a_idx: uint, + f: &fn(&mut Self) -> T) + -> T; + + // Specialized types: + fn read_option(&mut self, f: &fn(&mut Self, bool) -> T) -> T; + + fn read_seq(&mut self, f: &fn(&mut Self, uint) -> T) -> T; + fn read_seq_elt(&mut self, idx: uint, f: &fn(&mut Self) -> T) -> T; + + fn read_map(&mut self, f: &fn(&mut Self, uint) -> T) -> T; + fn read_map_elt_key(&mut self, idx: uint, f: &fn(&mut Self) -> T) -> T; + fn read_map_elt_val(&mut self, idx: uint, f: &fn(&mut Self) -> T) -> T; +} + +#[cfg(stage0)] pub trait Encodable { fn encode(&self, s: &S); } +#[cfg(not(stage0))] +pub trait Encodable { + fn encode(&self, s: &mut S); +} + +#[cfg(stage0)] pub trait Decodable { fn decode(d: &D) -> Self; } +#[cfg(not(stage0))] +pub trait Decodable { + fn decode(d: &mut D) -> Self; +} + +#[cfg(stage0)] impl Encodable for uint { - fn encode(&self, s: &S) { s.emit_uint(*self) } + fn encode(&self, s: &S) { + s.emit_uint(*self) + } } +#[cfg(not(stage0))] +impl Encodable for uint { + fn encode(&self, s: &mut S) { + s.emit_uint(*self) + } +} + +#[cfg(stage0)] impl Decodable for uint { fn decode(d: &D) -> uint { d.read_uint() } } +#[cfg(not(stage0))] +impl Decodable for uint { + fn decode(d: &mut D) -> uint { + d.read_uint() + } +} + +#[cfg(stage0)] impl Encodable for u8 { - fn encode(&self, s: &S) { s.emit_u8(*self) } + fn encode(&self, s: &S) { + s.emit_u8(*self) + } +} + +#[cfg(not(stage0))] +impl Encodable for u8 { + fn encode(&self, s: &mut S) { + s.emit_u8(*self) + } } +#[cfg(stage0)] impl Decodable for u8 { fn decode(d: &D) -> u8 { d.read_u8() } } +#[cfg(not(stage0))] +impl Decodable for u8 { + fn decode(d: &mut D) -> u8 { + d.read_u8() + } +} + +#[cfg(stage0)] impl Encodable for u16 { - fn encode(&self, s: &S) { s.emit_u16(*self) } + fn encode(&self, s: &S) { + s.emit_u16(*self) + } +} + +#[cfg(not(stage0))] +impl Encodable for u16 { + fn encode(&self, s: &mut S) { + s.emit_u16(*self) + } } +#[cfg(stage0)] impl Decodable for u16 { fn decode(d: &D) -> u16 { d.read_u16() } } +#[cfg(not(stage0))] +impl Decodable for u16 { + fn decode(d: &mut D) -> u16 { + d.read_u16() + } +} + +#[cfg(stage0)] impl Encodable for u32 { - fn encode(&self, s: &S) { s.emit_u32(*self) } + fn encode(&self, s: &S) { + s.emit_u32(*self) + } +} + +#[cfg(not(stage0))] +impl Encodable for u32 { + fn encode(&self, s: &mut S) { + s.emit_u32(*self) + } } +#[cfg(stage0)] impl Decodable for u32 { fn decode(d: &D) -> u32 { d.read_u32() } } +#[cfg(not(stage0))] +impl Decodable for u32 { + fn decode(d: &mut D) -> u32 { + d.read_u32() + } +} + +#[cfg(stage0)] +impl Encodable for u64 { + fn encode(&self, s: &S) { + s.emit_u64(*self) + } +} + +#[cfg(not(stage0))] impl Encodable for u64 { - fn encode(&self, s: &S) { s.emit_u64(*self) } + fn encode(&self, s: &mut S) { + s.emit_u64(*self) + } } +#[cfg(stage0)] impl Decodable for u64 { fn decode(d: &D) -> u64 { d.read_u64() } } +#[cfg(not(stage0))] +impl Decodable for u64 { + fn decode(d: &mut D) -> u64 { + d.read_u64() + } +} + +#[cfg(stage0)] impl Encodable for int { - fn encode(&self, s: &S) { s.emit_int(*self) } + fn encode(&self, s: &S) { + s.emit_int(*self) + } } +#[cfg(not(stage0))] +impl Encodable for int { + fn encode(&self, s: &mut S) { + s.emit_int(*self) + } +} + +#[cfg(stage0)] impl Decodable for int { fn decode(d: &D) -> int { d.read_int() } } +#[cfg(not(stage0))] +impl Decodable for int { + fn decode(d: &mut D) -> int { + d.read_int() + } +} + +#[cfg(stage0)] +impl Encodable for i8 { + fn encode(&self, s: &S) { + s.emit_i8(*self) + } +} + +#[cfg(not(stage0))] impl Encodable for i8 { - fn encode(&self, s: &S) { s.emit_i8(*self) } + fn encode(&self, s: &mut S) { + s.emit_i8(*self) + } } +#[cfg(stage0)] impl Decodable for i8 { fn decode(d: &D) -> i8 { d.read_i8() } } +#[cfg(not(stage0))] +impl Decodable for i8 { + fn decode(d: &mut D) -> i8 { + d.read_i8() + } +} + +#[cfg(stage0)] +impl Encodable for i16 { + fn encode(&self, s: &S) { + s.emit_i16(*self) + } +} + +#[cfg(not(stage0))] impl Encodable for i16 { - fn encode(&self, s: &S) { s.emit_i16(*self) } + fn encode(&self, s: &mut S) { + s.emit_i16(*self) + } } +#[cfg(stage0)] impl Decodable for i16 { fn decode(d: &D) -> i16 { d.read_i16() } } +#[cfg(not(stage0))] +impl Decodable for i16 { + fn decode(d: &mut D) -> i16 { + d.read_i16() + } +} + +#[cfg(stage0)] +impl Encodable for i32 { + fn encode(&self, s: &S) { + s.emit_i32(*self) + } +} + +#[cfg(not(stage0))] impl Encodable for i32 { - fn encode(&self, s: &S) { s.emit_i32(*self) } + fn encode(&self, s: &mut S) { + s.emit_i32(*self) + } } +#[cfg(stage0)] impl Decodable for i32 { fn decode(d: &D) -> i32 { d.read_i32() } } +#[cfg(not(stage0))] +impl Decodable for i32 { + fn decode(d: &mut D) -> i32 { + d.read_i32() + } +} + +#[cfg(stage0)] impl Encodable for i64 { - fn encode(&self, s: &S) { s.emit_i64(*self) } + fn encode(&self, s: &S) { + s.emit_i64(*self) + } +} + +#[cfg(not(stage0))] +impl Encodable for i64 { + fn encode(&self, s: &mut S) { + s.emit_i64(*self) + } } +#[cfg(stage0)] impl Decodable for i64 { fn decode(d: &D) -> i64 { d.read_i64() } } +#[cfg(not(stage0))] +impl Decodable for i64 { + fn decode(d: &mut D) -> i64 { + d.read_i64() + } +} + +#[cfg(stage0)] impl<'self, S:Encoder> Encodable for &'self str { - fn encode(&self, s: &S) { s.emit_str(*self) } + fn encode(&self, s: &S) { + s.emit_str(*self) + } } +#[cfg(not(stage0))] +impl<'self, S:Encoder> Encodable for &'self str { + fn encode(&self, s: &mut S) { + s.emit_str(*self) + } +} + +#[cfg(stage0)] +impl Encodable for ~str { + fn encode(&self, s: &S) { + s.emit_str(*self) + } +} + +#[cfg(not(stage0))] impl Encodable for ~str { - fn encode(&self, s: &S) { s.emit_str(*self) } + fn encode(&self, s: &mut S) { + s.emit_str(*self) + } } +#[cfg(stage0)] impl Decodable for ~str { fn decode(d: &D) -> ~str { d.read_str() } } +#[cfg(not(stage0))] +impl Decodable for ~str { + fn decode(d: &mut D) -> ~str { + d.read_str() + } +} + +#[cfg(stage0)] +impl Encodable for @str { + fn encode(&self, s: &S) { + s.emit_str(*self) + } +} + +#[cfg(not(stage0))] impl Encodable for @str { - fn encode(&self, s: &S) { s.emit_str(*self) } + fn encode(&self, s: &mut S) { + s.emit_str(*self) + } } +#[cfg(stage0)] impl Decodable for @str { - fn decode(d: &D) -> @str { d.read_str().to_managed() } + fn decode(d: &D) -> @str { + d.read_str().to_managed() + } } +#[cfg(not(stage0))] +impl Decodable for @str { + fn decode(d: &mut D) -> @str { + d.read_str().to_managed() + } +} + +#[cfg(stage0)] impl Encodable for float { - fn encode(&self, s: &S) { s.emit_float(*self) } + fn encode(&self, s: &S) { + s.emit_float(*self) + } } +#[cfg(not(stage0))] +impl Encodable for float { + fn encode(&self, s: &mut S) { + s.emit_float(*self) + } +} + +#[cfg(stage0)] impl Decodable for float { fn decode(d: &D) -> float { d.read_float() } } +#[cfg(not(stage0))] +impl Decodable for float { + fn decode(d: &mut D) -> float { + d.read_float() + } +} + +#[cfg(stage0)] +impl Encodable for f32 { + fn encode(&self, s: &S) { + s.emit_f32(*self) + } +} + +#[cfg(not(stage0))] impl Encodable for f32 { - fn encode(&self, s: &S) { s.emit_f32(*self) } + fn encode(&self, s: &mut S) { + s.emit_f32(*self) + } } +#[cfg(stage0)] impl Decodable for f32 { fn decode(d: &D) -> f32 { - d.read_f32() } + d.read_f32() + } } +#[cfg(not(stage0))] +impl Decodable for f32 { + fn decode(d: &mut D) -> f32 { + d.read_f32() + } +} + +#[cfg(stage0)] +impl Encodable for f64 { + fn encode(&self, s: &S) { + s.emit_f64(*self) + } +} + +#[cfg(not(stage0))] impl Encodable for f64 { - fn encode(&self, s: &S) { s.emit_f64(*self) } + fn encode(&self, s: &mut S) { + s.emit_f64(*self) + } } +#[cfg(stage0)] impl Decodable for f64 { fn decode(d: &D) -> f64 { d.read_f64() } } +#[cfg(not(stage0))] +impl Decodable for f64 { + fn decode(d: &mut D) -> f64 { + d.read_f64() + } +} + +#[cfg(stage0)] +impl Encodable for bool { + fn encode(&self, s: &S) { + s.emit_bool(*self) + } +} + +#[cfg(not(stage0))] impl Encodable for bool { - fn encode(&self, s: &S) { s.emit_bool(*self) } + fn encode(&self, s: &mut S) { + s.emit_bool(*self) + } } +#[cfg(stage0)] impl Decodable for bool { fn decode(d: &D) -> bool { d.read_bool() } } +#[cfg(not(stage0))] +impl Decodable for bool { + fn decode(d: &mut D) -> bool { + d.read_bool() + } +} + +#[cfg(stage0)] impl Encodable for () { - fn encode(&self, s: &S) { s.emit_nil() } + fn encode(&self, s: &S) { + s.emit_nil() + } } +#[cfg(not(stage0))] +impl Encodable for () { + fn encode(&self, s: &mut S) { + s.emit_nil() + } +} + +#[cfg(stage0)] impl Decodable for () { fn decode(d: &D) -> () { d.read_nil() } } +#[cfg(not(stage0))] +impl Decodable for () { + fn decode(d: &mut D) -> () { + d.read_nil() + } +} + +#[cfg(stage0)] impl<'self, S:Encoder,T:Encodable> Encodable for &'self T { fn encode(&self, s: &S) { (**self).encode(s) } } +#[cfg(not(stage0))] +impl<'self, S:Encoder,T:Encodable> Encodable for &'self T { + fn encode(&self, s: &mut S) { + (**self).encode(s) + } +} + +#[cfg(stage0)] impl> Encodable for ~T { fn encode(&self, s: &S) { (**self).encode(s) } } +#[cfg(not(stage0))] +impl> Encodable for ~T { + fn encode(&self, s: &mut S) { + (**self).encode(s) + } +} + +#[cfg(stage0)] impl> Decodable for ~T { fn decode(d: &D) -> ~T { ~Decodable::decode(d) } } +#[cfg(not(stage0))] +impl> Decodable for ~T { + fn decode(d: &mut D) -> ~T { + ~Decodable::decode(d) + } +} + +#[cfg(stage0)] impl> Encodable for @T { fn encode(&self, s: &S) { (**self).encode(s) } } +#[cfg(not(stage0))] +impl> Encodable for @T { + fn encode(&self, s: &mut S) { + (**self).encode(s) + } +} + +#[cfg(stage0)] impl> Decodable for @T { fn decode(d: &D) -> @T { @Decodable::decode(d) } } +#[cfg(not(stage0))] +impl> Decodable for @T { + fn decode(d: &mut D) -> @T { + @Decodable::decode(d) + } +} + +#[cfg(stage0)] impl<'self, S:Encoder,T:Encodable> Encodable for &'self [T] { fn encode(&self, s: &S) { do s.emit_seq(self.len()) { @@ -354,6 +909,18 @@ impl<'self, S:Encoder,T:Encodable> Encodable for &'self [T] { } } +#[cfg(not(stage0))] +impl<'self, S:Encoder,T:Encodable> Encodable for &'self [T] { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { + for self.eachi |i, e| { + s.emit_seq_elt(i, |s| e.encode(s)) + } + } + } +} + +#[cfg(stage0)] impl> Encodable for ~[T] { fn encode(&self, s: &S) { do s.emit_seq(self.len()) { @@ -364,6 +931,18 @@ impl> Encodable for ~[T] { } } +#[cfg(not(stage0))] +impl> Encodable for ~[T] { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { + for self.eachi |i, e| { + s.emit_seq_elt(i, |s| e.encode(s)) + } + } + } +} + +#[cfg(stage0)] impl> Decodable for ~[T] { fn decode(d: &D) -> ~[T] { do d.read_seq |len| { @@ -374,6 +953,18 @@ impl> Decodable for ~[T] { } } +#[cfg(not(stage0))] +impl> Decodable for ~[T] { + fn decode(d: &mut D) -> ~[T] { + do d.read_seq |d, len| { + do vec::from_fn(len) |i| { + d.read_seq_elt(i, |d| Decodable::decode(d)) + } + } + } +} + +#[cfg(stage0)] impl> Encodable for @[T] { fn encode(&self, s: &S) { do s.emit_seq(self.len()) { @@ -384,6 +975,18 @@ impl> Encodable for @[T] { } } +#[cfg(not(stage0))] +impl> Encodable for @[T] { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { + for self.eachi |i, e| { + s.emit_seq_elt(i, |s| e.encode(s)) + } + } + } +} + +#[cfg(stage0)] impl> Decodable for @[T] { fn decode(d: &D) -> @[T] { do d.read_seq |len| { @@ -394,6 +997,18 @@ impl> Decodable for @[T] { } } +#[cfg(not(stage0))] +impl> Decodable for @[T] { + fn decode(d: &mut D) -> @[T] { + do d.read_seq |d, len| { + do at_vec::from_fn(len) |i| { + d.read_seq_elt(i, |d| Decodable::decode(d)) + } + } + } +} + +#[cfg(stage0)] impl> Encodable for Option { fn encode(&self, s: &S) { do s.emit_option { @@ -405,6 +1020,19 @@ impl> Encodable for Option { } } +#[cfg(not(stage0))] +impl> Encodable for Option { + fn encode(&self, s: &mut S) { + do s.emit_option |s| { + match *self { + None => s.emit_option_none(), + Some(ref v) => s.emit_option_some(|s| v.encode(s)), + } + } + } +} + +#[cfg(stage0)] impl> Decodable for Option { fn decode(d: &D) -> Option { do d.read_option |b| { @@ -417,6 +1045,20 @@ impl> Decodable for Option { } } +#[cfg(not(stage0))] +impl> Decodable for Option { + fn decode(d: &mut D) -> Option { + do d.read_option |d, b| { + if b { + Some(Decodable::decode(d)) + } else { + None + } + } + } +} + +#[cfg(stage0)] impl,T1:Encodable> Encodable for (T0, T1) { fn encode(&self, s: &S) { match *self { @@ -430,6 +1072,21 @@ impl,T1:Encodable> Encodable for (T0, T1) { } } +#[cfg(not(stage0))] +impl,T1:Encodable> Encodable for (T0, T1) { + fn encode(&self, s: &mut S) { + match *self { + (ref t0, ref t1) => { + do s.emit_seq(2) |s| { + s.emit_seq_elt(0, |s| t0.encode(s)); + s.emit_seq_elt(1, |s| t1.encode(s)); + } + } + } + } +} + +#[cfg(stage0)] impl,T1:Decodable> Decodable for (T0, T1) { fn decode(d: &D) -> (T0, T1) { do d.read_seq |len| { @@ -442,6 +1099,20 @@ impl,T1:Decodable> Decodable for (T0, T1) { } } +#[cfg(not(stage0))] +impl,T1:Decodable> Decodable for (T0, T1) { + fn decode(d: &mut D) -> (T0, T1) { + do d.read_seq |d, len| { + assert!(len == 2); + ( + d.read_seq_elt(0, |d| Decodable::decode(d)), + d.read_seq_elt(1, |d| Decodable::decode(d)) + ) + } + } +} + +#[cfg(stage0)] impl< S: Encoder, T0: Encodable, @@ -461,6 +1132,27 @@ impl< } } +#[cfg(not(stage0))] +impl< + S: Encoder, + T0: Encodable, + T1: Encodable, + T2: Encodable +> Encodable for (T0, T1, T2) { + fn encode(&self, s: &mut S) { + match *self { + (ref t0, ref t1, ref t2) => { + do s.emit_seq(3) |s| { + s.emit_seq_elt(0, |s| t0.encode(s)); + s.emit_seq_elt(1, |s| t1.encode(s)); + s.emit_seq_elt(2, |s| t2.encode(s)); + } + } + } + } +} + +#[cfg(stage0)] impl< D: Decoder, T0: Decodable, @@ -479,6 +1171,26 @@ impl< } } +#[cfg(not(stage0))] +impl< + D: Decoder, + T0: Decodable, + T1: Decodable, + T2: Decodable +> Decodable for (T0, T1, T2) { + fn decode(d: &mut D) -> (T0, T1, T2) { + do d.read_seq |d, len| { + assert!(len == 3); + ( + d.read_seq_elt(0, |d| Decodable::decode(d)), + d.read_seq_elt(1, |d| Decodable::decode(d)), + d.read_seq_elt(2, |d| Decodable::decode(d)) + ) + } + } +} + +#[cfg(stage0)] impl< S: Encoder, T0: Encodable, @@ -500,6 +1212,29 @@ impl< } } +#[cfg(not(stage0))] +impl< + S: Encoder, + T0: Encodable, + T1: Encodable, + T2: Encodable, + T3: Encodable +> Encodable for (T0, T1, T2, T3) { + fn encode(&self, s: &mut S) { + match *self { + (ref t0, ref t1, ref t2, ref t3) => { + do s.emit_seq(4) |s| { + s.emit_seq_elt(0, |s| t0.encode(s)); + s.emit_seq_elt(1, |s| t1.encode(s)); + s.emit_seq_elt(2, |s| t2.encode(s)); + s.emit_seq_elt(3, |s| t3.encode(s)); + } + } + } + } +} + +#[cfg(stage0)] impl< D: Decoder, T0: Decodable, @@ -520,6 +1255,28 @@ impl< } } +#[cfg(not(stage0))] +impl< + D: Decoder, + T0: Decodable, + T1: Decodable, + T2: Decodable, + T3: Decodable +> Decodable for (T0, T1, T2, T3) { + fn decode(d: &mut D) -> (T0, T1, T2, T3) { + do d.read_seq |d, len| { + assert!(len == 4); + ( + d.read_seq_elt(0, |d| Decodable::decode(d)), + d.read_seq_elt(1, |d| Decodable::decode(d)), + d.read_seq_elt(2, |d| Decodable::decode(d)), + d.read_seq_elt(3, |d| Decodable::decode(d)) + ) + } + } +} + +#[cfg(stage0)] impl< S: Encoder, T0: Encodable, @@ -543,6 +1300,31 @@ impl< } } +#[cfg(not(stage0))] +impl< + S: Encoder, + T0: Encodable, + T1: Encodable, + T2: Encodable, + T3: Encodable, + T4: Encodable +> Encodable for (T0, T1, T2, T3, T4) { + fn encode(&self, s: &mut S) { + match *self { + (ref t0, ref t1, ref t2, ref t3, ref t4) => { + do s.emit_seq(5) |s| { + s.emit_seq_elt(0, |s| t0.encode(s)); + s.emit_seq_elt(1, |s| t1.encode(s)); + s.emit_seq_elt(2, |s| t2.encode(s)); + s.emit_seq_elt(3, |s| t3.encode(s)); + s.emit_seq_elt(4, |s| t4.encode(s)); + } + } + } + } +} + +#[cfg(stage0)] impl< D: Decoder, T0: Decodable, @@ -551,8 +1333,7 @@ impl< T3: Decodable, T4: Decodable > Decodable for (T0, T1, T2, T3, T4) { - fn decode(d: &D) - -> (T0, T1, T2, T3, T4) { + fn decode(d: &D) -> (T0, T1, T2, T3, T4) { do d.read_seq |len| { assert!(len == 5); ( @@ -566,6 +1347,30 @@ impl< } } +#[cfg(not(stage0))] +impl< + D: Decoder, + T0: Decodable, + T1: Decodable, + T2: Decodable, + T3: Decodable, + T4: Decodable +> Decodable for (T0, T1, T2, T3, T4) { + fn decode(d: &mut D) -> (T0, T1, T2, T3, T4) { + do d.read_seq |d, len| { + assert!(len == 5); + ( + d.read_seq_elt(0, |d| Decodable::decode(d)), + d.read_seq_elt(1, |d| Decodable::decode(d)), + d.read_seq_elt(2, |d| Decodable::decode(d)), + d.read_seq_elt(3, |d| Decodable::decode(d)), + d.read_seq_elt(4, |d| Decodable::decode(d)) + ) + } + } +} + +#[cfg(stage0)] impl< S: Encoder, T: Encodable + Copy @@ -581,6 +1386,23 @@ impl< } } +#[cfg(not(stage0))] +impl< + S: Encoder, + T: Encodable + Copy +> Encodable for @mut DList { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.size) |s| { + let mut i = 0; + for self.each |e| { + s.emit_seq_elt(i, |s| e.encode(s)); + i += 1; + } + } + } +} + +#[cfg(stage0)] impl> Decodable for @mut DList { fn decode(d: &D) -> @mut DList { let list = DList(); @@ -593,6 +1415,20 @@ impl> Decodable for @mut DList { } } +#[cfg(not(stage0))] +impl> Decodable for @mut DList { + fn decode(d: &mut D) -> @mut DList { + let list = DList(); + do d.read_seq |d, len| { + for uint::range(0, len) |i| { + list.push(d.read_seq_elt(i, |d| Decodable::decode(d))); + } + } + list + } +} + +#[cfg(stage0)] impl< S: Encoder, T: Encodable @@ -606,6 +1442,21 @@ impl< } } +#[cfg(not(stage0))] +impl< + S: Encoder, + T: Encodable +> Encodable for Deque { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { + for self.eachi |i, e| { + s.emit_seq_elt(i, |s| e.encode(s)); + } + } + } +} + +#[cfg(stage0)] impl> Decodable for Deque { fn decode(d: &D) -> Deque { let mut deque = Deque::new(); @@ -618,6 +1469,20 @@ impl> Decodable for Deque { } } +#[cfg(not(stage0))] +impl> Decodable for Deque { + fn decode(d: &mut D) -> Deque { + let mut deque = Deque::new(); + do d.read_seq |d, len| { + for uint::range(0, len) |i| { + deque.add_back(d.read_seq_elt(i, |d| Decodable::decode(d))); + } + } + deque + } +} + +#[cfg(stage0)] impl< E: Encoder, K: Encodable + Hash + IterBytes + Eq, @@ -635,6 +1500,25 @@ impl< } } +#[cfg(not(stage0))] +impl< + E: Encoder, + K: Encodable + Hash + IterBytes + Eq, + V: Encodable +> Encodable for HashMap { + fn encode(&self, e: &mut E) { + do e.emit_map(self.len()) |e| { + let mut i = 0; + for self.each |key, val| { + e.emit_map_elt_key(i, |e| key.encode(e)); + e.emit_map_elt_val(i, |e| val.encode(e)); + i += 1; + } + } + } +} + +#[cfg(stage0)] impl< D: Decoder, K: Decodable + Hash + IterBytes + Eq, @@ -653,6 +1537,26 @@ impl< } } +#[cfg(not(stage0))] +impl< + D: Decoder, + K: Decodable + Hash + IterBytes + Eq, + V: Decodable +> Decodable for HashMap { + fn decode(d: &mut D) -> HashMap { + do d.read_map |d, len| { + let mut map = HashMap::with_capacity(len); + for uint::range(0, len) |i| { + let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); + let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); + map.insert(key, val); + } + map + } + } +} + +#[cfg(stage0)] impl< S: Encoder, T: Encodable + Hash + IterBytes + Eq @@ -668,6 +1572,23 @@ impl< } } +#[cfg(not(stage0))] +impl< + S: Encoder, + T: Encodable + Hash + IterBytes + Eq +> Encodable for HashSet { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { + let mut i = 0; + for self.each |e| { + s.emit_seq_elt(i, |s| e.encode(s)); + i += 1; + } + } + } +} + +#[cfg(stage0)] impl< D: Decoder, T: Decodable + Hash + IterBytes + Eq @@ -683,6 +1604,23 @@ impl< } } +#[cfg(not(stage0))] +impl< + D: Decoder, + T: Decodable + Hash + IterBytes + Eq +> Decodable for HashSet { + fn decode(d: &mut D) -> HashSet { + do d.read_seq |d, len| { + let mut set = HashSet::with_capacity(len); + for uint::range(0, len) |i| { + set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); + } + set + } + } +} + +#[cfg(stage0)] impl< E: Encoder, V: Encodable @@ -699,6 +1637,24 @@ impl< } } +#[cfg(not(stage0))] +impl< + E: Encoder, + V: Encodable +> Encodable for TrieMap { + fn encode(&self, e: &mut E) { + do e.emit_map(self.len()) |e| { + let mut i = 0; + for self.each |key, val| { + e.emit_map_elt_key(i, |e| key.encode(e)); + e.emit_map_elt_val(i, |e| val.encode(e)); + i += 1; + } + } + } +} + +#[cfg(stage0)] impl< D: Decoder, V: Decodable @@ -716,6 +1672,25 @@ impl< } } +#[cfg(not(stage0))] +impl< + D: Decoder, + V: Decodable +> Decodable for TrieMap { + fn decode(d: &mut D) -> TrieMap { + do d.read_map |d, len| { + let mut map = TrieMap::new(); + for uint::range(0, len) |i| { + let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); + let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); + map.insert(key, val); + } + map + } + } +} + +#[cfg(stage0)] impl Encodable for TrieSet { fn encode(&self, s: &S) { do s.emit_seq(self.len()) { @@ -728,6 +1703,20 @@ impl Encodable for TrieSet { } } +#[cfg(not(stage0))] +impl Encodable for TrieSet { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { + let mut i = 0; + for self.each |e| { + s.emit_seq_elt(i, |s| e.encode(s)); + i += 1; + } + } + } +} + +#[cfg(stage0)] impl Decodable for TrieSet { fn decode(d: &D) -> TrieSet { do d.read_seq |len| { @@ -740,40 +1729,49 @@ impl Decodable for TrieSet { } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] +impl Decodable for TrieSet { + fn decode(d: &mut D) -> TrieSet { + do d.read_seq |d, len| { + let mut set = TrieSet::new(); + for uint::range(0, len) |i| { + set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); + } + set + } + } +} + +#[cfg(not(stage0))] impl< E: Encoder, K: Encodable + Eq + TotalOrd, V: Encodable + Eq > Encodable for TreeMap { - fn encode(&self, e: &E) { - do e.emit_map(self.len()) { + fn encode(&self, e: &mut E) { + do e.emit_map(self.len()) |e| { let mut i = 0; for self.each |key, val| { - e.emit_map_elt_key(i, || key.encode(e)); - e.emit_map_elt_val(i, || val.encode(e)); + e.emit_map_elt_key(i, |e| key.encode(e)); + e.emit_map_elt_val(i, |e| val.encode(e)); i += 1; } } } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] impl< D: Decoder, K: Decodable + Eq + TotalOrd, V: Decodable + Eq > Decodable for TreeMap { - fn decode(d: &D) -> TreeMap { - do d.read_map |len| { + fn decode(d: &mut D) -> TreeMap { + do d.read_map |d, len| { let mut map = TreeMap::new(); for uint::range(0, len) |i| { - let key = d.read_map_elt_key(i, || Decodable::decode(d)); - let val = d.read_map_elt_val(i, || Decodable::decode(d)); + let key = d.read_map_elt_key(i, |d| Decodable::decode(d)); + let val = d.read_map_elt_val(i, |d| Decodable::decode(d)); map.insert(key, val); } map @@ -781,36 +1779,32 @@ impl< } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] impl< S: Encoder, T: Encodable + Eq + TotalOrd > Encodable for TreeSet { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { + fn encode(&self, s: &mut S) { + do s.emit_seq(self.len()) |s| { let mut i = 0; for self.each |e| { - s.emit_seq_elt(i, || e.encode(s)); + s.emit_seq_elt(i, |s| e.encode(s)); i += 1; } } } } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] +#[cfg(not(stage0))] impl< D: Decoder, T: Decodable + Eq + TotalOrd > Decodable for TreeSet { - fn decode(d: &D) -> TreeSet { - do d.read_seq |len| { + fn decode(d: &mut D) -> TreeSet { + do d.read_seq |d, len| { let mut set = TreeSet::new(); for uint::range(0, len) |i| { - set.insert(d.read_seq_elt(i, || Decodable::decode(d))); + set.insert(d.read_seq_elt(i, |d| Decodable::decode(d))); } set } @@ -822,10 +1816,17 @@ impl< // // In some cases, these should eventually be coded as traits. +#[cfg(stage0)] pub trait EncoderHelpers { fn emit_from_vec(&self, v: &[T], f: &fn(v: &T)); } +#[cfg(not(stage0))] +pub trait EncoderHelpers { + fn emit_from_vec(&mut self, v: &[T], f: &fn(&mut Self, v: &T)); +} + +#[cfg(stage0)] impl EncoderHelpers for S { fn emit_from_vec(&self, v: &[T], f: &fn(v: &T)) { do self.emit_seq(v.len()) { @@ -838,10 +1839,30 @@ impl EncoderHelpers for S { } } +#[cfg(not(stage0))] +impl EncoderHelpers for S { + fn emit_from_vec(&mut self, v: &[T], f: &fn(&mut S, &T)) { + do self.emit_seq(v.len()) |this| { + for v.eachi |i, e| { + do this.emit_seq_elt(i) |this| { + f(this, e) + } + } + } + } +} + +#[cfg(stage0)] pub trait DecoderHelpers { fn read_to_vec(&self, f: &fn() -> T) -> ~[T]; } +#[cfg(not(stage0))] +pub trait DecoderHelpers { + fn read_to_vec(&mut self, f: &fn(&mut Self) -> T) -> ~[T]; +} + +#[cfg(stage0)] impl DecoderHelpers for D { fn read_to_vec(&self, f: &fn() -> T) -> ~[T] { do self.read_seq |len| { @@ -851,3 +1872,15 @@ impl DecoderHelpers for D { } } } + +#[cfg(not(stage0))] +impl DecoderHelpers for D { + fn read_to_vec(&mut self, f: &fn(&mut D) -> T) -> ~[T] { + do self.read_seq |this, len| { + do vec::from_fn(len) |i| { + this.read_seq_elt(i, |this| f(this)) + } + } + } +} + diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs index bb4a9e97ea1f4..2cdf36c71c79f 100644 --- a/src/libstd/workcache.rs +++ b/src/libstd/workcache.rs @@ -140,6 +140,7 @@ impl WorkMap { fn new() -> WorkMap { WorkMap(HashMap::new()) } } +#[cfg(stage0)] impl Encodable for WorkMap { fn encode(&self, s: &S) { let mut d = ~[]; @@ -151,6 +152,19 @@ impl Encodable for WorkMap { } } +#[cfg(not(stage0))] +impl Encodable for WorkMap { + fn encode(&self, s: &mut S) { + let mut d = ~[]; + for self.each |k, v| { + d.push((copy *k, copy *v)) + } + sort::tim_sort(d); + d.encode(s) + } +} + +#[cfg(stage0)] impl Decodable for WorkMap { fn decode(d: &D) -> WorkMap { let v : ~[(WorkKey,~str)] = Decodable::decode(d); @@ -162,6 +176,18 @@ impl Decodable for WorkMap { } } +#[cfg(not(stage0))] +impl Decodable for WorkMap { + fn decode(d: &mut D) -> WorkMap { + let v : ~[(WorkKey,~str)] = Decodable::decode(d); + let mut w = WorkMap::new(); + for v.each |&(k, v)| { + w.insert(copy k, copy v); + } + w + } +} + struct Database { db_filename: Path, db_cache: HashMap<~str, ~str>, @@ -171,8 +197,8 @@ struct Database { pub impl Database { fn prepare(&mut self, fn_name: &str, - declared_inputs: &WorkMap) -> Option<(WorkMap, WorkMap, ~str)> - { + declared_inputs: &WorkMap) + -> Option<(WorkMap, WorkMap, ~str)> { let k = json_encode(&(fn_name, declared_inputs)); match self.db_cache.find(&k) { None => None, @@ -229,17 +255,38 @@ struct Work { res: Option>> } +#[cfg(stage0)] fn json_encode>(t: &T) -> ~str { do io::with_str_writer |wr| { t.encode(&json::Encoder(wr)); } } +#[cfg(not(stage0))] +fn json_encode>(t: &T) -> ~str { + do io::with_str_writer |wr| { + let mut encoder = json::Encoder(wr); + t.encode(&mut encoder); + } +} + +// FIXME(#5121) +#[cfg(stage0)] +fn json_decode>(s: &str) -> T { + do io::with_str_reader(s) |rdr| { + let j = result::unwrap(json::from_reader(rdr)); + let decoder = json::Decoder(j); + Decodable::decode(&decoder) + } +} + // FIXME(#5121) +#[cfg(not(stage0))] fn json_decode>(s: &str) -> T { do io::with_str_reader(s) |rdr| { let j = result::unwrap(json::from_reader(rdr)); - Decodable::decode(&json::Decoder(j)) + let mut decoder = json::Decoder(j); + Decodable::decode(&mut decoder) } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a295952439fba..77e7986616086 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -70,21 +70,53 @@ pub type Name = uint; // with a macro expansion pub type Mrk = uint; +#[cfg(stage0)] impl Encodable for ident { fn encode(&self, s: &S) { + unsafe { + let intr = + match task::local_data::local_data_get(interner_key!()) { + None => fail!(~"encode: TLS interner not set up"), + Some(intr) => intr + }; + + s.emit_str(*(*intr).get(*self)); + } + } +} + +#[cfg(not(stage0))] +impl Encodable for ident { + fn encode(&self, s: &mut S) { + unsafe { + let intr = + match task::local_data::local_data_get(interner_key!()) { + None => fail!(~"encode: TLS interner not set up"), + Some(intr) => intr + }; + + s.emit_str(*(*intr).get(*self)); + } + } +} + +#[cfg(stage0)] +impl Decodable for ident { + fn decode(d: &D) -> ident { let intr = match unsafe { task::local_data::local_data_get(interner_key!()) } { - None => fail!(~"encode: TLS interner not set up"), + None => fail!(~"decode: TLS interner not set up"), Some(intr) => intr }; - s.emit_str(*(*intr).get(*self)); + (*intr).intern(@d.read_str()) } } +#[cfg(not(stage0))] impl Decodable for ident { - fn decode(d: &D) -> ident { + fn decode(d: &mut D) -> ident { let intr = match unsafe { task::local_data::local_data_get(interner_key!()) } { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index 5f4967351e11b..bbb390e9dc948 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -125,17 +125,34 @@ impl cmp::Eq for span { fn ne(&self, other: &span) -> bool { !(*self).eq(other) } } +#[cfg(stage0)] impl Encodable for span { /* Note #1972 -- spans are encoded but not decoded */ fn encode(&self, _s: &S) { _s.emit_nil() } } +#[cfg(not(stage0))] +impl Encodable for span { + /* Note #1972 -- spans are encoded but not decoded */ + fn encode(&self, s: &mut S) { + s.emit_nil() + } +} + +#[cfg(stage0)] impl Decodable for span { fn decode(_d: &D) -> span { dummy_sp() } } +#[cfg(not(stage0))] +impl Decodable for span { + fn decode(_d: &mut D) -> span { + dummy_sp() + } +} + pub fn spanned(lo: BytePos, hi: BytePos, t: T) -> spanned { respan(mk_sp(lo, hi), t) } diff --git a/src/libsyntax/ext/auto_encode.rs b/src/libsyntax/ext/auto_encode.rs index 2ceb6f0c4bb75..bdf0a2a1dd07c 100644 --- a/src/libsyntax/ext/auto_encode.rs +++ b/src/libsyntax/ext/auto_encode.rs @@ -238,7 +238,8 @@ trait ExtCtxtMethods { fn stmt(&self, expr: @ast::expr) -> @ast::stmt; fn lit_str(&self, span: span, s: @~str) -> @ast::expr; fn lit_uint(&self, span: span, i: uint) -> @ast::expr; - fn lambda(&self, blk: ast::blk) -> @ast::expr; + fn lambda0(&self, blk: ast::blk) -> @ast::expr; + fn lambda1(&self, blk: ast::blk, ident: ast::ident) -> @ast::expr; fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk; fn expr_blk(&self, expr: @ast::expr) -> ast::blk; fn expr_path(&self, span: span, strs: ~[ast::ident]) -> @ast::expr; @@ -254,8 +255,15 @@ trait ExtCtxtMethods { ident: ast::ident, args: ~[@ast::expr]) -> @ast::expr; - fn lambda_expr(&self, expr: @ast::expr) -> @ast::expr; - fn lambda_stmts(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr; + fn lambda_expr_0(&self, expr: @ast::expr) -> @ast::expr; + fn lambda_expr_1(&self, expr: @ast::expr, ident: ast::ident) + -> @ast::expr; + fn lambda_stmts_0(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr; + fn lambda_stmts_1(&self, + span: span, + stmts: ~[@ast::stmt], + ident: ast::ident) + -> @ast::expr; } impl ExtCtxtMethods for @ext_ctxt { @@ -388,12 +396,18 @@ impl ExtCtxtMethods for @ext_ctxt { span: span})) } - fn lambda(&self, blk: ast::blk) -> @ast::expr { + fn lambda0(&self, blk: ast::blk) -> @ast::expr { let ext_cx = *self; let blk_e = self.expr(copy blk.span, ast::expr_block(copy blk)); quote_expr!( || $blk_e ) } + fn lambda1(&self, blk: ast::blk, ident: ast::ident) -> @ast::expr { + let ext_cx = *self; + let blk_e = self.expr(copy blk.span, ast::expr_block(copy blk)); + quote_expr!( |$ident| $blk_e ) + } + fn blk(&self, span: span, stmts: ~[@ast::stmt]) -> ast::blk { codemap::spanned { node: ast::blk_ { @@ -461,15 +475,29 @@ impl ExtCtxtMethods for @ext_ctxt { ident: ast::ident, args: ~[@ast::expr] ) -> @ast::expr { - self.expr(span, ast::expr_method_call(expr, ident, ~[], args, ast::NoSugar)) + self.expr(span, + ast::expr_method_call(expr, ident, ~[], args, ast::NoSugar)) + } + + fn lambda_expr_0(&self, expr: @ast::expr) -> @ast::expr { + self.lambda0(self.expr_blk(expr)) + } + + fn lambda_expr_1(&self, expr: @ast::expr, ident: ast::ident) + -> @ast::expr { + self.lambda1(self.expr_blk(expr), ident) } - fn lambda_expr(&self, expr: @ast::expr) -> @ast::expr { - self.lambda(self.expr_blk(expr)) + fn lambda_stmts_0(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr { + self.lambda0(self.blk(span, stmts)) } - fn lambda_stmts(&self, span: span, stmts: ~[@ast::stmt]) -> @ast::expr { - self.lambda(self.blk(span, stmts)) + fn lambda_stmts_1(&self, + span: span, + stmts: ~[@ast::stmt], + ident: ast::ident) + -> @ast::expr { + self.lambda1(self.blk(span, stmts), ident) } } @@ -644,7 +672,7 @@ fn mk_ser_method( None, ast::mt { ty: cx.ty_path(span, ~[cx.ident_of(~"__S")], ~[]), - mutbl: ast::m_imm + mutbl: ast::m_mutbl } ), span: span, @@ -706,7 +734,7 @@ fn mk_deser_method( None, ast::mt { ty: cx.ty_path(span, ~[cx.ident_of(~"__D")], ~[]), - mutbl: ast::m_imm + mutbl: ast::m_mutbl } ), span: span, @@ -758,8 +786,8 @@ fn mk_struct_ser_impl( generics: &ast::Generics ) -> @ast::item { let fields = do mk_struct_fields(fields).mapi |idx, field| { - // ast for `|| self.$(name).encode(__s)` - let expr_lambda = cx.lambda_expr( + // ast for `|__s| self.$(name).encode(__s)` + let expr_lambda = cx.lambda_expr_1( cx.expr_method_call( span, cx.expr_field( @@ -769,7 +797,8 @@ fn mk_struct_ser_impl( ), cx.ident_of(~"encode"), ~[cx.expr_var(span, ~"__s")] - ) + ), + cx.ident_of(~"__s") ); // ast for `__s.emit_struct_field($(name), $(idx), $(expr_lambda))` @@ -787,7 +816,7 @@ fn mk_struct_ser_impl( ) }; - // ast for `__s.emit_struct($(name), || $(fields))` + // ast for `__s.emit_struct($(name), |__s| $(fields))` let ser_body = cx.expr_method_call( span, cx.expr_var(span, ~"__s"), @@ -795,7 +824,7 @@ fn mk_struct_ser_impl( ~[ cx.lit_str(span, @cx.str_of(ident)), cx.lit_uint(span, vec::len(fields)), - cx.lambda_stmts(span, fields), + cx.lambda_stmts_1(span, fields, cx.ident_of(~"__s")), ] ); @@ -810,8 +839,8 @@ fn mk_struct_deser_impl( generics: &ast::Generics ) -> @ast::item { let fields = do mk_struct_fields(fields).mapi |idx, field| { - // ast for `|| std::serialize::decode(__d)` - let expr_lambda = cx.lambda( + // ast for `|__d| std::serialize::decode(__d)` + let expr_lambda = cx.lambda1( cx.expr_blk( cx.expr_call( span, @@ -823,7 +852,8 @@ fn mk_struct_deser_impl( ]), ~[cx.expr_var(span, ~"__d")] ) - ) + ), + cx.ident_of(~"__d") ); // ast for `__d.read_struct_field($(name), $(idx), $(expr_lambda))` @@ -848,7 +878,7 @@ fn mk_struct_deser_impl( } }; - // ast for `read_struct($(name), || $(fields))` + // ast for `read_struct($(name), |__d| $(fields))` let body = cx.expr_method_call( span, cx.expr_var(span, ~"__d"), @@ -856,7 +886,7 @@ fn mk_struct_deser_impl( ~[ cx.lit_str(span, @cx.str_of(ident)), cx.lit_uint(span, vec::len(fields)), - cx.lambda_expr( + cx.lambda_expr_1( cx.expr( span, ast::expr_struct( @@ -864,7 +894,8 @@ fn mk_struct_deser_impl( fields, None ) - ) + ), + cx.ident_of(~"__d") ), ] ); @@ -974,14 +1005,15 @@ fn ser_variant( cx.ident_of(~"emit_enum_variant_arg") ); - // ast for `|| $(v).encode(__s)` - let expr_encode = cx.lambda_expr( - cx.expr_method_call( + // ast for `|__s| $(v).encode(__s)` + let expr_encode = cx.lambda_expr_1( + cx.expr_method_call( span, cx.expr_path(span, ~[names[a_idx]]), cx.ident_of(~"encode"), ~[cx.expr_var(span, ~"__s")] - ) + ), + cx.ident_of(~"__s") ); // ast for `$(expr_emit)($(a_idx), $(expr_encode))` @@ -1003,7 +1035,7 @@ fn ser_variant( cx.lit_str(span, @cx.str_of(v_name)), cx.lit_uint(span, v_idx), cx.lit_uint(span, stmts.len()), - cx.lambda_stmts(span, stmts), + cx.lambda_stmts_1(span, stmts, cx.ident_of(~"__s")), ] ); @@ -1050,7 +1082,7 @@ fn mk_enum_ser_body( cx.ident_of(~"emit_enum"), ~[ cx.lit_str(span, @cx.str_of(name)), - cx.lambda_expr(match_expr), + cx.lambda_expr_1(match_expr, cx.ident_of(~"__s")), ] ) } @@ -1062,8 +1094,8 @@ fn mk_enum_deser_variant_nary( args: ~[ast::variant_arg] ) -> @ast::expr { let args = do args.mapi |idx, _arg| { - // ast for `|| std::serialize::decode(__d)` - let expr_lambda = cx.lambda_expr( + // ast for `|__s| std::serialize::decode(__d)` + let expr_lambda = cx.lambda_expr_1( cx.expr_call( span, cx.expr_path_global(span, ~[ @@ -1073,7 +1105,8 @@ fn mk_enum_deser_variant_nary( cx.ident_of(~"decode"), ]), ~[cx.expr_var(span, ~"__d")] - ) + ), + cx.ident_of(~"__d") ); // ast for `__d.read_enum_variant_arg($(a_idx), $(expr_lambda))` @@ -1163,24 +1196,44 @@ fn mk_enum_deser_body( span, ast::expr_fn_block( ast::fn_decl { - inputs: ~[ast::arg { - is_mutbl: false, - ty: @ast::Ty { + inputs: ~[ + ast::arg { + is_mutbl: false, + ty: @ast::Ty { + id: ext_cx.next_id(), + node: ast::ty_infer, + span: span + }, + pat: @ast::pat { + id: ext_cx.next_id(), + node: ast::pat_ident( + ast::bind_by_copy, + ast_util::ident_to_path(span, + ext_cx.ident_of(~"__d")), + None), + span: span, + }, id: ext_cx.next_id(), - node: ast::ty_infer, - span: span }, - pat: @ast::pat { + ast::arg { + is_mutbl: false, + ty: @ast::Ty { + id: ext_cx.next_id(), + node: ast::ty_infer, + span: span + }, + pat: @ast::pat { + id: ext_cx.next_id(), + node: ast::pat_ident( + ast::bind_by_copy, + ast_util::ident_to_path(span, + ext_cx.ident_of(~"i")), + None), + span: span, + }, id: ext_cx.next_id(), - node: ast::pat_ident( - ast::bind_by_copy, - ast_util::ident_to_path(span, - ext_cx.ident_of(~"i")), - None), - span: span, - }, - id: ext_cx.next_id(), - }], + } + ], output: @ast::Ty { id: ext_cx.next_id(), node: ast::ty_infer, @@ -1198,13 +1251,14 @@ fn mk_enum_deser_body( ); // ast for `__d.read_enum_variant($expr_arm_names, $(expr_lambda))` - let expr_lambda = ext_cx.lambda_expr( + let expr_lambda = ext_cx.lambda_expr_1( ext_cx.expr_method_call( span, ext_cx.expr_var(span, ~"__d"), ext_cx.ident_of(~"read_enum_variant"), ~[expr_arm_names, expr_lambda] - ) + ), + ext_cx.ident_of(~"__d") ); // ast for `__d.read_enum($(e_name), $(expr_lambda))` @@ -1256,105 +1310,147 @@ mod test { } impl Encoder for TestEncoder { - fn emit_nil(&self) { self.add_to_log(CallToEmitNil) } + fn emit_nil(&mut self) { self.add_to_log(CallToEmitNil) } - fn emit_uint(&self, v: uint) {self.add_to_log(CallToEmitUint(v)); } - fn emit_u64(&self, _v: u64) { self.add_unknown_to_log(); } - fn emit_u32(&self, _v: u32) { self.add_unknown_to_log(); } - fn emit_u16(&self, _v: u16) { self.add_unknown_to_log(); } - fn emit_u8(&self, _v: u8) { self.add_unknown_to_log(); } + fn emit_uint(&mut self, v: uint) { + self.add_to_log(CallToEmitUint(v)); + } + fn emit_u64(&mut self, _v: u64) { self.add_unknown_to_log(); } + fn emit_u32(&mut self, _v: u32) { self.add_unknown_to_log(); } + fn emit_u16(&mut self, _v: u16) { self.add_unknown_to_log(); } + fn emit_u8(&mut self, _v: u8) { self.add_unknown_to_log(); } - fn emit_int(&self, _v: int) { self.add_unknown_to_log(); } - fn emit_i64(&self, _v: i64) { self.add_unknown_to_log(); } - fn emit_i32(&self, _v: i32) { self.add_unknown_to_log(); } - fn emit_i16(&self, _v: i16) { self.add_unknown_to_log(); } - fn emit_i8(&self, _v: i8) { self.add_unknown_to_log(); } + fn emit_int(&mut self, _v: int) { self.add_unknown_to_log(); } + fn emit_i64(&mut self, _v: i64) { self.add_unknown_to_log(); } + fn emit_i32(&mut self, _v: i32) { self.add_unknown_to_log(); } + fn emit_i16(&mut self, _v: i16) { self.add_unknown_to_log(); } + fn emit_i8(&mut self, _v: i8) { self.add_unknown_to_log(); } - fn emit_bool(&self, _v: bool) { self.add_unknown_to_log(); } + fn emit_bool(&mut self, _v: bool) { self.add_unknown_to_log(); } - fn emit_f64(&self, _v: f64) { self.add_unknown_to_log(); } - fn emit_f32(&self, _v: f32) { self.add_unknown_to_log(); } - fn emit_float(&self, _v: float) { self.add_unknown_to_log(); } + fn emit_f64(&mut self, _v: f64) { self.add_unknown_to_log(); } + fn emit_f32(&mut self, _v: f32) { self.add_unknown_to_log(); } + fn emit_float(&mut self, _v: float) { self.add_unknown_to_log(); } - fn emit_char(&self, _v: char) { self.add_unknown_to_log(); } - fn emit_str(&self, _v: &str) { self.add_unknown_to_log(); } + fn emit_char(&mut self, _v: char) { self.add_unknown_to_log(); } + fn emit_str(&mut self, _v: &str) { self.add_unknown_to_log(); } - fn emit_enum(&self, name: &str, f: &fn()) { - self.add_to_log(CallToEmitEnum(name.to_str())); f(); } + fn emit_enum(&mut self, name: &str, f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitEnum(name.to_str())); + f(self); + } - fn emit_enum_variant(&self, name: &str, id: uint, - cnt: uint, f: &fn()) { - self.add_to_log(CallToEmitEnumVariant (name.to_str(),id,cnt)); - f(); + fn emit_enum_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitEnumVariant(name.to_str(), id, cnt)); + f(self); } - fn emit_enum_variant_arg(&self, idx: uint, f: &fn()) { - self.add_to_log(CallToEmitEnumVariantArg (idx)); f(); + fn emit_enum_variant_arg(&mut self, + idx: uint, + f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitEnumVariantArg(idx)); + f(self); } - fn emit_enum_struct_variant(&self, name: &str, id: uint, cnt: uint, f: &fn()) { + fn emit_enum_struct_variant(&mut self, + name: &str, + id: uint, + cnt: uint, + f: &fn(&mut TestEncoder)) { self.emit_enum_variant(name, id, cnt, f) } - fn emit_enum_struct_variant_field(&self, _name: &str, idx: uint, f: &fn()) { + fn emit_enum_struct_variant_field(&mut self, + _name: &str, + idx: uint, + f: &fn(&mut TestEncoder)) { self.emit_enum_variant_arg(idx, f) } - fn emit_struct(&self, name: &str, len: uint, f: &fn()) { - self.add_to_log(CallToEmitStruct (name.to_str(),len)); f(); + fn emit_struct(&mut self, + name: &str, + len: uint, + f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitStruct (name.to_str(),len)); + f(self); } - fn emit_struct_field(&self, name: &str, idx: uint, f: &fn()) { - self.add_to_log(CallToEmitField (name.to_str(),idx)); f(); + fn emit_struct_field(&mut self, + name: &str, + idx: uint, + f: &fn(&mut TestEncoder)) { + self.add_to_log(CallToEmitField (name.to_str(),idx)); + f(self); } - fn emit_tuple(&self, _len: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_tuple(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_tuple_arg(&self, _idx: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_tuple_arg(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_tuple_struct(&self, _name: &str, _len: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_tuple_struct(&mut self, + _name: &str, + _len: uint, + f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_tuple_struct_arg(&self, _idx: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + + fn emit_tuple_struct_arg(&mut self, + _idx: uint, + f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_option(&self, f: &fn()) { + fn emit_option(&mut self, f: &fn(&mut TestEncoder)) { self.add_to_log(CallToEmitOption); - f(); + f(self); } - fn emit_option_none(&self) { + fn emit_option_none(&mut self) { self.add_to_log(CallToEmitOptionNone); } - fn emit_option_some(&self, f: &fn()) { + fn emit_option_some(&mut self, f: &fn(&mut TestEncoder)) { self.add_to_log(CallToEmitOptionSome); - f(); + f(self); } - fn emit_seq(&self, _len: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_seq(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_seq_elt(&self, _idx: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_seq_elt(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_map(&self, _len: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_map(&mut self, _len: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_map_elt_key(&self, _idx: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_map_elt_key(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } - fn emit_map_elt_val(&self, _idx: uint, f: &fn()) { - self.add_unknown_to_log(); f(); + fn emit_map_elt_val(&mut self, _idx: uint, f: &fn(&mut TestEncoder)) { + self.add_unknown_to_log(); + f(self); } } fn to_call_log>(val: E) -> ~[call] { - let mut te = TestEncoder {call_log: @mut ~[]}; - val.encode(&te); + let mut te = TestEncoder { + call_log: @mut ~[] + }; + val.encode(&mut te); copy *te.call_log } diff --git a/src/libsyntax/ext/deriving/decodable.rs b/src/libsyntax/ext/deriving/decodable.rs index 48f6d5baa8b9f..fe270abc2e4f2 100644 --- a/src/libsyntax/ext/deriving/decodable.rs +++ b/src/libsyntax/ext/deriving/decodable.rs @@ -96,7 +96,7 @@ fn create_decode_method( cx, span, build::mk_simple_ty_path(cx, span, cx.ident_of(~"__D")), - ast::m_imm + ast::m_mutbl ); let d_ident = cx.ident_of(~"__d"); let d_arg = build::mk_arg(cx, span, d_ident, d_arg_type); @@ -219,6 +219,11 @@ fn create_read_struct_field( // Call the substructure method. let decode_expr = call_substructure_decode_method(cx, span); + let d_arg = build::mk_arg(cx, + span, + cx.ident_of(~"__d"), + build::mk_ty_infer(cx, span)); + let call_expr = build::mk_method_call( cx, span, @@ -227,7 +232,11 @@ fn create_read_struct_field( ~[ build::mk_base_str(cx, span, cx.str_of(ident)), build::mk_uint(cx, span, idx), - build::mk_lambda_no_args(cx, span, decode_expr), + build::mk_lambda(cx, + span, + build::mk_fn_decl(~[d_arg], + build::mk_ty_infer(cx, span)), + decode_expr), ] ); @@ -282,6 +291,11 @@ fn expand_deriving_decodable_struct_method( i += 1; } + let d_arg = build::mk_arg(cx, + span, + cx.ident_of(~"__d"), + build::mk_ty_infer(cx, span)); + let read_struct_expr = build::mk_method_call( cx, span, @@ -294,9 +308,10 @@ fn expand_deriving_decodable_struct_method( ~[ build::mk_base_str(cx, span, cx.str_of(type_ident)), build::mk_uint(cx, span, fields.len()), - build::mk_lambda_no_args( + build::mk_lambda( cx, span, + build::mk_fn_decl(~[d_arg], build::mk_ty_infer(cx, span)), build::mk_struct_e( cx, span, @@ -334,6 +349,12 @@ fn create_read_variant_arg( // Call the substructure method. let expr = call_substructure_decode_method(cx, span); + let d_arg = build::mk_arg(cx, + span, + cx.ident_of(~"__d"), + build::mk_ty_infer(cx, span)); + let t_infer = build::mk_ty_infer(cx, span); + let call_expr = build::mk_method_call( cx, span, @@ -341,7 +362,10 @@ fn create_read_variant_arg( cx.ident_of(~"read_enum_variant_arg"), ~[ build::mk_uint(cx, span, j), - build::mk_lambda_no_args(cx, span, expr), + build::mk_lambda(cx, + span, + build::mk_fn_decl(~[d_arg], t_infer), + expr), ] ); @@ -399,6 +423,12 @@ fn create_read_enum_variant( span, build::mk_fn_decl( ~[ + build::mk_arg( + cx, + span, + cx.ident_of(~"__d"), + build::mk_ty_infer(cx, span) + ), build::mk_arg( cx, span, @@ -434,6 +464,11 @@ fn expand_deriving_decodable_enum_method( enum_definition ); + let d_arg = build::mk_arg(cx, + span, + cx.ident_of(~"__d"), + build::mk_ty_infer(cx, span)); + // Create the read_enum expression let read_enum_expr = build::mk_method_call( cx, @@ -442,7 +477,11 @@ fn expand_deriving_decodable_enum_method( cx.ident_of(~"read_enum"), ~[ build::mk_base_str(cx, span, cx.str_of(type_ident)), - build::mk_lambda_no_args(cx, span, read_enum_variant_expr), + build::mk_lambda(cx, + span, + build::mk_fn_decl(~[d_arg], + build::mk_ty_infer(cx, span)), + read_enum_variant_expr), ] ); diff --git a/src/libsyntax/ext/deriving/encodable.rs b/src/libsyntax/ext/deriving/encodable.rs index 640d0d0ff2d23..8f8139790ade9 100644 --- a/src/libsyntax/ext/deriving/encodable.rs +++ b/src/libsyntax/ext/deriving/encodable.rs @@ -94,10 +94,9 @@ fn create_encode_method( cx, span, build::mk_simple_ty_path(cx, span, cx.ident_of(~"__E")), - ast::m_imm + ast::m_mutbl ); - let e_ident = cx.ident_of(~"__e"); - let e_arg = build::mk_arg(cx, span, e_ident, e_arg_type); + let e_arg = build::mk_arg(cx, span, cx.ident_of(~"__e"), e_arg_type); // Create the type of the return value. let output_type = @ast::Ty { id: cx.next_id(), node: ty_nil, span: span }; @@ -226,10 +225,16 @@ fn expand_deriving_encodable_struct_method( self_field ); + let e_ident = cx.ident_of(~"__e"); + let e_arg = build::mk_arg(cx, + span, + e_ident, + build::mk_ty_infer(cx, span)); + let blk_expr = build::mk_lambda( cx, span, - build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)), encode_expr ); @@ -257,6 +262,11 @@ fn expand_deriving_encodable_struct_method( idx += 1; } + let e_arg = build::mk_arg(cx, + span, + cx.ident_of(~"__e"), + build::mk_ty_infer(cx, span)); + let emit_struct_stmt = build::mk_method_call( cx, span, @@ -272,7 +282,7 @@ fn expand_deriving_encodable_struct_method( build::mk_lambda_stmts( cx, span, - build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)), statements ), ] @@ -309,10 +319,16 @@ fn expand_deriving_encodable_enum_method( // Call the substructure method. let expr = call_substructure_encode_method(cx, span, field); + let e_ident = cx.ident_of(~"__e"); + let e_arg = build::mk_arg(cx, + span, + e_ident, + build::mk_ty_infer(cx, span)); + let blk_expr = build::mk_lambda( cx, span, - build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)), expr ); @@ -331,6 +347,10 @@ fn expand_deriving_encodable_enum_method( } // Create the pattern body. + let e_arg = build::mk_arg(cx, + span, + cx.ident_of(~"__e"), + build::mk_ty_infer(cx, span)); let call_expr = build::mk_method_call( cx, span, @@ -343,7 +363,7 @@ fn expand_deriving_encodable_enum_method( build::mk_lambda_stmts( cx, span, - build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)), stmts ) ] @@ -359,11 +379,17 @@ fn expand_deriving_encodable_enum_method( } }; + let e_ident = cx.ident_of(~"__e"); + let e_arg = build::mk_arg(cx, + span, + e_ident, + build::mk_ty_infer(cx, span)); + // Create the method body. let lambda_expr = build::mk_lambda( cx, span, - build::mk_fn_decl(~[], build::mk_ty_infer(cx, span)), + build::mk_fn_decl(~[e_arg], build::mk_ty_infer(cx, span)), expand_enum_or_struct_match(cx, span, arms) ); diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 4f1d41a4a7a17..0c024958a24d8 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -420,7 +420,8 @@ mod test { #[cfg(test)] fn to_json_str>(val: @E) -> ~str { do io::with_str_writer |writer| { - val.encode(~std::json::Encoder(writer)); + let mut encoder = std::json::Encoder(writer); + val.encode(&mut encoder); } } diff --git a/src/test/bench/shootout-binarytrees.rs b/src/test/bench/shootout-binarytrees.rs index 8d0675d0884e5..c420e0cbb2fd0 100644 --- a/src/test/bench/shootout-binarytrees.rs +++ b/src/test/bench/shootout-binarytrees.rs @@ -1,3 +1,7 @@ +// xfail-test + +// Broken due to arena API problems. + // 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. @@ -10,7 +14,6 @@ extern mod std; use std::arena; -use methods = std::arena::Arena; enum tree<'self> { nil, @@ -26,9 +29,7 @@ fn item_check(t: &tree) -> int { } } -fn bottom_up_tree<'r>(arena: &'r arena::Arena, - item: int, - depth: int) +fn bottom_up_tree<'r>(arena: &'r mut arena::Arena, item: int, depth: int) -> &'r tree<'r> { if depth > 0 { return arena.alloc( @@ -58,25 +59,25 @@ fn main() { max_depth = n; } - let stretch_arena = arena::Arena(); + let mut stretch_arena = arena::Arena(); let stretch_depth = max_depth + 1; - let stretch_tree = bottom_up_tree(&stretch_arena, 0, stretch_depth); + let stretch_tree = bottom_up_tree(&mut stretch_arena, 0, stretch_depth); io::println(fmt!("stretch tree of depth %d\t check: %d", stretch_depth, item_check(stretch_tree))); - let long_lived_arena = arena::Arena(); - let long_lived_tree = bottom_up_tree(&long_lived_arena, 0, max_depth); + let mut long_lived_arena = arena::Arena(); + let long_lived_tree = bottom_up_tree(&mut long_lived_arena, 0, max_depth); let mut depth = min_depth; while depth <= max_depth { let iterations = int::pow(2, (max_depth - depth + min_depth) as uint); let mut chk = 0; let mut i = 1; while i <= iterations { - let mut temp_tree = bottom_up_tree(&long_lived_arena, i, depth); + let mut temp_tree = bottom_up_tree(&mut long_lived_arena, i, depth); chk += item_check(temp_tree); - temp_tree = bottom_up_tree(&long_lived_arena, -i, depth); + temp_tree = bottom_up_tree(&mut long_lived_arena, -i, depth); chk += item_check(temp_tree); i += 1; } @@ -87,5 +88,5 @@ fn main() { } io::println(fmt!("long lived trees of depth %d\t check: %d", max_depth, - item_check(long_lived_tree))); + item_check(long_lived_tree))); } diff --git a/src/test/run-pass/auto-encode.rs b/src/test/run-pass/auto-encode.rs index bfc15acaa763c..cfac8e8cd061f 100644 --- a/src/test/run-pass/auto-encode.rs +++ b/src/test/run-pass/auto-encode.rs @@ -31,11 +31,12 @@ fn test_ebml >(a1: &A) { let bytes = do io::with_bytes_writer |wr| { - let ebml_w = &EBWriter::Encoder(wr); - a1.encode(ebml_w) + let mut ebml_w = EBWriter::Encoder(wr); + a1.encode(&mut ebml_w) }; let d = EBReader::Doc(@bytes); - let a2: A = Decodable::decode(&EBReader::Decoder(d)); + let mut decoder = EBReader::Decoder(d); + let a2: A = Decodable::decode(&mut decoder); assert!(*a1 == a2); } diff --git a/src/test/run-pass/issue-4036.rs b/src/test/run-pass/issue-4036.rs index f24875cbf8e0b..8b514b11625e4 100644 --- a/src/test/run-pass/issue-4036.rs +++ b/src/test/run-pass/issue-4036.rs @@ -17,5 +17,6 @@ use self::std::serialize; pub fn main() { let json = json::from_str("[1]").unwrap(); - let _x: ~[int] = serialize::Decodable::decode(&json::Decoder(json)); + let mut decoder = json::Decoder(json); + let _x: ~[int] = serialize::Decodable::decode(&mut decoder); } diff --git a/src/test/run-pass/placement-new-arena.rs b/src/test/run-pass/placement-new-arena.rs index 12c804219328e..166435cbc3d50 100644 --- a/src/test/run-pass/placement-new-arena.rs +++ b/src/test/run-pass/placement-new-arena.rs @@ -14,7 +14,8 @@ extern mod std; use std::arena; pub fn main() { - let p = &arena::Arena(); + let mut arena = arena::Arena(); + let p = &mut arena; let x = p.alloc(|| 4u); io::print(fmt!("%u", *x)); assert!(*x == 4u); diff --git a/src/test/run-pass/regions-mock-trans-impls.rs b/src/test/run-pass/regions-mock-trans-impls.rs index c1f7a713ca679..e916350574883 100644 --- a/src/test/run-pass/regions-mock-trans-impls.rs +++ b/src/test/run-pass/regions-mock-trans-impls.rs @@ -21,7 +21,7 @@ struct Bcx<'self> { } struct Fcx<'self> { - arena: &'self Arena, + arena: &'self mut Arena, ccx: &'self Ccx } @@ -29,23 +29,27 @@ struct Ccx { x: int } -fn h<'r>(bcx : &'r Bcx<'r>) -> &'r Bcx<'r> { - return bcx.fcx.arena.alloc(|| Bcx { fcx: bcx.fcx }); +fn h<'r>(bcx : &'r mut Bcx<'r>) -> &'r mut Bcx<'r> { + // XXX: Arena has a bad interface here; it should return mutable pointers. + // But this patch is too big to roll that in. + unsafe { + cast::transmute(bcx.fcx.arena.alloc(|| Bcx { fcx: bcx.fcx })) + } } -fn g(fcx : &Fcx) { - let bcx = Bcx { fcx: fcx }; - h(&bcx); +fn g(fcx: &mut Fcx) { + let mut bcx = Bcx { fcx: fcx }; + h(&mut bcx); } -fn f(ccx : &Ccx) { - let a = Arena(); - let fcx = &Fcx { arena: &a, ccx: ccx }; - return g(fcx); +fn f(ccx: &mut Ccx) { + let mut a = Arena(); + let mut fcx = Fcx { arena: &mut a, ccx: ccx }; + return g(&mut fcx); } pub fn main() { - let ccx = Ccx { x: 0 }; - f(&ccx); + let mut ccx = Ccx { x: 0 }; + f(&mut ccx); } From 9bded762601e47b16bd97ef4439536fb9d7af0cd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 2 May 2013 21:15:36 -0400 Subject: [PATCH 155/215] move @mut into scope_info --- src/librustc/middle/trans/base.rs | 67 ++++++++++++------------ src/librustc/middle/trans/common.rs | 37 +++++++------ src/librustc/middle/trans/controlflow.rs | 4 +- src/librustc/middle/trans/expr.rs | 1 - 4 files changed, 55 insertions(+), 54 deletions(-) diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 80cedf2372786..8a21d9116f5e6 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -34,7 +34,6 @@ use lib; use metadata::common::LinkMeta; use metadata::{csearch, cstore, encoder}; use middle::astencode; -use middle::borrowck::RootInfo; use middle::resolve; use middle::trans::_match; use middle::trans::adt; @@ -62,7 +61,6 @@ use middle::trans::type_of::*; use middle::ty; use util::common::indenter; use util::ppaux::{Repr, ty_to_str}; -use util::ppaux; use core::hash; use core::hashmap::{HashMap, HashSet}; @@ -887,11 +885,10 @@ pub fn need_invoke(bcx: block) -> bool { // Walk the scopes to look for cleanups let mut cur = bcx; loop { - let current = &mut *cur; - let kind = &mut *current.kind; - match *kind { - block_scope(ref mut inf) => { - for vec::each((*inf).cleanups) |cleanup| { + match cur.kind { + block_scope(inf) => { + let inf = &mut *inf; // FIXME(#5074) workaround old borrowck + for vec::each(inf.cleanups) |cleanup| { match *cleanup { clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) => { if cleanup_type == normal_exit_and_unwind { @@ -903,7 +900,7 @@ pub fn need_invoke(bcx: block) -> bool { } _ => () } - cur = match current.parent { + cur = match cur.parent { Some(next) => next, None => return false } @@ -925,11 +922,13 @@ pub fn in_lpad_scope_cx(bcx: block, f: &fn(si: &mut scope_info)) { let mut bcx = bcx; loop { { - // FIXME #4280: Borrow check bug workaround. - let kind: &mut block_kind = &mut *bcx.kind; - match *kind { - block_scope(ref mut inf) => { - if inf.cleanups.len() > 0u || bcx.parent.is_none() { + match bcx.kind { + block_scope(inf) => { + let len = { // FIXME(#5074) workaround old borrowck + let inf = &mut *inf; + inf.cleanups.len() + }; + if len > 0u || bcx.parent.is_none() { f(inf); return; } @@ -1194,7 +1193,7 @@ pub fn new_block(cx: fn_ctxt, parent: Option, kind: block_kind, } pub fn simple_block_scope() -> block_kind { - block_scope(scope_info { + block_scope(@mut scope_info { loop_break: None, loop_label: None, cleanups: ~[], @@ -1222,7 +1221,7 @@ pub fn loop_scope_block(bcx: block, loop_label: Option, n: ~str, opt_node_info: Option) -> block { - return new_block(bcx.fcx, Some(bcx), block_scope(scope_info { + return new_block(bcx.fcx, Some(bcx), block_scope(@mut scope_info { loop_break: Some(loop_break), loop_label: loop_label, cleanups: ~[], @@ -1300,28 +1299,28 @@ pub fn cleanup_and_leave(bcx: block, @fmt!("cleanup_and_leave(%s)", cur.to_str())); } - { - // FIXME #4280: Borrow check bug workaround. - let kind: &mut block_kind = &mut *cur.kind; - match *kind { - block_scope(ref mut inf) if !inf.cleanups.is_empty() => { - for vec::find((*inf).cleanup_paths, - |cp| cp.target == leave).each |cp| { - Br(bcx, cp.dest); - return; - } - let sub_cx = sub_block(bcx, ~"cleanup"); - Br(bcx, sub_cx.llbb); - inf.cleanup_paths.push(cleanup_path { - target: leave, - dest: sub_cx.llbb - }); + match cur.kind { + block_scope(inf) if !inf.empty_cleanups() => { + let (sub_cx, inf_cleanups) = { + let inf = &mut *inf; // FIXME(#5074) workaround stage0 + for vec::find((*inf).cleanup_paths, + |cp| cp.target == leave).each |cp| { + Br(bcx, cp.dest); + return; + } + let sub_cx = sub_block(bcx, ~"cleanup"); + Br(bcx, sub_cx.llbb); + inf.cleanup_paths.push(cleanup_path { + target: leave, + dest: sub_cx.llbb + }); + (sub_cx, copy inf.cleanups) + }; bcx = trans_block_cleanups_(sub_cx, - inf.cleanups, + inf_cleanups, is_lpad); - } - _ => () } + _ => () } match upto { diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index dba9ddd2b1d1a..705a89381dfa5 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -532,6 +532,7 @@ pub fn add_clean_free(cx: block, ptr: ValueRef, heap: heap) { // drop glue checks whether it is zero. pub fn revoke_clean(cx: block, val: ValueRef) { do in_scope_cx(cx) |scope_info| { + let scope_info = &mut *scope_info; // FIXME(#5074) workaround borrowck let cleanup_pos = vec::position( scope_info.cleanups, |cu| match *cu { @@ -550,9 +551,9 @@ pub fn revoke_clean(cx: block, val: ValueRef) { } pub fn block_cleanups(bcx: block) -> ~[cleanup] { - match *bcx.kind { + match bcx.kind { block_non_scope => ~[], - block_scope(ref mut inf) => /*bad*/copy inf.cleanups + block_scope(inf) => /*bad*/copy inf.cleanups } } @@ -561,7 +562,7 @@ pub enum block_kind { // cleaned up. May correspond to an actual block in the language, but also // to an implicit scope, for example, calls introduce an implicit scope in // which the arguments are evaluated and cleaned up. - block_scope(scope_info), + block_scope(@mut scope_info), // A non-scope block is a basic block created as a translation artifact // from translating code that expresses conditional logic rather than by @@ -584,6 +585,12 @@ pub struct scope_info { landing_pad: Option, } +pub impl scope_info { + fn empty_cleanups(&mut self) -> bool { + self.cleanups.is_empty() + } +} + pub trait get_node_info { fn info(&self) -> Option; } @@ -632,7 +639,7 @@ pub struct block_ { unreachable: bool, parent: Option, // The 'kind' of basic block this is. - kind: @mut block_kind, + kind: block_kind, // Is this block part of a landing pad? is_lpad: bool, // info about the AST node this block originated from, if any @@ -651,7 +658,7 @@ pub fn block_(llbb: BasicBlockRef, parent: Option, kind: block_kind, terminated: false, unreachable: false, parent: parent, - kind: @mut kind, + kind: kind, is_lpad: is_lpad, node_info: node_info, fcx: fcx @@ -699,21 +706,17 @@ pub fn val_str(tn: @TypeNames, v: ValueRef) -> @str { return ty_str(tn, val_ty(v)); } -pub fn in_scope_cx(cx: block, f: &fn(si: &mut scope_info)) { +pub fn in_scope_cx(cx: block, f: &fn(si: @mut scope_info)) { let mut cur = cx; loop { - { - // XXX: Borrow check bug workaround. - let kind: &mut block_kind = &mut *cur.kind; - match *kind { - block_scope(ref mut inf) => { - debug!("in_scope_cx: selected cur=%s (cx=%s)", - cur.to_str(), cx.to_str()); - f(inf); - return; - } - _ => () + match cur.kind { + block_scope(inf) => { + debug!("in_scope_cx: selected cur=%s (cx=%s)", + cur.to_str(), cx.to_str()); + f(inf); + return; } + _ => () } cur = block_parent(cur); } diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 113136fa58d13..60b6cf9e23f79 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -243,8 +243,8 @@ pub fn trans_break_cont(bcx: block, let mut unwind = bcx; let mut target; loop { - match *unwind.kind { - block_scope(scope_info { + match unwind.kind { + block_scope(@scope_info { loop_break: Some(brk), loop_label: l, _ diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 30c541c0c055b..ff493c46a176a 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -123,7 +123,6 @@ use back::abi; use lib; use lib::llvm::{ValueRef, TypeRef, llvm}; use metadata::csearch; -use middle::borrowck::root_map_key; use middle::trans::_match; use middle::trans::adt; use middle::trans::asm; From c0f587de34f30b060df8a88c4068740e587b9340 Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 2 May 2013 18:41:57 -0700 Subject: [PATCH 156/215] librustc: Make uninhabited enums not castable to int --- src/librustc/middle/ty.rs | 15 +++++++++------ src/test/compile-fail/uninhabited-enum-cast.rs | 7 +++++++ 2 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 src/test/compile-fail/uninhabited-enum-cast.rs diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index c42c4c3cf0758..d28efcd55b00c 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -2509,12 +2509,15 @@ pub fn type_is_enum(ty: t) -> bool { // constructors pub fn type_is_c_like_enum(cx: ctxt, ty: t) -> bool { match get(ty).sty { - ty_enum(did, _) => { - let variants = enum_variants(cx, did); - let some_n_ary = vec::any(*variants, |v| vec::len(v.args) > 0u); - return !some_n_ary; - } - _ => return false + ty_enum(did, _) => { + let variants = enum_variants(cx, did); + if variants.len() == 0 { + false + } else { + variants.all(|v| v.args.len() == 0) + } + } + _ => false } } diff --git a/src/test/compile-fail/uninhabited-enum-cast.rs b/src/test/compile-fail/uninhabited-enum-cast.rs new file mode 100644 index 0000000000000..c4a5dc4710cba --- /dev/null +++ b/src/test/compile-fail/uninhabited-enum-cast.rs @@ -0,0 +1,7 @@ +enum E {} + +fn f(e: E) { + println((e as int).to_str()); //~ ERROR non-scalar cast +} + +fn main() {} From db6a62c537852a30f030f866598c358d01fb95cd Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 2 May 2013 18:42:07 -0700 Subject: [PATCH 157/215] rustc: Drop the visitor object from the visitor glue Recent demoding makes the visitor glue leak. It hasn't shown up in tests because the box annihilator deletes the leaked boxes. This affects the new scheduler though which does not yet have a box annihilator. I don't think there's any great way to test this besides setting up a task that doesn't run the box annihilator and I don't know that that's a capability we want tasks to have. --- src/librustc/middle/trans/glue.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs index 4c5a17056b2ea..4025835495b58 100644 --- a/src/librustc/middle/trans/glue.rs +++ b/src/librustc/middle/trans/glue.rs @@ -394,10 +394,15 @@ pub fn call_tydesc_glue(cx: block, v: ValueRef, t: ty::t, field: uint) pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) { let _icx = bcx.insn_ctxt("make_visit_glue"); - let mut bcx = bcx; - let (visitor_trait, object_ty) = ty::visitor_object_ty(bcx.tcx()); - let v = PointerCast(bcx, v, T_ptr(type_of::type_of(bcx.ccx(), object_ty))); - bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, visitor_trait.def_id); + let bcx = do with_scope(bcx, None, ~"visitor cleanup") |bcx| { + let mut bcx = bcx; + let (visitor_trait, object_ty) = ty::visitor_object_ty(bcx.tcx()); + let v = PointerCast(bcx, v, T_ptr(type_of::type_of(bcx.ccx(), object_ty))); + bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, visitor_trait.def_id); + // The visitor is a boxed object and needs to be dropped + add_clean(bcx, v, object_ty); + bcx + }; build_return(bcx); } From f8dffc6789113a10c9dbf1d815c3569b19b53e96 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 2 May 2013 19:13:56 -0700 Subject: [PATCH 158/215] core: Wire up the unwinder to newsched again This was some merge fallout --- src/libcore/sys.rs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs index 215fc95f8c7d7..4a8d9fe27d915 100644 --- a/src/libcore/sys.rs +++ b/src/libcore/sys.rs @@ -204,22 +204,32 @@ impl FailWithCause for &'static str { #[cfg(stage0)] pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! { + do str::as_buf(msg) |msg_buf, _msg_len| { + do str::as_buf(file) |file_buf, _file_len| { + unsafe { + let msg_buf = cast::transmute(msg_buf); + let file_buf = cast::transmute(file_buf); + begin_unwind_(msg_buf, file_buf, line as libc::size_t) + } + } + } +} + +// FIXME #4427: Temporary until rt::rt_fail_ goes away +pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { use rt::{context, OldTaskContext}; use rt::local_services::unsafe_borrow_local_services; match context() { OldTaskContext => { - do str::as_buf(msg) |msg_buf, _msg_len| { - do str::as_buf(file) |file_buf, _file_len| { - unsafe { - let msg_buf = cast::transmute(msg_buf); - let file_buf = cast::transmute(file_buf); - begin_unwind_(msg_buf, file_buf, line as libc::size_t) - } - } + unsafe { + gc::cleanup_stack_for_failure(); + rustrt::rust_upcall_fail(msg, file, line); + cast::transmute(()) } } _ => { + // XXX: Need to print the failure message gc::cleanup_stack_for_failure(); unsafe { let local_services = unsafe_borrow_local_services(); @@ -232,15 +242,6 @@ pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! { } } -// FIXME #4427: Temporary until rt::rt_fail_ goes away -pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { - unsafe { - gc::cleanup_stack_for_failure(); - rustrt::rust_upcall_fail(msg, file, line); - cast::transmute(()) - } -} - // NOTE: remove function after snapshot #[cfg(stage0)] pub fn fail_assert(msg: &str, file: &str, line: uint) -> ! { From 17b368fd2225ffc65333a9a5293fca4f6bdcf7f5 Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Fri, 3 May 2013 11:14:01 +0900 Subject: [PATCH 159/215] mk: configurable android test directory --- mk/install.mk | 17 ++++++++++------- mk/tests.mk | 5 ++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/mk/install.mk b/mk/install.mk index 693589980ce03..71ea1d02a0e1e 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -164,7 +164,7 @@ endef $(foreach target,$(CFG_TARGET_TRIPLES), \ $(if $(findstring $(target),"arm-linux-androideabi"), \ $(if $(findstring adb,$(shell which adb)), \ - $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[A-Za-z0-9]+[[:blank:]]+device')), \ + $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[A-Za-z0-9-]+[[:blank:]]+device')), \ $(info install: install-runtime-target for arm-linux-androideabi enabled \ $(info install: android device attached) \ $(eval $(call DEF_ADB_STATUS, true))), \ @@ -181,6 +181,8 @@ $(foreach target,$(CFG_TARGET_TRIPLES), \ ifeq ($(CFG_ADB_DEVICE),true) +CFG_RUNTIME_PUSH_DIR=/system/lib + ifdef VERBOSE ADB = adb $(1) ADB_PUSH = adb push $(1) $(2) @@ -193,17 +195,18 @@ endif define INSTALL_RUNTIME_TARGET_N install-runtime-target-$(1)-host-$(2): $$(TSREQ$$(ISTAGE)_T_$(1)_H_$(2)) $$(SREQ$$(ISTAGE)_T_$(1)_H_$(2)) - $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(CFG_RUNTIME_$(1)),/system/lib) - $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(CORELIB_GLOB_$(1)),/system/lib) - $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(STDLIB_GLOB_$(1)),/system/lib) + $(Q)$(call ADB_SHELL,mkdir,$(CFG_RUNTIME_PUSH_DIR)) + $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(CFG_RUNTIME_$(1)),$(CFG_RUNTIME_PUSH_DIR)) + $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(CORELIB_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR)) + $(Q)$(call ADB_PUSH,$$(TL$(1)$(2))/$$(STDLIB_GLOB_$(1)),$(CFG_RUNTIME_PUSH_DIR)) endef define INSTALL_RUNTIME_TARGET_CLEANUP_N install-runtime-target-$(1)-cleanup: $(Q)$(call ADB,remount) - $(Q)$(call ADB_SHELL,rm,/system/lib/$(CFG_RUNTIME_$(1))) - $(Q)$(call ADB_SHELL,rm,/system/lib/$(CORELIB_GLOB_$(1))) - $(Q)$(call ADB_SHELL,rm,/system/lib/$(STDLIB_GLOB_$(1))) + $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(CFG_RUNTIME_$(1))) + $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(CORELIB_GLOB_$(1))) + $(Q)$(call ADB_SHELL,rm,$(CFG_RUNTIME_PUSH_DIR)/$(STDLIB_GLOB_$(1))) endef $(eval $(call INSTALL_RUNTIME_TARGET_N,arm-linux-androideabi,$(CFG_BUILD_TRIPLE))) diff --git a/mk/tests.mk b/mk/tests.mk index 310dec8de7977..7fbba3095625d 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -104,7 +104,7 @@ $(foreach target,$(CFG_TARGET_TRIPLES), \ $(eval $(call DEF_RUNNABLE_STATUS,$(target),true))), \ $(if $(findstring $(target),"arm-linux-androideabi"), \ $(if $(findstring adb,$(shell which adb)), \ - $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[A-Za-z0-9]+[[:blank:]]+device')), \ + $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[A-Za-z0-9-]+[[:blank:]]+device')), \ $(info check: $(target) test set is runnable \ $(info check: adb device attached) \ $(eval $(call DEF_RUNNABLE_STATUS,$(target),true))), \ @@ -129,9 +129,8 @@ CFG_ADB_PATH := $(shell which adb) CFG_ADB_TEST_DIR=/system/tmp $(info check: device $(CFG_ADB_TEST_DIR) \ + $(shell $(CFG_ADB_PATH) remount 1>/dev/null) \ $(shell $(CFG_ADB_PATH) shell mkdir $(CFG_ADB_TEST_DIR) 1>/dev/null) \ - $(shell $(CFG_ADB_PATH) shell rm $(CFG_ADB_TEST_DIR)/*-arm-linux-androideabi 1>/dev/null) \ - $(shell $(CFG_ADB_PATH) shell rm $(CFG_ADB_TEST_DIR)/*.so 1>/dev/null) \ ) endif From 76f7207af22d1c64280b1dcbf7d99d198781e0b2 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 2 May 2013 22:18:16 -0700 Subject: [PATCH 160/215] std: xfail test_serializing_pipes --- src/libstd/flatpipes.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/flatpipes.rs b/src/libstd/flatpipes.rs index 55ea9c2948b01..52d6afbb93e86 100644 --- a/src/libstd/flatpipes.rs +++ b/src/libstd/flatpipes.rs @@ -678,6 +678,7 @@ mod test { } #[test] + #[ignore(reason = "FIXME #6211 failing on linux snapshot machine")] fn test_serializing_pipes() { let (port, chan) = serial::pipe_stream(); From f45c6b878ff11ca7d1927f330ee6f2c878893b29 Mon Sep 17 00:00:00 2001 From: kud1ing Date: Fri, 3 May 2013 09:20:01 +0300 Subject: [PATCH 161/215] Add a brief description to show up in http://static.rust-lang.org/doc/core/index.html --- src/libcore/str/ascii.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcore/str/ascii.rs b/src/libcore/str/ascii.rs index 9180c995ca28c..73f556518fa66 100644 --- a/src/libcore/str/ascii.rs +++ b/src/libcore/str/ascii.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Operations on ASCII strings and characters. + use to_str::{ToStr,ToStrConsume}; use str; use cast; From e34a7ecbab8190560d50d4ccb21ffdae855b7c60 Mon Sep 17 00:00:00 2001 From: gifnksm Date: Fri, 3 May 2013 15:57:05 +0900 Subject: [PATCH 162/215] Remove extra `#[cfg(stage0)]` --- src/libcore/bool.rs | 3 --- src/libstd/net_url.rs | 2 -- 2 files changed, 5 deletions(-) diff --git a/src/libcore/bool.rs b/src/libcore/bool.rs index 1b5855049ca61..1b4b81dca267c 100644 --- a/src/libcore/bool.rs +++ b/src/libcore/bool.rs @@ -108,9 +108,6 @@ mod tests { #[test] fn test_bool_from_str() { - #[cfg(stage0)] - use from_str::FromStr; - do all_values |v| { assert!(Some(v) == FromStr::from_str(to_str(v))) } diff --git a/src/libstd/net_url.rs b/src/libstd/net_url.rs index fa872ffee87e6..21e1733cc3075 100644 --- a/src/libstd/net_url.rs +++ b/src/libstd/net_url.rs @@ -13,8 +13,6 @@ #[allow(deprecated_mode)]; use core::cmp::Eq; -#[cfg(stage0)] -use core::from_str::FromStr; use core::io::{Reader, ReaderUtil}; use core::io; use core::hashmap::HashMap; From 02889f75072cd3eb75afc4000d15b8174eda6155 Mon Sep 17 00:00:00 2001 From: Daniel Ralston Date: Fri, 3 May 2013 01:22:52 -0700 Subject: [PATCH 163/215] Add core::cmp::Equiv to prelude --- src/libcore/prelude.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 4527fcf2923da..e394b5d31f68f 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -31,7 +31,7 @@ pub use io::{print, println}; /* Reexported types and traits */ pub use clone::Clone; -pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; +pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv}; pub use container::{Container, Mutable, Map, Set}; pub use hash::Hash; pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter}; From 47050c499a7cc6823ce8ac94f9766dd7a5e61108 Mon Sep 17 00:00:00 2001 From: Daniel Ralston Date: Fri, 3 May 2013 02:25:02 -0700 Subject: [PATCH 164/215] FIX: Export to_bytes::ToBytes --- src/libcore/to_bytes.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libcore/to_bytes.rs b/src/libcore/to_bytes.rs index 7b4b6994e50a5..e563a304f0988 100644 --- a/src/libcore/to_bytes.rs +++ b/src/libcore/to_bytes.rs @@ -419,8 +419,7 @@ impl IterBytes for *const A { } } - -trait ToBytes { +pub trait ToBytes { fn to_bytes(&self, lsb0: bool) -> ~[u8]; } From 34024353e86e22e459a1981f563e3d4f43906432 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 3 May 2013 05:42:00 -0400 Subject: [PATCH 165/215] Change borrow debugging so it is disabled by -O --- src/libcore/rt/env.rs | 2 - src/libcore/unstable/lang.rs | 121 +++++++++++++++------------- src/librustc/middle/lang_items.rs | 20 ++++- src/librustc/middle/trans/common.rs | 32 ++++++-- src/librustc/middle/trans/datum.rs | 24 +++++- src/rt/rust_env.cpp | 2 - src/rt/rust_env.h | 1 - 7 files changed, 129 insertions(+), 73 deletions(-) diff --git a/src/libcore/rt/env.rs b/src/libcore/rt/env.rs index 1f52cf77868a2..e479375401a3b 100644 --- a/src/libcore/rt/env.rs +++ b/src/libcore/rt/env.rs @@ -33,8 +33,6 @@ pub struct Environment { argv: **c_char, /// Print GC debugging info (true if env var RUST_DEBUG_MEM is set) debug_mem: bool, - /// Track origin of `@mut` borrows (true if env var RUST_DEBUG_BORROWS is set) - debug_borrows: bool } /// Get the global environment settings diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index a3e44b5feea4a..27fc3287bdb39 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -19,7 +19,7 @@ use sys; use unstable::exchange_alloc; use cast::transmute; use task::rt::rust_get_task; -use option::{Some, None}; +use option::{Option, Some, None}; #[allow(non_camel_case_types)] pub type rust_task = c_void; @@ -79,6 +79,19 @@ struct BorrowRecord { line: size_t } +fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> { + unsafe { + let cur_task = rust_get_task(); + let ptr = rustrt::rust_take_task_borrow_list(cur_task); + if ptr.is_null() { + None + } else { + let v: ~[BorrowRecord] = transmute(ptr); + Some(v) + } + } +} + fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { unsafe { let cur_task = rust_get_task(); @@ -93,23 +106,20 @@ fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { pub unsafe fn clear_task_borrow_list() { // pub because it is used by the box annihilator. - let cur_task = rust_get_task(); - let ptr = rustrt::rust_take_task_borrow_list(cur_task); - if !ptr.is_null() { - let _: ~[BorrowRecord] = transmute(ptr); - } + let _ = try_take_task_borrow_list(); } fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { debug_ptr("fail_borrowed: ", box); - if !::rt::env::get().debug_borrows { - let msg = "borrowed"; - do str::as_buf(msg) |msg_p, _| { - fail_(msg_p as *c_char, file, line); + match try_take_task_borrow_list() { + None => { // not recording borrows + let msg = "borrowed"; + do str::as_buf(msg) |msg_p, _| { + fail_(msg_p as *c_char, file, line); + } } - } else { - do swap_task_borrow_list |borrow_list| { + Some(borrow_list) => { // recording borrows let mut msg = ~"borrowed"; let mut sep = " at "; for borrow_list.each_reverse |entry| { @@ -126,7 +136,6 @@ fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { do str::as_buf(msg) |msg_p, _| { fail_(msg_p as *c_char, file, line) } - borrow_list } } } @@ -211,34 +220,6 @@ pub unsafe fn borrow_as_imm(a: *u8) { (*a).header.ref_count |= FROZEN_BIT; } -fn add_borrow_to_task_list(a: *mut BoxRepr, file: *c_char, line: size_t) { - do swap_task_borrow_list |borrow_list| { - let mut borrow_list = borrow_list; - borrow_list.push(BorrowRecord {box: a, file: file, line: line}); - borrow_list - } -} - -fn remove_borrow_from_task_list(a: *mut BoxRepr, file: *c_char, line: size_t) { - do swap_task_borrow_list |borrow_list| { - let mut borrow_list = borrow_list; - let br = BorrowRecord {box: a, file: file, line: line}; - match borrow_list.rposition_elem(&br) { - Some(idx) => { - borrow_list.remove(idx); - borrow_list - } - None => { - let err = fmt!("no borrow found, br=%?, borrow_list=%?", - br, borrow_list); - do str::as_buf(err) |msg_p, _| { - fail_(msg_p as *c_char, file, line) - } - } - } - } -} - #[cfg(not(stage0))] #[lang="borrow_as_imm"] #[inline(always)] @@ -252,12 +233,8 @@ pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { if (ref_count & MUT_BIT) != 0 { fail_borrowed(a, file, line); - } else { - (*a).header.ref_count |= FROZEN_BIT; - if ::rt::env::get().debug_borrows { - add_borrow_to_task_list(a, file, line); - } } + ref_count } @@ -273,15 +250,53 @@ pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint { let ref_count = (*a).header.ref_count; if (ref_count & (MUT_BIT|FROZEN_BIT)) != 0 { fail_borrowed(a, file, line); - } else { - (*a).header.ref_count |= (MUT_BIT|FROZEN_BIT); - if ::rt::env::get().debug_borrows { - add_borrow_to_task_list(a, file, line); - } } ref_count } + +#[cfg(not(stage0))] +#[lang="record_borrow"] +pub unsafe fn record_borrow(a: *u8, old_ref_count: uint, + file: *c_char, line: size_t) { + if (old_ref_count & ALL_BITS) == 0 { + // was not borrowed before + let a: *mut BoxRepr = transmute(a); + do swap_task_borrow_list |borrow_list| { + let mut borrow_list = borrow_list; + borrow_list.push(BorrowRecord {box: a, file: file, line: line}); + borrow_list + } + } +} + +#[cfg(not(stage0))] +#[lang="unrecord_borrow"] +pub unsafe fn unrecord_borrow(a: *u8, old_ref_count: uint, + file: *c_char, line: size_t) { + if (old_ref_count & ALL_BITS) == 0 { + // was not borrowed before + let a: *mut BoxRepr = transmute(a); + do swap_task_borrow_list |borrow_list| { + let mut borrow_list = borrow_list; + let br = BorrowRecord {box: a, file: file, line: line}; + match borrow_list.rposition_elem(&br) { + Some(idx) => { + borrow_list.remove(idx); + borrow_list + } + None => { + let err = fmt!("no borrow found, br=%?, borrow_list=%?", + br, borrow_list); + do str::as_buf(err) |msg_p, _| { + fail_(msg_p as *c_char, file, line) + } + } + } + } + } +} + #[cfg(stage0)] #[lang="return_to_mut"] #[inline(always)] @@ -312,10 +327,6 @@ pub unsafe fn return_to_mut(a: *u8, old_ref_count: uint, debug_ptr(" (old) : ", old_ref_count as *()); debug_ptr(" (new) : ", ref_count as *()); debug_ptr(" (comb): ", combined as *()); - - if ::rt::env::get().debug_borrows { - remove_borrow_from_task_list(a, file, line); - } } } diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 314b58d13e147..448f33796bcfd 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -70,18 +70,20 @@ pub enum LangItem { ReturnToMutFnLangItem, // 32 CheckNotBorrowedFnLangItem, // 33 StrDupUniqFnLangItem, // 34 + RecordBorrowFnLangItem, // 35 + UnrecordBorrowFnLangItem, // 36 - StartFnLangItem, // 35 + StartFnLangItem, // 37 } pub struct LanguageItems { - items: [Option, ..36] + items: [Option, ..38] } pub impl LanguageItems { pub fn new() -> LanguageItems { LanguageItems { - items: [ None, ..36 ] + items: [ None, ..38 ] } } @@ -133,8 +135,10 @@ pub impl LanguageItems { 32 => "return_to_mut", 33 => "check_not_borrowed", 34 => "strdup_uniq", + 35 => "record_borrow", + 36 => "unrecord_borrow", - 35 => "start", + 37 => "start", _ => "???" } @@ -251,6 +255,12 @@ pub impl LanguageItems { pub fn strdup_uniq_fn(&const self) -> def_id { self.items[StrDupUniqFnLangItem as uint].get() } + pub fn record_borrow_fn(&const self) -> def_id { + self.items[RecordBorrowFnLangItem as uint].get() + } + pub fn unrecord_borrow_fn(&const self) -> def_id { + self.items[UnrecordBorrowFnLangItem as uint].get() + } pub fn start_fn(&const self) -> def_id { self.items[StartFnLangItem as uint].get() } @@ -302,6 +312,8 @@ fn LanguageItemCollector(crate: @crate, item_refs.insert(@~"check_not_borrowed", CheckNotBorrowedFnLangItem as uint); item_refs.insert(@~"strdup_uniq", StrDupUniqFnLangItem as uint); + item_refs.insert(@~"record_borrow", RecordBorrowFnLangItem as uint); + item_refs.insert(@~"unrecord_borrow", UnrecordBorrowFnLangItem as uint); item_refs.insert(@~"start", StartFnLangItem as uint); LanguageItemCollector { diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 705a89381dfa5..2a13cf73f8bba 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -489,15 +489,37 @@ pub fn add_clean_return_to_mut(bcx: block, clean_temp( frozen_val_ref, |bcx| { + let mut bcx = bcx; + + let box_ptr = + build::Load(bcx, + build::PointerCast(bcx, + frozen_val_ref, + T_ptr(T_ptr(T_i8())))); + + let bits_val = + build::Load(bcx, + bits_val_ref); + + if bcx.tcx().sess.opts.optimize == session::No { + bcx = callee::trans_lang_call( + bcx, + bcx.tcx().lang_items.unrecord_borrow_fn(), + ~[ + box_ptr, + bits_val, + filename_val, + line_val + ], + expr::Ignore); + } + callee::trans_lang_call( bcx, bcx.tcx().lang_items.return_to_mut_fn(), ~[ - build::Load(bcx, - build::PointerCast(bcx, - frozen_val_ref, - T_ptr(T_ptr(T_i8())))), - build::Load(bcx, bits_val_ref), + box_ptr, + bits_val, filename_val, line_val ], diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index d6df6c87dec43..af7165c53a7c2 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -101,6 +101,7 @@ use middle::trans::type_of; use middle::ty; use util::common::indenter; use util::ppaux::ty_to_str; +use driver::session; use core::container::Set; // XXX: this should not be necessary use core::to_bytes; @@ -564,19 +565,34 @@ pub impl Datum { DynaMut => bcx.tcx().lang_items.borrow_as_mut_fn(), }; + let box_ptr = Load(bcx, + PointerCast(bcx, + scratch.val, + T_ptr(T_ptr(T_i8())))); + bcx = callee::trans_lang_call( bcx, freeze_did, ~[ - Load(bcx, - PointerCast(bcx, - scratch.val, - T_ptr(T_ptr(T_i8())))), + box_ptr, filename, line ], expr::SaveIn(scratch_bits.val)); + if bcx.tcx().sess.opts.optimize == session::No { + bcx = callee::trans_lang_call( + bcx, + bcx.tcx().lang_items.record_borrow_fn(), + ~[ + box_ptr, + Load(bcx, scratch_bits.val), + filename, + line + ], + expr::Ignore); + } + add_clean_return_to_mut( cleanup_bcx, scratch.val, scratch_bits.val, filename, line); diff --git a/src/rt/rust_env.cpp b/src/rt/rust_env.cpp index e6fe35609ec93..041b4efac52a2 100644 --- a/src/rt/rust_env.cpp +++ b/src/rt/rust_env.cpp @@ -24,7 +24,6 @@ #define RUST_SEED "RUST_SEED" #define RUST_POISON_ON_FREE "RUST_POISON_ON_FREE" #define RUST_DEBUG_MEM "RUST_DEBUG_MEM" -#define RUST_DEBUG_BORROWS "RUST_DEBUG_BORROWS" #if defined(__WIN32__) static int @@ -131,7 +130,6 @@ load_env(int argc, char **argv) { env->argc = argc; env->argv = argv; env->debug_mem = getenv(RUST_DEBUG_MEM) != NULL; - env->debug_borrows = getenv(RUST_DEBUG_BORROWS) != NULL; return env; } diff --git a/src/rt/rust_env.h b/src/rt/rust_env.h index 322198bb031ff..df27f7674f265 100644 --- a/src/rt/rust_env.h +++ b/src/rt/rust_env.h @@ -28,7 +28,6 @@ struct rust_env { int argc; char **argv; rust_bool debug_mem; - rust_bool debug_borrows; }; rust_env* load_env(int argc, char **argv); From 2e3e0c0892d6fc9d20374d31db994eee4d083366 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Fri, 3 May 2013 12:26:45 +0200 Subject: [PATCH 166/215] Avoid needless creation of unique strings in fmt!() Only the first portion has to be owned, as it acts as the buffer for the constructed string. The remaining strings can be static. --- src/libsyntax/ext/fmt.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/ext/fmt.rs b/src/libsyntax/ext/fmt.rs index 62641279f883a..e9eebe5b2acc6 100644 --- a/src/libsyntax/ext/fmt.rs +++ b/src/libsyntax/ext/fmt.rs @@ -273,15 +273,13 @@ fn pieces_to_expr(cx: @ext_ctxt, sp: span, match pc { /* Raw strings get appended via str::push_str */ PieceString(s) => { - let portion = mk_uniq_str(cx, fmt_sp, s); - /* If this is the first portion, then initialize the local buffer with it directly. If it's actually the only piece, then there's no need for it to be mutable */ if i == 0 { - stms.push(mk_local(cx, fmt_sp, npieces > 1, ident, portion)); + stms.push(mk_local(cx, fmt_sp, npieces > 1, ident, mk_uniq_str(cx, fmt_sp, s))); } else { - let args = ~[mk_mut_addr_of(cx, fmt_sp, buf()), portion]; + let args = ~[mk_mut_addr_of(cx, fmt_sp, buf()), mk_base_str(cx, fmt_sp, s)]; let call = mk_call_global(cx, fmt_sp, ~[str_ident, push_ident], From 35214d3c6cd5f70b38baa6d879ca40d9db8118ba Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Sat, 4 May 2013 00:46:52 +0900 Subject: [PATCH 167/215] configure: CFG_ADB for adb added --- configure | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/configure b/configure index 884ececa24b1e..0c4afa0566de3 100755 --- a/configure +++ b/configure @@ -439,6 +439,10 @@ then probe CFG_ZCAT zcat fi +step_msg "looking for target specific programs" + +probe CFG_ADB adb + if [ ! -z "$CFG_PANDOC" ] then PV_MAJOR_MINOR=$(pandoc --version | grep '^pandoc ' | From 9ecb97ae58c6fde97bfe58aeddd11790899bd4ec Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Sat, 4 May 2013 00:47:54 +0900 Subject: [PATCH 168/215] mk: install.mk directory argument pass for install-runtime-target --- mk/install.mk | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/mk/install.mk b/mk/install.mk index 71ea1d02a0e1e..5fa477a790d4f 100644 --- a/mk/install.mk +++ b/mk/install.mk @@ -157,40 +157,46 @@ uninstall: # target platform specific variables # for arm-linux-androidabi -define DEF_ADB_STATUS -CFG_ADB_DEVICE=$(1) +define DEF_ADB_DEVICE_STATUS +CFG_ADB_DEVICE_STATUS=$(1) endef $(foreach target,$(CFG_TARGET_TRIPLES), \ $(if $(findstring $(target),"arm-linux-androideabi"), \ - $(if $(findstring adb,$(shell which adb)), \ - $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[A-Za-z0-9-]+[[:blank:]]+device')), \ - $(info install: install-runtime-target for arm-linux-androideabi enabled \ + $(if $(findstring adb,$(CFG_ADB)), \ + $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \ + $(info install: install-runtime-target for $(target) enabled \ $(info install: android device attached) \ - $(eval $(call DEF_ADB_STATUS, true))), \ - $(info install: install-runtime-target for arm-linux-androideabi disabled \ + $(eval $(call DEF_ADB_DEVICE_STATUS, true))), \ + $(info install: install-runtime-target for $(target) disabled \ $(info install: android device not attached) \ - $(eval $(call DEF_ADB_STATUS, false))) \ + $(eval $(call DEF_ADB_DEVICE_STATUS, false))) \ ), \ - $(info install: install-runtime-target for arm-linux-androideabi disabled \ + $(info install: install-runtime-target for $(target) disabled \ $(info install: adb not found) \ - $(eval $(call DEF_ADB_STATUS, false))) \ + $(eval $(call DEF_ADB_DEVICE_STATUS, false))) \ ), \ ) \ ) -ifeq ($(CFG_ADB_DEVICE),true) - +ifeq (install-runtime-target,$(firstword $(MAKECMDGOALS))) +$(eval $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)):;@:) +L_TOKEN := $(word 2,$(MAKECMDGOALS)) +ifeq ($(L_TOKEN),) CFG_RUNTIME_PUSH_DIR=/system/lib +else +CFG_RUNTIME_PUSH_DIR=$(L_TOKEN) +endif +ifeq ($(CFG_ADB_DEVICE_STATUS),true) ifdef VERBOSE ADB = adb $(1) ADB_PUSH = adb push $(1) $(2) ADB_SHELL = adb shell $(1) $(2) else - ADB = $(Q)$(call E, adb $(1)) && adb $(1) 1>/dev/null 2>/dev/null - ADB_PUSH = $(Q)$(call E, adb push $(1)) && adb push $(1) $(2) 1>/dev/null 2>/dev/null - ADB_SHELL = $(Q)$(call E, adb shell $(1) $(2)) && adb shell $(1) $(2) 1>/dev/null 2>/dev/null + ADB = $(Q)$(call E, adb $(1)) && adb $(1) 1>/dev/null + ADB_PUSH = $(Q)$(call E, adb push $(1)) && adb push $(1) $(2) 1>/dev/null + ADB_SHELL = $(Q)$(call E, adb shell $(1) $(2)) && adb shell $(1) $(2) 1>/dev/null endif define INSTALL_RUNTIME_TARGET_N @@ -215,8 +221,9 @@ $(eval $(call INSTALL_RUNTIME_TARGET_CLEANUP_N,arm-linux-androideabi)) install-runtime-target: \ install-runtime-target-arm-linux-androideabi-cleanup \ install-runtime-target-arm-linux-androideabi-host-$(CFG_BUILD_TRIPLE) - else install-runtime-target: - @echo + @echo "No device to install runtime library" + @echo +endif endif From 84bdd05accba00254e999e1d73b963cca3388d33 Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Sat, 4 May 2013 00:49:18 +0900 Subject: [PATCH 169/215] compiletest: fix decision rule to run and cleanup --- mk/tests.mk | 90 +++++++++++++--------------------- src/compiletest/compiletest.rc | 8 +-- src/compiletest/runtest.rs | 47 ++++++++++++------ 3 files changed, 72 insertions(+), 73 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index 7fbba3095625d..9997f170a98f0 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -92,48 +92,44 @@ endef $(foreach target,$(CFG_TARGET_TRIPLES), \ $(eval $(call DEF_TARGET_COMMANDS,$(target)))) -# Target specific variables +# Target platform specific variables # for arm-linux-androidabi -define DEF_RUNNABLE_STATUS -CFG_RUNNABLE_$(1)=$(2) +define DEF_ADB_DEVICE_STATUS +CFG_ADB_DEVICE_STATUS=$(1) endef $(foreach target,$(CFG_TARGET_TRIPLES), \ - $(if $(findstring $(target),$(CFG_BUILD_TRIPLE)), \ - $(info check: $(target) test set is runnable \ - $(eval $(call DEF_RUNNABLE_STATUS,$(target),true))), \ - $(if $(findstring $(target),"arm-linux-androideabi"), \ - $(if $(findstring adb,$(shell which adb)), \ - $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[A-Za-z0-9-]+[[:blank:]]+device')), \ - $(info check: $(target) test set is runnable \ - $(info check: adb device attached) \ - $(eval $(call DEF_RUNNABLE_STATUS,$(target),true))), \ - $(info check: $(target) test set is not runnable \ - $(info check: adb device not attached) \ - $(eval $(call DEF_RUNNABLE_STATUS,$(target),false))) \ - ), \ - $(info check: $(target) test set is not runnable \ - $(info check: adb not found) \ - $(eval $(call DEF_RUNNABLE_STATUS,$(target),false))) \ + $(if $(findstring $(target),"arm-linux-androideabi"), \ + $(if $(findstring adb,$(CFG_ADB)), \ + $(if $(findstring device,$(shell adb devices 2>/dev/null | grep -E '^[_A-Za-z0-9-]+[[:blank:]]+device')), \ + $(info check: $(target) test enabled \ + $(info check: android device attached) \ + $(eval $(call DEF_ADB_DEVICE_STATUS, true))), \ + $(info check: $(target) test disabled \ + $(info check: android device not attached) \ + $(eval $(call DEF_ADB_DEVICE_STATUS, false))) \ ), \ - $(info check: $(target) test set is not runnable \ - $(eval $(call DEF_RUNNABLE_STATUS,$(target),false)) \ - ) \ - ) \ + $(info check: $(target) test disabled \ + $(info check: adb not found) \ + $(eval $(call DEF_ADB_DEVICE_STATUS, false))) \ + ), \ ) \ ) -ifeq ($(CFG_RUNNABLE_arm-linux-androideabi),true) -CFG_ADB_DEVICE=true -CFG_ADB_PATH := $(shell which adb) -CFG_ADB_TEST_DIR=/system/tmp +ifeq ($(CFG_ADB_DEVICE_STATUS),true) +CFG_ADB_TEST_DIR=/data/tmp -$(info check: device $(CFG_ADB_TEST_DIR) \ - $(shell $(CFG_ADB_PATH) remount 1>/dev/null) \ - $(shell $(CFG_ADB_PATH) shell mkdir $(CFG_ADB_TEST_DIR) 1>/dev/null) \ +$(info check: android device test dir $(CFG_ADB_TEST_DIR) ready \ + $(shell adb remount 1>/dev/null) \ + $(shell adb shell mkdir $(CFG_ADB_TEST_DIR) 1>/dev/null) \ + $(shell adb push $(CFG_ANDROID_CROSS_PATH)/arm-linux-androideabi/lib/armv7-a/libgnustl_shared.so \ + $(CFG_ADB_TEST_DIR) 1>/dev/null) \ ) +else +CFG_ADB_TEST_DIR= endif + ###################################################################### # Main test targets ###################################################################### @@ -366,14 +362,15 @@ check-stage$(1)-T-$(2)-H-$(3)-$(4)-exec: $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4 $$(call TEST_OK_FILE,$(1),$(2),$(3),$(4)): \ $(3)/test/$(4)test.stage$(1)-$(2)$$(X_$(2)) @$$(call E, run: $$< via adb) - @$(CFG_ADB_PATH) push $$< $(CFG_ADB_TEST_DIR) - @$(CFG_ADB_PATH) shell $(CFG_ADB_TEST_DIR)/`echo $$< | sed 's/.*\///'` \ + @$(CFG_ADB) push $$< $(CFG_ADB_TEST_DIR) + @$(CFG_ADB) shell LD_LIBRARY_PATH=$(CFG_ADB_TEST_DIR) \ + $(CFG_ADB_TEST_DIR)/`echo $$< | sed 's/.*\///'` \ --logfile $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log > \ tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp @cat tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp @touch tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).log - @$(CFG_ADB_PATH) pull $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log tmp/ - @$(CFG_ADB_PATH) shell rm $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log + @$(CFG_ADB) pull $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log tmp/ + @$(CFG_ADB) shell rm $(CFG_ADB_TEST_DIR)/check-stage$(1)-T-$(2)-H-$(3)-$(4).log @if grep -q "result: ok" tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \ then \ rm tmp/check-stage$(1)-T-$(2)-H-$(3)-$(4).tmp; \ @@ -400,11 +397,11 @@ $(foreach host,$(CFG_HOST_TRIPLES), \ $(if $(findstring $(target),$(CFG_BUILD_TRIPLE)), \ $(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))), \ $(if $(findstring $(target),"arm-linux-androideabi"), \ - $(if $(findstring $(CFG_RUNNABLE_arm-linux-androideabi),"true"), \ + $(if $(findstring $(CFG_ADB_DEVICE_STATUS),"true"), \ $(eval $(call DEF_TEST_CRATE_RULES_arm-linux-androideabi,$(stage),$(target),$(host),$(crate))), \ $(eval $(call DEF_TEST_CRATE_RULES_null,$(stage),$(target),$(host),$(crate))) \ ), \ - $(eval $(call DEF_TEST_CRATE_RULES_null,$(stage),$(target),$(host),$(crate))) \ + $(eval $(call DEF_TEST_CRATE_RULES,$(stage),$(target),$(host),$(crate))) \ )))))) @@ -496,36 +493,19 @@ TEST_SREQ$(1)_T_$(2)_H_$(3) = \ # Rules for the cfail/rfail/rpass/bench/perf test runner -ifeq ($(CFG_ADB_DEVICE),true) - CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --compile-lib-path $$(HLIB$(1)_H_$(3)) \ --run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \ - --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ + --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ --aux-base $$(S)src/test/auxiliary/ \ --stage-id stage$(1)-$(2) \ --host $(CFG_BUILD_TRIPLE) \ --target $(2) \ - --adb-path=$(CFG_ADB_PATH) \ + --adb-path=$(CFG_ADB) \ --adb-test-dir=$(CFG_ADB_TEST_DIR) \ --rustcflags "$(RUSTC_FLAGS_$(2)) $$(CFG_RUSTC_FLAGS) --target=$(2)" \ $$(CTEST_TESTARGS) -else - -CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ - --compile-lib-path $$(HLIB$(1)_H_$(3)) \ - --run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \ - --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ - --aux-base $$(S)src/test/auxiliary/ \ - --stage-id stage$(1)-$(2) \ - --host $(CFG_BUILD_TRIPLE) \ - --target $(2) \ - --rustcflags "$(RUSTC_FLAGS_$(2)) $$(CFG_RUSTC_FLAGS) --target=$(2)" \ - $$(CTEST_TESTARGS) - -endif - CTEST_DEPS_rpass_$(1)-T-$(2)-H-$(3) = $$(RPASS_TESTS) CTEST_DEPS_rpass_full_$(1)-T-$(2)-H-$(3) = $$(RPASS_FULL_TESTS) $$(TLIBRUSTC_DEFAULT$(1)_T_$(2)_H_$(3)) CTEST_DEPS_rfail_$(1)-T-$(2)-H-$(3) = $$(RFAIL_TESTS) diff --git a/src/compiletest/compiletest.rc b/src/compiletest/compiletest.rc index 5575c01a9065b..fab73d78021c2 100644 --- a/src/compiletest/compiletest.rc +++ b/src/compiletest/compiletest.rc @@ -108,11 +108,13 @@ pub fn parse_config(args: ~[~str]) -> config { else { match getopts::opt_maybe_str(matches, ~"target") { Some(~"arm-linux-androideabi") => { - if (getopts::opt_maybe_str(matches, ~"adb-path") != - option::None) { true } + if (opt_str(getopts::opt_maybe_str(matches, ~"adb-test-dir")) != + ~"(none)" && + opt_str(getopts::opt_maybe_str(matches, ~"adb-test-dir")) != + ~"") { true } else { false } } - _ => { false } + _ => { true } } }, verbose: getopts::opt_present(matches, ~"verbose") diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index 142460fe0dc09..d1319c395add6 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -77,9 +77,18 @@ fn run_rfail_test(config: config, props: TestProps, testfile: &Path) { fatal_ProcRes(~"run-fail test isn't valgrind-clean!", ProcRes); } - if (config.flag_runnable) { + if (config.host == config.target) { check_correct_failure_status(ProcRes); check_error_patterns(props, testfile, ProcRes); + } else { + match (config.target, config.flag_runnable) { + + (~"arm-linux-androideabi", false) => { } + _ => { + check_correct_failure_status(ProcRes); + check_error_patterns(props, testfile, ProcRes); + } + } } } @@ -490,16 +499,10 @@ fn exec_compiled_test(config: config, props: TestProps, make_run_args(config, props, testfile), env, config.run_lib_path, None) - } - else { + } else { let args = make_run_args(config, props, testfile); let cmdline = make_cmdline(~"", args.prog, args.args); - let defaultRes = match config.mode { - mode_run_fail => ProcRes {status: 101, stdout: ~"", stderr: ~"", cmdline: cmdline}, - _ => ProcRes {status: 0, stdout: ~"", stderr: ~"", cmdline: cmdline} - }; - match (config.target, config.flag_runnable) { (~"arm-linux-androideabi", true) => { @@ -524,8 +527,8 @@ fn exec_compiled_test(config: config, props: TestProps, // execute program logv(config, fmt!("executing (%s) %s", config.target, cmdline)); - // NOTE : adb shell dose not forward to each stdout and stderr of internal result - // but forward to stdout only + // NOTE: adb shell dose not forward stdout and stderr of internal result + // to stdout and stderr seperately but to stdout only let mut newargs_out = ~[]; let mut newargs_err = ~[]; let subargs = args.args; @@ -534,12 +537,11 @@ fn exec_compiled_test(config: config, props: TestProps, let mut newcmd_out = ~""; let mut newcmd_err = ~""; - newcmd_out.push_str(fmt!( - "LD_LIBRARY_PATH=%s; export LD_LIBRARY_PATH; cd %s; ./%s", + + newcmd_out.push_str(fmt!("LD_LIBRARY_PATH=%s %s/%s", config.adb_test_dir, config.adb_test_dir, prog_short)); - newcmd_err.push_str(fmt!( - "LD_LIBRARY_PATH=%s; export LD_LIBRARY_PATH; cd %s; ./%s", + newcmd_err.push_str(fmt!("LD_LIBRARY_PATH=%s %s/%s", config.adb_test_dir, config.adb_test_dir, prog_short)); for vec::each(subargs) |tv| { @@ -569,7 +571,22 @@ fn exec_compiled_test(config: config, props: TestProps, stderr: exe_result_err.out, cmdline: cmdline } } } - _=> defaultRes + + (~"arm-linux-androideabi", false) => { + match config.mode { + mode_run_fail => ProcRes {status: 101, stdout: ~"", + stderr: ~"", cmdline: cmdline}, + _ => ProcRes {status: 0, stdout: ~"", + stderr: ~"", cmdline: cmdline} + } + } + + _=> { + compose_and_run(config, testfile, + make_run_args(config, props, testfile), + env, + config.run_lib_path, None) + } } } } From e7d96934c16c915d18be391836fbf0ebca6c558b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 3 May 2013 12:11:15 -0400 Subject: [PATCH 170/215] Correct mismatch between the way that pattern ids and expression ids map to types (pattern ids map to the input type, expression ids map to the output type) --- src/librustc/middle/borrowck/check_loans.rs | 2 +- .../middle/borrowck/gather_loans/lifetime.rs | 8 +- src/librustc/middle/borrowck/mod.rs | 18 +- src/librustc/middle/mem_categorization.rs | 195 +++++++++--------- src/librustc/middle/trans/_match.rs | 17 +- src/librustc/middle/trans/datum.rs | 4 +- src/librustc/middle/trans/expr.rs | 2 +- 7 files changed, 131 insertions(+), 115 deletions(-) diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 70da9c9380559..c2dc2fb22ab5b 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -378,7 +378,7 @@ pub impl<'self> CheckLoanCtxt<'self> { // Dynamically check writes to `@mut` let key = root_map_key { - id: base.id, + id: guarantor.id, derefs: deref_count }; debug!("Inserting write guard at %?", key); diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index fdfb26c0d0835..43fff110a7a7e 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -97,7 +97,7 @@ impl GuaranteeLifetimeContext { ); if !omit_root { - self.check_root(base, derefs, ptr_mutbl, discr_scope); + self.check_root(cmt, base, derefs, ptr_mutbl, discr_scope); } else { debug!("omitting root, base=%s, base_scope=%?", base.repr(self.tcx()), base_scope); @@ -168,12 +168,14 @@ impl GuaranteeLifetimeContext { } fn check_root(&self, + cmt_deref: mc::cmt, cmt_base: mc::cmt, derefs: uint, ptr_mutbl: ast::mutability, discr_scope: Option) { - debug!("check_root(cmt_base=%s, derefs=%? ptr_mutbl=%?, \ + debug!("check_root(cmt_deref=%s, cmt_base=%s, derefs=%?, ptr_mutbl=%?, \ discr_scope=%?)", + cmt_deref.repr(self.tcx()), cmt_base.repr(self.tcx()), derefs, ptr_mutbl, @@ -234,7 +236,7 @@ impl GuaranteeLifetimeContext { }; // Add a record of what is required - let rm_key = root_map_key {id: cmt_base.id, derefs: derefs}; + let rm_key = root_map_key {id: cmt_deref.id, derefs: derefs}; let root_info = RootInfo {scope: root_scope, freeze: opt_dyna}; self.bccx.root_map.insert(rm_key, root_info); diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index 3f10223723727..a44f743c9ead0 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -172,11 +172,19 @@ pub struct BorrowStats { pub type LoanMap = @mut HashMap; -// the keys to the root map combine the `id` of the expression with -// the number of types that it is autodereferenced. So, for example, -// if you have an expression `x.f` and x has type ~@T, we could add an -// entry {id:x, derefs:0} to refer to `x` itself, `{id:x, derefs:1}` -// to refer to the deref of the unique pointer, and so on. +// The keys to the root map combine the `id` of the deref expression +// with the number of types that it is *autodereferenced*. So, for +// example, imagine I have a variable `x: @@@T` and an expression +// `(*x).f`. This will have 3 derefs, one explicit and then two +// autoderefs. These are the relevant `root_map_key` values that could +// appear: +// +// {id:*x, derefs:0} --> roots `x` (type: @@@T, due to explicit deref) +// {id:*x, derefs:1} --> roots `*x` (type: @@T, due to autoderef #1) +// {id:*x, derefs:2} --> roots `**x` (type: @T, due to autoderef #2) +// +// Note that there is no entry with derefs:3---the type of that expression +// is T, which is not a box. #[deriving(Eq, IterBytes)] pub struct root_map_key { id: ast::node_id, diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 5921e4b0e4ca0..f1c337125d704 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -92,12 +92,12 @@ pub enum ptr_kind { pub enum interior_kind { interior_tuple, // elt in a tuple interior_anon_field, // anonymous field (in e.g. - // struct Foo(int, int); + // struct Foo(int, int); interior_variant(ast::def_id), // internals to a variant of given enum interior_field(ast::ident, // name of field - ast::mutability), // declared mutability of field + ast::mutability), // declared mutability of field interior_index(ty::t, // type of vec/str/etc being deref'd - ast::mutability) // mutability of vec content + ast::mutability) // mutability of vec content } #[deriving(Eq)] @@ -108,18 +108,27 @@ pub enum MutabilityCategory { McInherited // Inherited from the fact that owner is mutable. } +// `cmt`: "Category, Mutability, and Type". +// // a complete categorization of a value indicating where it originated // and how it is located, as well as the mutability of the memory in // which the value is stored. // -// note: cmt stands for "categorized mutable type". +// *WARNING* The field `cmt.type` is NOT necessarily the same as the +// result of `node_id_to_type(cmt.id)`. This is because the `id` is +// always the `id` of the node producing the type; in an expression +// like `*x`, the type of this deref node is the deref'd type (`T`), +// but in a pattern like `@x`, the `@x` pattern is again a +// dereference, but its type is the type *before* the dereference +// (`@T`). So use `cmt.type` to find the type of the value in a consistent +// fashion. For more details, see the method `cat_pattern` #[deriving(Eq)] pub struct cmt_ { id: ast::node_id, // id of expr/pat producing this value span: span, // span of same expr/pat cat: categorization, // categorization of expr mutbl: MutabilityCategory, // mutability of expr as lvalue - ty: ty::t // type of the expr + ty: ty::t // type of the expr (*see WARNING above*) } pub type cmt = @cmt_; @@ -245,19 +254,6 @@ pub fn cat_def( return mcx.cat_def(expr_id, expr_span, expr_ty, def); } -pub fn cat_variant( - tcx: ty::ctxt, - method_map: typeck::method_map, - arg: N, - enum_did: ast::def_id, - cmt: cmt) -> cmt { - - let mcx = &mem_categorization_ctxt { - tcx: tcx, method_map: method_map - }; - return mcx.cat_variant(arg, enum_did, cmt); -} - pub trait ast_node { fn id(&self) -> ast::node_id; fn span(&self) -> span; @@ -273,16 +269,6 @@ impl ast_node for @ast::pat { fn span(&self) -> span { self.span } } -pub trait get_type_for_node { - fn ty(&self, node: N) -> ty::t; -} - -impl get_type_for_node for ty::ctxt { - fn ty(&self, node: N) -> ty::t { - ty::node_id_to_type(*self, node.id()) - } -} - pub struct mem_categorization_ctxt { tcx: ty::ctxt, method_map: typeck::method_map, @@ -336,6 +322,14 @@ pub impl MutabilityCategory { } pub impl mem_categorization_ctxt { + fn expr_ty(&self, expr: @ast::expr) -> ty::t { + ty::expr_ty(self.tcx, expr) + } + + fn pat_ty(&self, pat: @ast::pat) -> ty::t { + ty::node_id_to_type(self.tcx, pat.id) + } + fn cat_expr(&self, expr: @ast::expr) -> cmt { match self.tcx.adjustments.find(&expr.id) { None => { @@ -385,7 +379,7 @@ pub impl mem_categorization_ctxt { expr.id, pprust::expr_to_str(expr, self.tcx.sess.intr())); let tcx = self.tcx; - let expr_ty = tcx.ty(expr); + let expr_ty = self.expr_ty(expr); match expr.node { ast::expr_unary(ast::deref, e_base) => { if self.method_map.contains_key(&expr.id) { @@ -402,7 +396,8 @@ pub impl mem_categorization_ctxt { assert!(!self.method_map.contains_key(&expr.id)); let base_cmt = self.cat_expr(base); - self.cat_field(expr, base_cmt, f_name, expr.id) + self.cat_field(expr, base_cmt, f_name, + self.expr_ty(expr), expr.id) } ast::expr_index(base, _) => { @@ -554,19 +549,6 @@ pub impl mem_categorization_ctxt { } } - fn cat_variant(&self, - arg: N, - enum_did: ast::def_id, - cmt: cmt) -> cmt { - @cmt_ { - id: arg.id(), - span: arg.span(), - cat: cat_interior(cmt, interior_variant(enum_did)), - mutbl: cmt.mutbl.inherit(), - ty: self.tcx.ty(arg) - } - } - fn cat_rvalue(&self, elt: N, expr_ty: ty::t) -> cmt { @cmt_ { id:elt.id(), @@ -598,6 +580,7 @@ pub impl mem_categorization_ctxt { node: N, base_cmt: cmt, f_name: ast::ident, + f_ty: ty::t, field_id: ast::node_id) -> cmt { let f_mutbl = match field_mutbl(self.tcx, base_cmt.ty, f_name, field_id) { @@ -617,7 +600,7 @@ pub impl mem_categorization_ctxt { span: node.span(), cat: cat_interior(base_cmt, f_interior), mutbl: m, - ty: self.tcx.ty(node) + ty: f_ty } } @@ -697,8 +680,8 @@ pub impl mem_categorization_ctxt { } fn cat_index(&self, - elt: N, - base_cmt: cmt) -> cmt { + elt: N, + base_cmt: cmt) -> cmt { let mt = match ty::index(base_cmt.ty) { Some(mt) => mt, None => { @@ -756,27 +739,17 @@ pub impl mem_categorization_ctxt { } } - fn cat_tuple_elt(&self, - elt: N, - cmt: cmt) -> cmt { - @cmt_ { - id: elt.id(), - span: elt.span(), - cat: cat_interior(cmt, interior_tuple), - mutbl: cmt.mutbl.inherit(), - ty: self.tcx.ty(elt) - } - } - - fn cat_anon_struct_field(&self, - elt: N, - cmt: cmt) -> cmt { + fn cat_imm_interior(&self, + node: N, + base_cmt: cmt, + interior_ty: ty::t, + interior: interior_kind) -> cmt { @cmt_ { - id: elt.id(), - span: elt.span(), - cat: cat_interior(cmt, interior_anon_field), - mutbl: cmt.mutbl.inherit(), - ty: self.tcx.ty(elt) + id: node.id(), + span: node.span(), + cat: cat_interior(base_cmt, interior), + mutbl: base_cmt.mutbl.inherit(), + ty: interior_ty } } @@ -797,27 +770,37 @@ pub impl mem_categorization_ctxt { // we can be sure that the binding will remain valid for the // duration of the arm. // - // The correspondence between the id in the cmt and which - // pattern is being referred to is somewhat...subtle. In - // general, the id of the cmt is the id of the node that - // produces the value. For patterns, that's actually the - // *subpattern*, generally speaking. + // (*) There is subtlety concerning the correspondence between + // pattern ids and types as compared to *expression* ids and + // types. This is explained briefly. on the definition of the + // type `cmt`, so go off and read what it says there, then + // come back and I'll dive into a bit more detail here. :) OK, + // back? // - // To see what I mean about ids etc, consider: + // In general, the id of the cmt should be the node that + // "produces" the value---patterns aren't executable code + // exactly, but I consider them to "execute" when they match a + // value. So if you have something like: // // let x = @@3; // match x { // @@y { ... } // } // - // Here the cmt for `y` would be something like + // In this case, the cmt and the relevant ids would be: + // + // CMT Id Type of Id Type of cmt // // local(x)->@->@ + // ^~~~~~~^ `x` from discr @@int @@int + // ^~~~~~~~~~^ `@@y` pattern node @@int @int + // ^~~~~~~~~~~~~^ `@y` pattern node @int int // - // where the id of `local(x)` is the id of the `x` that appears - // in the match, the id of `local(x)->@` is the `@y` pattern, - // and the id of `local(x)->@->@` is the id of the `y` pattern. - + // You can see that the types of the id and the cmt are in + // sync in the first line, because that id is actually the id + // of an expression. But once we get to pattern ids, the types + // step out of sync again. So you'll see below that we always + // get the type of the *subpattern* and use that. let tcx = self.tcx; debug!("cat_pattern: id=%d pat=%s cmt=%s", @@ -839,22 +822,27 @@ pub impl mem_categorization_ctxt { match self.tcx.def_map.find(&pat.id) { Some(&ast::def_variant(enum_did, _)) => { // variant(x, y, z) - for subpats.each |subpat| { - let subcmt = self.cat_variant(*subpat, enum_did, cmt); - self.cat_pattern(subcmt, *subpat, op); + for subpats.each |&subpat| { + let subpat_ty = self.pat_ty(subpat); // see (*) + let subcmt = + self.cat_imm_interior(pat, cmt, subpat_ty, + interior_variant(enum_did)); + self.cat_pattern(subcmt, subpat, op); } } Some(&ast::def_fn(*)) | Some(&ast::def_struct(*)) => { - for subpats.each |subpat| { - let cmt_field = self.cat_anon_struct_field(*subpat, - cmt); - self.cat_pattern(cmt_field, *subpat, op); + for subpats.each |&subpat| { + let subpat_ty = self.pat_ty(subpat); // see (*) + let cmt_field = + self.cat_imm_interior(pat, cmt, subpat_ty, + interior_anon_field); + self.cat_pattern(cmt_field, subpat, op); } } Some(&ast::def_const(*)) => { - for subpats.each |subpat| { - self.cat_pattern(cmt, *subpat, op); + for subpats.each |&subpat| { + self.cat_pattern(cmt, subpat, op); } } _ => { @@ -876,39 +864,43 @@ pub impl mem_categorization_ctxt { ast::pat_struct(_, ref field_pats, _) => { // {f1: p1, ..., fN: pN} for field_pats.each |fp| { - let cmt_field = self.cat_field(fp.pat, cmt, fp.ident, pat.id); + let field_ty = self.pat_ty(fp.pat); // see (*) + let cmt_field = self.cat_field(pat, cmt, fp.ident, + field_ty, pat.id); self.cat_pattern(cmt_field, fp.pat, op); } } ast::pat_tup(ref subpats) => { // (p1, ..., pN) - for subpats.each |subpat| { - let subcmt = self.cat_tuple_elt(*subpat, cmt); - self.cat_pattern(subcmt, *subpat, op); + for subpats.each |&subpat| { + let subpat_ty = self.pat_ty(subpat); // see (*) + let subcmt = self.cat_imm_interior(pat, cmt, subpat_ty, + interior_tuple); + self.cat_pattern(subcmt, subpat, op); } } ast::pat_box(subpat) | ast::pat_uniq(subpat) | ast::pat_region(subpat) => { // @p1, ~p1 - let subcmt = self.cat_deref(subpat, cmt, 0); + let subcmt = self.cat_deref(pat, cmt, 0); self.cat_pattern(subcmt, subpat, op); } ast::pat_vec(ref before, slice, ref after) => { - for before.each |pat| { - let elt_cmt = self.cat_index(*pat, cmt); - self.cat_pattern(elt_cmt, *pat, op); + for before.each |&before_pat| { + let elt_cmt = self.cat_index(pat, cmt); + self.cat_pattern(elt_cmt, before_pat, op); } - for slice.each |slice_pat| { - let slice_ty = self.tcx.ty(*slice_pat); - let slice_cmt = self.cat_rvalue(*slice_pat, slice_ty); - self.cat_pattern(slice_cmt, *slice_pat, op); + for slice.each |&slice_pat| { + let slice_ty = self.pat_ty(slice_pat); + let slice_cmt = self.cat_rvalue(pat, slice_ty); + self.cat_pattern(slice_cmt, slice_pat, op); } - for after.each |pat| { - let elt_cmt = self.cat_index(*pat, cmt); - self.cat_pattern(elt_cmt, *pat, op); + for after.each |&after_pat| { + let elt_cmt = self.cat_index(pat, cmt); + self.cat_pattern(elt_cmt, after_pat, op); } } @@ -1145,4 +1137,3 @@ impl Repr for interior_kind { } } } - diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index be39edd2d9b78..80e34ca481426 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -947,6 +947,17 @@ pub fn collect_record_or_struct_fields(bcx: block, } } +pub fn pats_require_rooting(bcx: block, + m: &[@Match], + col: uint) + -> bool { + vec::any(m, |br| { + let pat_id = br.pats[col].id; + let key = root_map_key {id: pat_id, derefs: 0u }; + bcx.ccx().maps.root_map.contains_key(&key) + }) +} + pub fn root_pats_as_necessary(bcx: block, m: &[@Match], col: uint, @@ -1303,7 +1314,10 @@ pub fn compile_submatch(bcx: block, if pat_id == 0 { pat_id = br.pats[col].id; } } - bcx = root_pats_as_necessary(bcx, m, col, val); + // If we are not matching against an `@T`, we should not be + // required to root any values. + assert!(any_box_pat(m, col) || !pats_require_rooting(bcx, m, col)); + let rec_fields = collect_record_or_struct_fields(bcx, m, col); if rec_fields.len() > 0 { let pat_ty = node_id_type(bcx, pat_id); @@ -1364,6 +1378,7 @@ pub fn compile_submatch(bcx: block, // Unbox in case of a box field if any_box_pat(m, col) { + bcx = root_pats_as_necessary(bcx, m, col, val); let llbox = Load(bcx, val); let box_no_addrspace = non_gc_box_cast(bcx, llbox); let unboxed = diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index af7165c53a7c2..095798ae21272 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -675,7 +675,7 @@ pub impl Datum { fn try_deref(&self, bcx: block, // block wherein to generate insn's span: span, // location where deref occurs - expr_id: ast::node_id, // id of expr being deref'd + expr_id: ast::node_id, // id of deref expr derefs: uint, // number of times deref'd already is_auto: bool) // if true, only deref if auto-derefable -> (Option, block) @@ -810,7 +810,7 @@ pub impl Datum { } fn deref(&self, bcx: block, - expr: @ast::expr, // the expression whose value is being deref'd + expr: @ast::expr, // the deref expression derefs: uint) -> DatumBlock { match self.try_deref(bcx, expr.span, expr.id, derefs, false) { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index ff493c46a176a..1a9824dcfe8a1 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -835,7 +835,7 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { } ast::expr_unary(ast::deref, base) => { let basedatum = unpack_datum!(bcx, trans_to_datum(bcx, base)); - basedatum.deref(bcx, base, 0) + basedatum.deref(bcx, expr, 0) } _ => { bcx.tcx().sess.span_bug( From 4dd0fa68766e84499bd1680043b38a34a9fc7606 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 3 May 2013 18:53:47 +0200 Subject: [PATCH 171/215] Make build products depend on their target directories. This is an attempt to address Issue #3326 by adding [*order-only*][1] prerequsites of each build product on the directory where it is to go. It is important that the prerequisites be order-only, since the timestamp on a parent directory is not relevant to whether a product is out of date; the parent directory merely needs to exist. (This use case of generating target directories was provided as an [example][2] of how order-only prequisites are used.) [1]: http://www.gnu.org/software/make/manual/html_node/Prerequisite-Types.html [2]: http://www.kolpackov.net/pipermail/notes/2004-January/000001.html --- mk/host.mk | 35 +++++++++++++++++++++++++---------- mk/target.mk | 29 ++++++++++++++++++++--------- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/mk/host.mk b/mk/host.mk index 13a8a5401172a..54e7e7ca09609 100644 --- a/mk/host.mk +++ b/mk/host.mk @@ -29,7 +29,9 @@ $$(HBIN$(2)_H_$(4))/rustc$$(X_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)) \ $$(HCORELIB_DEFAULT$(2)_H_$(4)) \ - $$(HSTDLIB_DEFAULT$(2)_H_$(4)) + $$(HSTDLIB_DEFAULT$(2)_H_$(4)) \ + | $$(HBIN$(2)_H_$(4))/ + @$$(call E, cp: $$@) $$(Q)cp $$< $$@ @@ -39,7 +41,9 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \ $$(HCORELIB_DEFAULT$(2)_H_$(4)) \ - $$(HSTDLIB_DEFAULT$(2)_H_$(4)) + $$(HSTDLIB_DEFAULT$(2)_H_$(4)) \ + | $$(HBIN$(2)_H_$(4))/ + @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBRUSTC_GLOB_$(4)) \ @@ -51,7 +55,8 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \ $$(HCORELIB_DEFAULT$(2)_H_$(4)) \ - $$(HSTDLIB_DEFAULT$(2)_H_$(4)) + $$(HSTDLIB_DEFAULT$(2)_H_$(4)) \ + | $$(HBIN$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBSYNTAX_GLOB_$(4)) \ @@ -59,13 +64,15 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)): \ $$(HLIB$(2)_H_$(4)) $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)): \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUNTIME_$(4)) + $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUNTIME_$(4)) \ + | $$(HBIN$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)): \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_CORELIB_$(4)) \ - $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) + $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \ + | $$(HBIN$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ # Subtle: We do not let the shell expand $(CORELIB_DSYM_GLOB) directly rather @@ -82,7 +89,8 @@ $$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \ $$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)) \ - $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) + $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \ + | $$(HBIN$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_GLOB_$(4)) \ @@ -91,14 +99,16 @@ $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \ $$(HLIB$(2)_H_$(4))/libcore.rlib: \ $$(TLIB$(1)_T_$(4)_H_$(3))/libcore.rlib \ - $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) + $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \ + | $$(HBIN$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(HLIB$(2)_H_$(4))/libstd.rlib: \ $$(TLIB$(1)_T_$(4)_H_$(3))/libstd.rlib \ $$(HLIB$(2)_H_$(4))/libcore.rlib \ - $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) + $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \ + | $$(HBIN$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ @@ -106,15 +116,20 @@ $$(HLIB$(2)_H_$(4))/librustc.rlib: \ $$(TLIB$(1)_T_$(4)_H_$(3))/librustc.rlib \ $$(HLIB$(2)_H_$(4))/libcore.rlib \ $$(HLIB$(2)_H_$(4))/libstd.rlib \ - $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) + $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \ + | $$(HBIN$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)): \ - $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUSTLLVM_$(4)) + $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUSTLLVM_$(4)) \ + | $$(HBIN$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ +$$(HBIN$(2)_H_$(4))/: + mkdir -p $@ + endef $(foreach t,$(CFG_HOST_TRIPLES), \ diff --git a/mk/target.mk b/mk/target.mk index fba1a6e0ee591..a3e5a5caff107 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -18,25 +18,29 @@ define TARGET_STAGE_N $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a: \ - rt/$(2)/arch/$$(HOST_$(2))/libmorestack.a + rt/$(2)/arch/$$(HOST_$(2))/libmorestack.a \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUNTIME_$(2)): \ - rt/$(2)/$(CFG_RUNTIME_$(2)) + rt/$(2)/$(CFG_RUNTIME_$(2)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB_$(2)): \ $$(CORELIB_CRATE) $$(CORELIB_INPUTS) \ - $$(TSREQ$(1)_T_$(2)_H_$(3)) + $$(TSREQ$(1)_T_$(2)_H_$(3)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_STDLIB_$(2)): \ $$(STDLIB_CRATE) $$(STDLIB_INPUTS) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_CORELIB_$(2)) \ - $$(TSREQ$(1)_T_$(2)_H_$(3)) + $$(TSREQ$(1)_T_$(2)_H_$(3)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@ @@ -44,7 +48,8 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \ $$(LIBSYNTAX_CRATE) $$(LIBSYNTAX_INPUTS) \ $$(TSREQ$(1)_T_$(2)_H_$(3)) \ $$(TCORELIB_DEFAULT$(1)_T_$(2)_H_$(3)) \ - $$(TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3)) + $$(TSTDLIB_DEFAULT$(1)_T_$(2)_H_$(3)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) $(BORROWCK) -o $$@ $$< && touch $$@ @@ -52,20 +57,23 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)): \ ifneq ($$(findstring $(2),$$(CFG_HOST_TRIPLES)),) $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)): \ - rustllvm/$(2)/$(CFG_RUSTLLVM_$(3)) + rustllvm/$(2)/$(CFG_RUSTLLVM_$(3)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): \ $$(COMPILER_CRATE) $$(COMPILER_INPUTS) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBSYNTAX_$(3)) \ - $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)) + $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_RUSTLLVM_$(3)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) -o $$@ $$< && touch $$@ $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)): \ - $$(DRIVER_CRATE) \ - $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)) + $$(DRIVER_CRATE) \ + $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)) \ + | $$(TLIB$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) --cfg rustc -o $$@ $$< ifdef CFG_ENABLE_PAX_FLAGS @@ -75,6 +83,9 @@ endif endif +$$(TLIB$(1)_T_$(2)_H_$(3))/: + mkdir -p $@ + endef # In principle, each host can build each target: From f3a6ea26437e240b02d749331b3a2d60aab0588b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 3 May 2013 15:12:04 -0400 Subject: [PATCH 172/215] lang: um, actually set locking bits! this code got lost. --- src/libcore/unstable/lang.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 27fc3287bdb39..01ab2345918b1 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -235,6 +235,8 @@ pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { fail_borrowed(a, file, line); } + (*a).header.ref_count = ref_count | FROZEN_BIT; + ref_count } @@ -251,6 +253,9 @@ pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint { if (ref_count & (MUT_BIT|FROZEN_BIT)) != 0 { fail_borrowed(a, file, line); } + + (*a).header.ref_count = ref_count | MUT_BIT | FROZEN_BIT; + ref_count } @@ -349,7 +354,12 @@ pub unsafe fn check_not_borrowed(a: *u8, file: *c_char, line: size_t) { let a: *mut BoxRepr = transmute(a); - if ((*a).header.ref_count & FROZEN_BIT) != 0 { + let ref_count = (*a).header.ref_count; + debug_ptr("check_not_borrowed (ptr) : ", a); + debug_ptr(" (line): ", line as *()); + debug_ptr(" (rc) : ", ref_count as *()); + + if (ref_count & FROZEN_BIT) != 0 { fail_borrowed(a, file, line); } } From 832f7b758f28d36030df27c888ef9248ba584859 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Thu, 2 May 2013 14:12:47 -0700 Subject: [PATCH 173/215] librustc: Add argument to allow choosing "linker" --- src/librustc/back/link.rs | 28 ++++++++++++++++++---------- src/librustc/driver/driver.rs | 4 +++- src/librustc/driver/session.rs | 4 +++- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index 87e08a73fcb1c..de6469e81807d 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -752,18 +752,26 @@ pub fn link_binary(sess: Session, // instead of hard-coded gcc. // For win32, there is no cc command, // so we add a condition to make it use gcc. - let cc_prog: ~str = if sess.targ_cfg.os == session::os_android { - match &sess.opts.android_cross_path { - &Some(copy path) => { - fmt!("%s/bin/arm-linux-androideabi-gcc", path) - } - &None => { - sess.fatal(~"need Android NDK path for linking \ - (--android-cross-path)") + let cc_prog: ~str = match sess.opts.linker { + Some(copy linker) => linker, + None => { + if sess.targ_cfg.os == session::os_android { + match &sess.opts.android_cross_path { + &Some(copy path) => { + fmt!("%s/bin/arm-linux-androideabi-gcc", path) + } + &None => { + sess.fatal(~"need Android NDK path for linking \ + (--android-cross-path)") + } + } + } else if sess.targ_cfg.os == session::os_win32 { + ~"gcc" + } else { + ~"cc" } } - } else if sess.targ_cfg.os == session::os_win32 { ~"gcc" } - else { ~"cc" }; + }; // The invocations of cc share some flags across platforms diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 5e5d0640d808e..02940ea9905ba 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -650,7 +650,7 @@ pub fn build_session_options(binary: @~str, }; let addl_lib_search_paths = getopts::opt_strs(matches, ~"L").map(|s| Path(*s)); - + let linker = getopts::opt_maybe_str(matches, ~"linker"); let linker_args = getopts::opt_strs(matches, ~"link-args").flat_map( |a| { let mut args = ~[]; for str::each_split_char(*a, ' ') |arg| { @@ -676,6 +676,7 @@ pub fn build_session_options(binary: @~str, jit: jit, output_type: output_type, addl_lib_search_paths: addl_lib_search_paths, + linker: linker, linker_args: linker_args, maybe_sysroot: sysroot_opt, target_triple: target, @@ -760,6 +761,7 @@ pub fn optgroups() -> ~[getopts::groups::OptGroup] { optmulti("L", "", "Add a directory to the library search path", "PATH"), optflag("", "lib", "Compile a library crate"), + optopt("", "linker", "Program to use for linking instead of the default.", "LINKER"), optmulti("", "link-args", "FLAGS is a space-separated list of flags passed to the linker", "FLAGS"), optflag("", "ls", "List the symbols defined by a library crate"), diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 237b03bc20fb3..29cb5a71f3165 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -124,6 +124,7 @@ pub struct options { jit: bool, output_type: back::link::output_type, addl_lib_search_paths: ~[Path], + linker: Option<~str>, linker_args: ~[~str], maybe_sysroot: Option, target_triple: ~str, @@ -302,7 +303,8 @@ pub fn basic_options() -> @options { jit: false, output_type: link::output_type_exe, addl_lib_search_paths: ~[], - linker_args:~[], + linker: None, + linker_args: ~[], maybe_sysroot: None, target_triple: host_triple(), target_feature: ~"", From 13df2ea69c332d7a20c7ab394020430a09dad507 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Thu, 2 May 2013 15:38:19 -0700 Subject: [PATCH 174/215] rustc: Handle struct patterns where the expected type is an enum Previously, rustc would ICE if you matched on an enum-typed thing with a structure pattern. Error out correctly. --- src/librustc/middle/typeck/check/_match.rs | 78 +++++++++++++--------- src/libsyntax/ast_util.rs | 6 +- src/test/compile-fail/issue-5358-1.rs | 18 +++++ src/test/compile-fail/issue-5358.rs | 17 +++++ 4 files changed, 85 insertions(+), 34 deletions(-) create mode 100644 src/test/compile-fail/issue-5358-1.rs create mode 100644 src/test/compile-fail/issue-5358.rs diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index de384d02dc3bc..3937e54853efa 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -114,37 +114,53 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, ty::ty_enum(_, ref expected_substs) => { // Lookup the enum and variant def ids: let v_def = lookup_def(pcx.fcx, pat.span, pat.id); - let (enm, var) = ast_util::variant_def_ids(v_def); - - // Assign the pattern the type of the *enum*, not the variant. - let enum_tpt = ty::lookup_item_type(tcx, enm); - instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id, - pcx.block_region); - - // check that the type of the value being matched is a subtype - // of the type of the pattern: - let pat_ty = fcx.node_ty(pat.id); - demand::subtype(fcx, pat.span, expected, pat_ty); - - // Get the expected types of the arguments. - arg_types = { - let vinfo = - ty::enum_variant_with_id(tcx, enm, var); - let var_tpt = ty::lookup_item_type(tcx, var); - vinfo.args.map(|t| { - if var_tpt.generics.type_param_defs.len() == - expected_substs.tps.len() - { - ty::subst(tcx, expected_substs, *t) - } - else { - *t // In this case, an error was already signaled - // anyway - } - }) - }; - - kind_name = "variant"; + match ast_util::variant_def_ids(v_def) { + Some((enm, var)) => { + // Assign the pattern the type of the *enum*, not the variant. + let enum_tpt = ty::lookup_item_type(tcx, enm); + instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id, + pcx.block_region); + + // check that the type of the value being matched is a subtype + // of the type of the pattern: + let pat_ty = fcx.node_ty(pat.id); + demand::subtype(fcx, pat.span, expected, pat_ty); + + // Get the expected types of the arguments. + arg_types = { + let vinfo = + ty::enum_variant_with_id(tcx, enm, var); + let var_tpt = ty::lookup_item_type(tcx, var); + vinfo.args.map(|t| { + if var_tpt.generics.type_param_defs.len() == + expected_substs.tps.len() + { + ty::subst(tcx, expected_substs, *t) + } + else { + *t // In this case, an error was already signaled + // anyway + } + }) + }; + + kind_name = "variant"; + } + None => { + let resolved_expected = + fcx.infcx().ty_to_str(fcx.infcx().resolve_type_vars_if_possible(expected)); + fcx.infcx().type_error_message_str(pat.span, + |actual| { + fmt!("mismatched types: expected `%s` but found %s", + resolved_expected, actual)}, + ~"a structure pattern", + None); + fcx.write_error(pat.id); + kind_name = "[error]"; + arg_types = (copy subpats).get_or_default(~[]).map(|_| + ty::mk_err()); + } + } } ty::ty_struct(struct_def_id, ref expected_substs) => { // Lookup the struct ctor def id diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 47ef7227842e2..10350413f2d68 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -41,12 +41,12 @@ pub fn stmt_id(s: &stmt) -> node_id { } } -pub fn variant_def_ids(d: def) -> (def_id, def_id) { +pub fn variant_def_ids(d: def) -> Option<(def_id, def_id)> { match d { def_variant(enum_id, var_id) => { - return (enum_id, var_id); + Some((enum_id, var_id)) } - _ => fail!(~"non-variant in variant_def_ids") + _ => None } } diff --git a/src/test/compile-fail/issue-5358-1.rs b/src/test/compile-fail/issue-5358-1.rs new file mode 100644 index 0000000000000..0b6e2fb0ff5f2 --- /dev/null +++ b/src/test/compile-fail/issue-5358-1.rs @@ -0,0 +1,18 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S(Either); + +fn main() { + match S(Left(5)) { + Right(_) => {} //~ ERROR mismatched types: expected `S` but found `core::either::Either + _ => {} + } +} diff --git a/src/test/compile-fail/issue-5358.rs b/src/test/compile-fail/issue-5358.rs new file mode 100644 index 0000000000000..7d11a127f9ae8 --- /dev/null +++ b/src/test/compile-fail/issue-5358.rs @@ -0,0 +1,17 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct S(Either); + +fn main() { + match *S(Left(5)) { + S(_) => {} //~ ERROR mismatched types: expected `core::either::Either` but found a structure pattern + } +} From 32b3d3e9ebd8dbc1073445b3be9676da85b6410c Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 3 May 2013 13:03:01 -0700 Subject: [PATCH 175/215] tidy --- src/librustc/middle/typeck/check/_match.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 3937e54853efa..a139a26a597fc 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -120,12 +120,12 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, let enum_tpt = ty::lookup_item_type(tcx, enm); instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id, pcx.block_region); - + // check that the type of the value being matched is a subtype // of the type of the pattern: let pat_ty = fcx.node_ty(pat.id); demand::subtype(fcx, pat.span, expected, pat_ty); - + // Get the expected types of the arguments. arg_types = { let vinfo = @@ -143,7 +143,7 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, } }) }; - + kind_name = "variant"; } None => { @@ -151,10 +151,10 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: @ast::Path, fcx.infcx().ty_to_str(fcx.infcx().resolve_type_vars_if_possible(expected)); fcx.infcx().type_error_message_str(pat.span, |actual| { - fmt!("mismatched types: expected `%s` but found %s", - resolved_expected, actual)}, - ~"a structure pattern", - None); + fmt!("mismatched types: expected `%s` but found %s", + resolved_expected, actual)}, + ~"a structure pattern", + None); fcx.write_error(pat.id); kind_name = "[error]"; arg_types = (copy subpats).get_or_default(~[]).map(|_| From c15fa3a02aa3e7e5111f0410abf7321387a7a97f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 29 Apr 2013 15:11:16 -0400 Subject: [PATCH 176/215] Be more careful about the order in which we read the next field during task annihilation, since it is easy to tread on freed memory. --- src/libcore/cleanup.rs | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/libcore/cleanup.rs b/src/libcore/cleanup.rs index a07c6b4811b6c..aca49c9464477 100644 --- a/src/libcore/cleanup.rs +++ b/src/libcore/cleanup.rs @@ -126,14 +126,17 @@ struct AnnihilateStats { n_bytes_freed: uint } -unsafe fn each_live_alloc(f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) { +unsafe fn each_live_alloc(read_next_before: bool, + f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) { + //! Walks the internal list of allocations + use managed; let task: *Task = transmute(rustrt::rust_get_task()); let box = (*task).boxed_region.live_allocs; let mut box: *mut BoxRepr = transmute(copy box); while box != mut_null() { - let next = transmute(copy (*box).header.next); + let next_before = transmute(copy (*box).header.next); let uniq = (*box).header.ref_count == managed::raw::RC_MANAGED_UNIQUE; @@ -141,7 +144,11 @@ unsafe fn each_live_alloc(f: &fn(box: *mut BoxRepr, uniq: bool) -> bool) { break } - box = next + if read_next_before { + box = next_before; + } else { + box = transmute(copy (*box).header.next); + } } } @@ -173,7 +180,10 @@ pub unsafe fn annihilate() { }; // Pass 1: Make all boxes immortal. - for each_live_alloc |box, uniq| { + // + // In this pass, nothing gets freed, so it does not matter whether + // we read the next field before or after the callback. + for each_live_alloc(true) |box, uniq| { stats.n_total_boxes += 1; if uniq { stats.n_unique_boxes += 1; @@ -183,7 +193,11 @@ pub unsafe fn annihilate() { } // Pass 2: Drop all boxes. - for each_live_alloc |box, uniq| { + // + // In this pass, unique-managed boxes may get freed, but not + // managed boxes, so we must read the `next` field *after* the + // callback, as the original value may have been freed. + for each_live_alloc(false) |box, uniq| { if !uniq { let tydesc: *TypeDesc = transmute(copy (*box).header.type_desc); let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0)); @@ -192,7 +206,12 @@ pub unsafe fn annihilate() { } // Pass 3: Free all boxes. - for each_live_alloc |box, uniq| { + // + // In this pass, managed boxes may get freed (but not + // unique-managed boxes, though I think that none of those are + // left), so we must read the `next` field before, since it will + // not be valid after. + for each_live_alloc(true) |box, uniq| { if !uniq { stats.n_bytes_freed += (*((*box).header.type_desc)).size From be08c3e5146953619ff777aaa422152dfee4ad28 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 3 May 2013 16:26:43 -0400 Subject: [PATCH 177/215] rustc: add rooting, write-guards to slices etc --- src/librustc/middle/trans/_match.rs | 25 +++++-- src/librustc/middle/trans/controlflow.rs | 2 +- src/librustc/middle/trans/datum.rs | 70 ++++++++++++++----- src/librustc/middle/trans/expr.rs | 19 +++-- src/test/run-fail/borrowck-wg-fail-2.rs | 3 + src/test/run-fail/borrowck-wg-fail-3.rs | 3 + src/test/run-fail/borrowck-wg-fail.rs | 3 + ...orrowck-wg-one-mut-one-imm-slice-method.rs | 37 ++++++++++ .../borrowck-wg-one-mut-one-imm-slices.rs | 16 +++++ .../run-fail/borrowck-wg-one-mut-one-imm.rs | 17 +++++ .../run-fail/borrowck-wg-two-array-indices.rs | 17 +++++ .../run-pass/borrowck-wg-two-imm-borrows.rs | 14 ++++ 12 files changed, 194 insertions(+), 32 deletions(-) create mode 100644 src/test/run-fail/borrowck-wg-one-mut-one-imm-slice-method.rs create mode 100644 src/test/run-fail/borrowck-wg-one-mut-one-imm-slices.rs create mode 100644 src/test/run-fail/borrowck-wg-one-mut-one-imm.rs create mode 100644 src/test/run-fail/borrowck-wg-two-array-indices.rs create mode 100644 src/test/run-pass/borrowck-wg-two-imm-borrows.rs diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 80e34ca481426..3b1cdf0ba47f7 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -866,7 +866,18 @@ pub fn extract_variant_args(bcx: block, ExtractedBlock { vals: args, bcx: bcx } } +fn match_datum(bcx: block, val: ValueRef, pat_id: ast::node_id) -> Datum { + //! Helper for converting from the ValueRef that we pass around in + //! the match code, which is always by ref, into a Datum. Eventually + //! we should just pass around a Datum and be done with it. + + let ty = node_id_type(bcx, pat_id); + Datum {val: val, ty: ty, mode: datum::ByRef, source: RevokeClean} +} + + pub fn extract_vec_elems(bcx: block, + pat_span: span, pat_id: ast::node_id, elem_count: uint, slice: Option, @@ -874,9 +885,9 @@ pub fn extract_vec_elems(bcx: block, count: ValueRef) -> ExtractedBlock { let _icx = bcx.insn_ctxt("match::extract_vec_elems"); + let vec_datum = match_datum(bcx, val, pat_id); + let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span, pat_id); let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id)); - let unboxed = load_if_immediate(bcx, val, vt.vec_ty); - let (base, len) = tvec::get_base_and_len(bcx, unboxed, vt.vec_ty); let mut elems = do vec::from_fn(elem_count) |i| { match slice { @@ -1308,10 +1319,14 @@ pub fn compile_submatch(bcx: block, vec::slice(vals, col + 1u, vals.len())); let ccx = *bcx.fcx.ccx; let mut pat_id = 0; + let mut pat_span = dummy_sp(); for vec::each(m) |br| { // Find a real id (we're adding placeholder wildcard patterns, but // each column is guaranteed to have at least one real pattern) - if pat_id == 0 { pat_id = br.pats[col].id; } + if pat_id == 0 { + pat_id = br.pats[col].id; + pat_span = br.pats[col].span; + } } // If we are not matching against an `@T`, we should not be @@ -1579,8 +1594,8 @@ pub fn compile_submatch(bcx: block, vec_len_ge(_, i) => Some(i), _ => None }; - let args = extract_vec_elems(opt_cx, pat_id, n, slice, - val, test_val); + let args = extract_vec_elems(opt_cx, pat_span, pat_id, n, slice, + val, test_val); size = args.vals.len(); unpacked = /*bad*/copy args.vals; opt_cx = args.bcx; diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 60b6cf9e23f79..c8699cc6371bc 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -333,7 +333,7 @@ pub fn trans_fail_expr(bcx: block, bcx, expr::trans_to_datum(bcx, arg_expr)); if ty::type_is_str(arg_datum.ty) { - let (lldata, _lllen) = arg_datum.get_base_and_len(bcx); + let (lldata, _) = arg_datum.get_vec_base_and_len_no_root(bcx); return trans_fail_value(bcx, sp_opt, lldata); } else if bcx.unreachable || ty::type_is_bot(arg_datum.ty) { return bcx; diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 095798ae21272..6ffe504b804fb 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -603,6 +603,8 @@ pub impl Datum { } fn perform_write_guard(&self, bcx: block, span: span) -> block { + debug!("perform_write_guard"); + // Create scratch space, but do not root it. let llval = match self.mode { ByValue => self.val, @@ -682,25 +684,10 @@ pub impl Datum { { let ccx = bcx.ccx(); - debug!("try_deref(expr_id=%d, derefs=%?, is_auto=%b, self=%?)", + debug!("try_deref(expr_id=%?, derefs=%?, is_auto=%b, self=%?)", expr_id, derefs, is_auto, self.to_str(bcx.ccx())); - let _indenter = indenter(); - - // root the autoderef'd value, if necessary: - // - // (Note: root'd values are always boxes) - let key = root_map_key { id: expr_id, derefs: derefs }; - let bcx = match ccx.maps.root_map.find(&key) { - None => bcx, - Some(&root_info) => self.root(bcx, span, key, root_info) - }; - // Perform the write guard, if necessary. - // - // (Note: write-guarded values are always boxes) - let bcx = if ccx.maps.write_guard_map.contains(&key) { - self.perform_write_guard(bcx, span) - } else { bcx }; + let bcx = self.root_and_write_guard(bcx, span, expr_id, derefs); match ty::get(self.ty).sty { ty::ty_box(_) | ty::ty_uniq(_) => { @@ -854,8 +841,53 @@ pub impl Datum { DatumBlock { bcx: bcx, datum: datum } } - fn get_base_and_len(&self, bcx: block) -> (ValueRef, ValueRef) { - tvec::get_base_and_len(bcx, self.to_appropriate_llval(bcx), self.ty) + fn root_and_write_guard(&self, + mut bcx: block, + span: span, + expr_id: ast::node_id, + derefs: uint) -> block { + let key = root_map_key { id: expr_id, derefs: derefs }; + debug!("root_and_write_guard(key=%?)", key); + + // root the autoderef'd value, if necessary: + // + // (Note: root'd values are always boxes) + let ccx = bcx.ccx(); + bcx = match ccx.maps.root_map.find(&key) { + None => bcx, + Some(&root_info) => self.root(bcx, span, key, root_info) + }; + + // Perform the write guard, if necessary. + // + // (Note: write-guarded values are always boxes) + if ccx.maps.write_guard_map.contains(&key) { + self.perform_write_guard(bcx, span) + } else { + bcx + } + } + + fn get_vec_base_and_len(&self, + mut bcx: block, + span: span, + expr_id: ast::node_id) + -> (block, ValueRef, ValueRef) { + //! Converts a vector into the slice pair. Performs rooting + //! and write guards checks. + + // only imp't for @[] and @str, but harmless + bcx = self.root_and_write_guard(bcx, span, expr_id, 0); + let (base, len) = self.get_vec_base_and_len_no_root(bcx); + (bcx, base, len) + } + + fn get_vec_base_and_len_no_root(&self, bcx: block) -> (ValueRef, ValueRef) { + //! Converts a vector into the slice pair. Des not root + //! nor perform write guard checks. + + let llval = self.to_appropriate_llval(bcx); + tvec::get_base_and_len(bcx, llval, self.ty) } fn to_result(&self, bcx: block) -> common::Result { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 1a9824dcfe8a1..b8cdfeb796db0 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -218,10 +218,10 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { unpack_datum!(bcx, auto_ref(bcx, datum)) } Some(AutoBorrowVec(*)) => { - unpack_datum!(bcx, auto_slice(bcx, datum)) + unpack_datum!(bcx, auto_slice(bcx, expr, datum)) } Some(AutoBorrowVecRef(*)) => { - unpack_datum!(bcx, auto_slice_and_ref(bcx, datum)) + unpack_datum!(bcx, auto_slice_and_ref(bcx, expr, datum)) } Some(AutoBorrowFn(*)) => { // currently, all closure types are @@ -241,7 +241,7 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { DatumBlock {bcx: bcx, datum: datum.to_rptr(bcx)} } - fn auto_slice(bcx: block, datum: Datum) -> DatumBlock { + fn auto_slice(bcx: block, expr: @ast::expr, datum: Datum) -> DatumBlock { // This is not the most efficient thing possible; since slices // are two words it'd be better if this were compiled in // 'dest' mode, but I can't find a nice way to structure the @@ -250,7 +250,9 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { let tcx = bcx.tcx(); let unit_ty = ty::sequence_element_type(tcx, datum.ty); - let (base, len) = datum.get_base_and_len(bcx); + // NOTE prob need to distinguish "auto-slice" from explicit index? + let (bcx, base, len) = + datum.get_vec_base_and_len(bcx, expr.span, expr.id); // this type may have a different region/mutability than the // real one, but it will have the same runtime representation @@ -283,8 +285,10 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { DatumBlock {bcx: bcx, datum: scratch} } - fn auto_slice_and_ref(bcx: block, datum: Datum) -> DatumBlock { - let DatumBlock { bcx, datum } = auto_slice(bcx, datum); + fn auto_slice_and_ref(bcx: block, + expr: @ast::expr, + datum: Datum) -> DatumBlock { + let DatumBlock { bcx, datum } = auto_slice(bcx, expr, datum); auto_ref(bcx, datum) } } @@ -903,7 +907,8 @@ fn trans_lvalue_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock { let scaled_ix = Mul(bcx, ix_val, vt.llunit_size); base::maybe_name_value(bcx.ccx(), scaled_ix, ~"scaled_ix"); - let mut (base, len) = base_datum.get_base_and_len(bcx); + let mut (bcx, base, len) = + base_datum.get_vec_base_and_len(bcx, index_expr.span, index_expr.id); if ty::type_is_str(base_ty) { // acccount for null terminator in the case of string diff --git a/src/test/run-fail/borrowck-wg-fail-2.rs b/src/test/run-fail/borrowck-wg-fail-2.rs index 121ec9c79216f..59a5fecd34003 100644 --- a/src/test/run-fail/borrowck-wg-fail-2.rs +++ b/src/test/run-fail/borrowck-wg-fail-2.rs @@ -1,5 +1,8 @@ // error-pattern:borrowed +// Test that write guards trigger when there is a write to a field +// of a frozen structure. + struct S { x: int } diff --git a/src/test/run-fail/borrowck-wg-fail-3.rs b/src/test/run-fail/borrowck-wg-fail-3.rs index 2b95cf3fe5fa9..ebff553aafbad 100644 --- a/src/test/run-fail/borrowck-wg-fail-3.rs +++ b/src/test/run-fail/borrowck-wg-fail-3.rs @@ -1,5 +1,8 @@ // error-pattern:borrowed +// Test that write guards trigger when there is a write to a directly +// frozen @mut box. + fn main() { let x = @mut 3; let y: &mut int = x; diff --git a/src/test/run-fail/borrowck-wg-fail.rs b/src/test/run-fail/borrowck-wg-fail.rs index fd2d36b895ada..939d802c21ca1 100644 --- a/src/test/run-fail/borrowck-wg-fail.rs +++ b/src/test/run-fail/borrowck-wg-fail.rs @@ -1,5 +1,8 @@ // error-pattern:borrowed +// Test that write guards trigger when mut box is frozen +// as part of argument coercion. + fn f(_x: &int, y: @mut int) { *y = 2; } diff --git a/src/test/run-fail/borrowck-wg-one-mut-one-imm-slice-method.rs b/src/test/run-fail/borrowck-wg-one-mut-one-imm-slice-method.rs new file mode 100644 index 0000000000000..91df90f8b3ac9 --- /dev/null +++ b/src/test/run-fail/borrowck-wg-one-mut-one-imm-slice-method.rs @@ -0,0 +1,37 @@ +// error-pattern:borrowed + +// Test that write guards trigger when there is a coercion to +// a slice on the receiver of a method. + +trait MyMutSlice { + fn my_mut_slice(self) -> Self; +} + +impl<'self, T> MyMutSlice for &'self mut [T] { + fn my_mut_slice(self) -> &'self mut [T] { + self + } +} + +trait MySlice { + fn my_slice(self) -> Self; +} + +impl<'self, T> MySlice for &'self [T] { + fn my_slice(self) -> &'self [T] { + self + } +} + +fn add(x:&mut [int], y:&[int]) +{ + x[0] = x[0] + y[0]; +} + +pub fn main() +{ + let z = @mut [1,2,3]; + let z2 = z; + add(z.my_mut_slice(), z2.my_slice()); + print(fmt!("%d\n", z[0])); +} diff --git a/src/test/run-fail/borrowck-wg-one-mut-one-imm-slices.rs b/src/test/run-fail/borrowck-wg-one-mut-one-imm-slices.rs new file mode 100644 index 0000000000000..bae693ce4eae2 --- /dev/null +++ b/src/test/run-fail/borrowck-wg-one-mut-one-imm-slices.rs @@ -0,0 +1,16 @@ +// error-pattern:borrowed + +// Test that write guards trigger when arguments are coerced to slices. + +fn add(x:&mut [int], y:&[int]) +{ + x[0] = x[0] + y[0]; +} + +pub fn main() +{ + let z = @mut [1,2,3]; + let z2 = z; + add(z, z2); + print(fmt!("%d\n", z[0])); +} diff --git a/src/test/run-fail/borrowck-wg-one-mut-one-imm.rs b/src/test/run-fail/borrowck-wg-one-mut-one-imm.rs new file mode 100644 index 0000000000000..9e2a02b32dfed --- /dev/null +++ b/src/test/run-fail/borrowck-wg-one-mut-one-imm.rs @@ -0,0 +1,17 @@ +// error-pattern:borrowed + +// Test that write guards trigger when we are indexing into +// an @mut vector. + +fn add(x:&mut int, y:&int) +{ + *x = *x + *y; +} + +pub fn main() +{ + let z = @mut [1,2,3]; + let z2 = z; + add(&mut z[0], &z2[0]); + print(fmt!("%d\n", z[0])); +} diff --git a/src/test/run-fail/borrowck-wg-two-array-indices.rs b/src/test/run-fail/borrowck-wg-two-array-indices.rs new file mode 100644 index 0000000000000..ad68448876028 --- /dev/null +++ b/src/test/run-fail/borrowck-wg-two-array-indices.rs @@ -0,0 +1,17 @@ +// error-pattern:borrowed + +// Test that arguments trigger when there are *two mutable* borrows +// of indices. + +fn add(x:&mut int, y:&mut int) +{ + *x = *x + *y; +} + +pub fn main() +{ + let z = @mut [1,2,3]; + let z2 = z; + add(&mut z[0], &mut z2[0]); + print(fmt!("%d\n", z[0])); +} diff --git a/src/test/run-pass/borrowck-wg-two-imm-borrows.rs b/src/test/run-pass/borrowck-wg-two-imm-borrows.rs new file mode 100644 index 0000000000000..20f824e969a48 --- /dev/null +++ b/src/test/run-pass/borrowck-wg-two-imm-borrows.rs @@ -0,0 +1,14 @@ +// Test that we can borrow the same @mut box twice, so long as both are imm. + +fn add(x:&int, y:&int) +{ + *x + *y; +} + +pub fn main() +{ + let z = @mut [1,2,3]; + let z2 = z; + add(&z[0], &z2[0]); + print(fmt!("%d\n", z[0])); +} From 4d4cabff9ede49ae3642b05c4cfb023a0a9222b2 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Thu, 2 May 2013 13:09:28 -0700 Subject: [PATCH 178/215] rustpkg: Implement install command The install command should work now, though it only installs in-place (anything else has to wait until I implement RUST_PATH). Also including: core: Add remove_directory_recursive, change copy_file Make copy_file preserve permissions, and add a remove_directory_recursive function. --- src/libcore/os.rs | 37 ++++++++++ src/librustpkg/conditions.rs | 10 ++- src/librustpkg/path_util.rs | 130 +++++++++++++++++++++++++++++++--- src/librustpkg/rustpkg.rc | 132 +++++++++++++++++++++-------------- src/librustpkg/tests.rs | 71 +++++++++++++------ src/librustpkg/util.rs | 7 +- src/libstd/tempfile.rs | 26 ++++++- 7 files changed, 328 insertions(+), 85 deletions(-) diff --git a/src/libcore/os.rs b/src/libcore/os.rs index c4b03d76cefec..7b68e6597a179 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -772,6 +772,28 @@ pub fn list_dir_path(p: &Path) -> ~[~Path] { list_dir(p).map(|f| ~p.push(*f)) } +/// Removes a directory at the specified path, after removing +/// all its contents. Use carefully! +pub fn remove_dir_recursive(p: &Path) -> bool { + let mut error_happened = false; + for walk_dir(p) |inner| { + if !error_happened { + if path_is_dir(inner) { + if !remove_dir_recursive(inner) { + error_happened = true; + } + } + else { + if !remove_file(inner) { + error_happened = true; + } + } + } + }; + // Directory should now be empty + !error_happened && remove_dir(p) +} + /// Removes a directory at the specified path pub fn remove_dir(p: &Path) -> bool { return rmdir(p); @@ -877,6 +899,10 @@ pub fn copy_file(from: &Path, to: &Path) -> bool { if istream as uint == 0u { return false; } + // Preserve permissions + let from_mode = from.get_mode().expect("copy_file: couldn't get permissions \ + for source file"); + let ostream = do as_c_charp(to.to_str()) |top| { do as_c_charp("w+b") |modebuf| { libc::fopen(top, modebuf) @@ -908,6 +934,15 @@ pub fn copy_file(from: &Path, to: &Path) -> bool { } fclose(istream); fclose(ostream); + + // Give the new file the old file's permissions + unsafe { + if do str::as_c_str(to.to_str()) |to_buf| { + libc::chmod(to_buf, from_mode as mode_t) + } != 0 { + return false; // should be a condition... + } + } return ok; } } @@ -1594,6 +1629,7 @@ mod tests { == buf.len() as size_t)) } assert!((libc::fclose(ostream) == (0u as c_int))); + let in_mode = in.get_mode(); let rs = os::copy_file(&in, &out); if (!os::path_exists(&in)) { fail!(fmt!("%s doesn't exist", in.to_str())); @@ -1601,6 +1637,7 @@ mod tests { assert!((rs)); let rslt = run::run_program(~"diff", ~[in.to_str(), out.to_str()]); assert!((rslt == 0)); + assert!(out.get_mode() == in_mode); assert!((remove_file(&in))); assert!((remove_file(&out))); } diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs index 35e70af7914c1..5b19a3bd66042 100644 --- a/src/librustpkg/conditions.rs +++ b/src/librustpkg/conditions.rs @@ -18,5 +18,13 @@ condition! { } condition! { - nonexistent_package: (super::PkgId, ~str) -> super::Path; + nonexistent_package: (super::PkgId, ~str) -> (); +} + +condition! { + copy_failed: (super::Path, super::Path) -> (); +} + +condition! { + missing_pkg_files: (super::PkgId) -> (); } diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 0490f066f0bea..161cb75e9e50e 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -12,6 +12,7 @@ use util::PkgId; use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; +use core::os::mkdir_recursive; #[deriving(Eq)] pub enum OutputType { Main, Lib, Bench, Test } @@ -23,7 +24,7 @@ pub fn rust_path() -> ~[Path] { ~[Path(".")] } -static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; +pub static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; /// Creates a directory that is readable, writeable, /// and executable by the user. Returns true iff creation @@ -70,34 +71,137 @@ pub fn pkgid_src_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { result.push(pkgid.path.to_str()) } +/// Figure out what the executable name for in 's build +/// directory is, and if the file exists, return it. +pub fn built_executable_in_workspace(pkgid: PkgId, workspace: &Path) -> Option { + let mut result = workspace.push("build"); + result = result.push_rel(&pkgid.path); + // should use a target-specific subdirectory + result = mk_output_path(Main, fmt!("%s-%s", pkgid.path.to_str(), pkgid.version.to_str()), + result); + debug!("built_executable_in_workspace: checking whether %s exists", + result.to_str()); + if os::path_exists(&result) { + Some(result) + } + else { + None + } +} + +/// Figure out what the library name for in 's build +/// directory is, and if the file exists, return it. +pub fn built_library_in_workspace(pkgid: PkgId, workspace: &Path) -> Option { + let mut result = workspace.push("build"); + result = result.push_rel(&pkgid.path); + // should use a target-specific subdirectory + result = mk_output_path(Lib, pkgid.path.to_str(), result); + debug!("built_library_in_workspace: checking whether %s exists", + result.to_str()); + + // We don't know what the hash is, so we have to search through the directory + // contents + let dir_contents = os::list_dir(&result.pop()); + debug!("dir has %? entries", dir_contents.len()); + + // n.b. This code assumes the pkgid's path only has one element + let lib_prefix = fmt!("%s%s", os::consts::DLL_PREFIX, pkgid.path.to_str()); + let lib_filetype = fmt!("%s%s", pkgid.version.to_str(), os::consts::DLL_SUFFIX); + + debug!("lib_prefix = %s and lib_filetype = %s", lib_prefix, lib_filetype); + + let mut result_filename = None; + for dir_contents.each |&p| { + let mut which = 0; + let mut hash = None; + // Find a filename that matches the pattern: (lib_prefix)-hash-(version)(lib_suffix) + // and remember what the hash was + for p.each_split_char('-') |piece| { + debug!("a piece = %s", piece); + if which == 0 && piece != lib_prefix { + break; + } + else if which == 0 { + which += 1; + } + else if which == 1 { + hash = Some(piece.to_owned()); + which += 1; + } + else if which == 2 && piece != lib_filetype { + hash = None; + break; + } + else if which == 2 { + break; + } + else { + // something went wrong + hash = None; + break; + } + } + if hash.is_some() { + result_filename = Some(p); + break; + } + } + + // Return the filename that matches, which we now know exists + // (if result_filename != None) + debug!("result_filename = %?", result_filename); + match result_filename { + None => None, + Some(result_filename) => { + let result_filename = result.with_filename(result_filename); + debug!("result_filename = %s", result_filename.to_str()); + Some(result_filename) + } + } +} + /// Returns the executable that would be installed for /// in +/// As a side effect, creates the bin-dir if it doesn't exist pub fn target_executable_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { - let result = workspace.push("bin"); - // should use a target-specific subdirectory - mk_output_path(Main, pkgid.path.to_str(), result) + target_file_in_workspace(pkgid, workspace, Main) } /// Returns the executable that would be installed for /// in +/// As a side effect, creates the bin-dir if it doesn't exist pub fn target_library_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { - let result = workspace.push("lib"); - mk_output_path(Lib, pkgid.path.to_str(), result) + target_file_in_workspace(pkgid, workspace, Lib) } /// Returns the test executable that would be installed for /// in pub fn target_test_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { - let result = workspace.push("build"); - mk_output_path(Test, pkgid.path.to_str(), result) + target_file_in_workspace(pkgid, workspace, Test) } /// Returns the bench executable that would be installed for /// in pub fn target_bench_in_workspace(pkgid: PkgId, workspace: &Path) -> Path { - let result = workspace.push("build"); - mk_output_path(Bench, pkgid.path.to_str(), result) + target_file_in_workspace(pkgid, workspace, Bench) +} + +fn target_file_in_workspace(pkgid: PkgId, workspace: &Path, + what: OutputType) -> Path { + use conditions::bad_path::cond; + + let (subdir, create_dir) = match what { + Main => ("bin", true), Lib => ("lib", true), Test | Bench => ("build", false) + }; + let result = workspace.push(subdir); + if create_dir { + if !os::path_exists(&result) && !mkdir_recursive(&result, u_rwx) { + cond.raise((result, fmt!("I couldn't create the %s dir", subdir))); + } + } + mk_output_path(what, pkgid.path.to_str(), result) + } /// Return the directory for 's build artifacts in . @@ -123,7 +227,11 @@ pub fn mk_output_path(what: OutputType, short_name: ~str, dir: Path) -> Path { match what { Lib => dir.push(os::dll_filename(short_name)), _ => dir.push(fmt!("%s%s%s", short_name, - if what == Test { ~"test" } else { ~"" }, + match what { + Test => "test", + Bench => "bench", + _ => "" + } os::EXE_SUFFIX)) } } diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index a296f0ca32a48..cc74f464e0e82 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -34,6 +34,8 @@ use syntax::{ast, diagnostic}; use util::*; use path_util::normalize; use path_util::{build_pkg_id_in_workspace, pkgid_src_in_workspace}; +use path_util::{built_executable_in_workspace, built_library_in_workspace}; +use path_util::{target_executable_in_workspace, target_library_in_workspace}; use workspace::pkg_parent_workspaces; use rustc::driver::session::{lib_crate, bin_crate, crate_type}; use context::Ctx; @@ -188,49 +190,7 @@ impl Ctx { // argument let pkgid = PkgId::new(args[0]); for pkg_parent_workspaces(pkgid) |workspace| { - let src_dir = pkgid_src_in_workspace(pkgid, workspace); - let build_dir = build_pkg_id_in_workspace(pkgid, workspace); - debug!("Destination dir = %s", build_dir.to_str()); - - // Create the package source - let mut src = PkgSrc::new(&workspace.push("src"), &build_dir, &pkgid); - debug!("Package src = %?", src); - - // Is there custom build logic? If so, use it - let pkg_src_dir = src_dir; - let mut custom = false; - debug!("Package source directory = %s", pkg_src_dir.to_str()); - let cfgs = match src.package_script_option(&pkg_src_dir) { - Some(package_script_path) => { - let pscript = PkgScript::parse(package_script_path, - workspace, - pkgid); - // Limited right now -- we're only running the post_build - // hook and probably fail otherwise - // also post_build should be called pre_build - let (cfgs, hook_result) = pscript.run_custom(~"post_build"); - debug!("Command return code = %?", hook_result); - if hook_result != 0 { - fail!(fmt!("Error running custom build command")) - } - custom = true; - // otherwise, the package script succeeded - cfgs - } - None => { - debug!("No package script, continuing"); - ~[] - } - }; - - // If there was a package script, it should have finished - // the build already. Otherwise... - if !custom { - // Find crates inside the workspace - src.find_crates(); - // Build it! - src.build(&build_dir, cfgs); - } + self.build(workspace, pkgid); } } ~"clean" => { @@ -304,6 +264,53 @@ impl Ctx { fail!(~"`do` not yet implemented"); } + fn build(&self, workspace: &Path, pkgid: PkgId) { + let src_dir = pkgid_src_in_workspace(pkgid, workspace); + let build_dir = build_pkg_id_in_workspace(pkgid, workspace); + debug!("Destination dir = %s", build_dir.to_str()); + + // Create the package source + let mut src = PkgSrc::new(&workspace.push("src"), &build_dir, &pkgid); + debug!("Package src = %?", src); + + // Is there custom build logic? If so, use it + let pkg_src_dir = src_dir; + let mut custom = false; + debug!("Package source directory = %s", pkg_src_dir.to_str()); + let cfgs = match src.package_script_option(&pkg_src_dir) { + Some(package_script_path) => { + let pscript = PkgScript::parse(package_script_path, + workspace, + pkgid); + // Limited right now -- we're only running the post_build + // hook and probably fail otherwise + // also post_build should be called pre_build + let (cfgs, hook_result) = pscript.run_custom(~"post_build"); + debug!("Command return code = %?", hook_result); + if hook_result != 0 { + fail!(fmt!("Error running custom build command")) + } + custom = true; + // otherwise, the package script succeeded + cfgs + } + None => { + debug!("No package script, continuing"); + ~[] + } + }; + + // If there was a package script, it should have finished + // the build already. Otherwise... + if !custom { + // Find crates inside the workspace + src.find_crates(); + // Build it! + src.build(&build_dir, cfgs); + } + + } + fn clean(&self, workspace: &Path, id: PkgId) { // Could also support a custom build hook in the pkg // script for cleaning files rustpkg doesn't know about. @@ -325,9 +332,31 @@ impl Ctx { fail!(~"info not yet implemented"); } - fn install(&self, _workspace: &Path, _id: PkgId) { - // stub - fail!(~"install not yet implemented"); + fn install(&self, workspace: &Path, id: PkgId) { + use conditions::copy_failed::cond; + + // Should use RUST_PATH in the future. + // Also should use workcache to not build if not necessary. + self.build(workspace, id); + + // Now copy stuff into the install dirs + let maybe_executable = built_executable_in_workspace(id, workspace); + let maybe_library = built_library_in_workspace(id, workspace); + let target_exec = target_executable_in_workspace(id, workspace); + let target_lib = target_library_in_workspace(id, workspace); + + for maybe_executable.each |exec| { + debug!("Copying: %s -> %s", exec.to_str(), target_exec.to_str()); + if !os::copy_file(exec, &target_exec) { + cond.raise((*exec, target_exec)); + } + } + for maybe_library.each |lib| { + debug!("Copying: %s -> %s", lib.to_str(), target_lib.to_str()); + if !os::copy_file(lib, &target_lib) { + cond.raise((*lib, target_lib)); + } + } } fn fetch(&self, _dir: &Path, _url: ~str, _target: Option<~str>) { @@ -610,7 +639,7 @@ impl PkgSrc { fn check_dir(&self) -> Path { - use conditions::bad_path::cond; + use conditions::nonexistent_package::cond; debug!("Pushing onto root: %s | %s", self.id.path.to_str(), self.root.to_str()); @@ -620,12 +649,12 @@ impl PkgSrc { debug!("Checking dir: %s", dir.to_str()); if !os::path_exists(&dir) { - return cond.raise((dir, ~"missing package dir")); + cond.raise((self.id, ~"missing package dir")); } if !os::path_is_dir(&dir) { - return cond.raise((dir, ~"supplied path for package dir is a \ - non-directory")); + cond.raise((self.id, ~"supplied path for package dir is a \ + non-directory")); } dir @@ -680,6 +709,7 @@ impl PkgSrc { /// is no custom build logic fn find_crates(&mut self) { use PkgSrc::push_crate; + use conditions::missing_pkg_files::cond; let dir = self.check_dir(); let prefix = dir.components.len(); @@ -704,7 +734,7 @@ impl PkgSrc { util::note(~"Couldn't infer any crates to build.\n\ Try naming a crate `main.rs`, `lib.rs`, \ `test.rs`, or `bench.rs`."); - fail!(~"Failed to infer crates to build"); + cond.raise(self.id); } debug!("found %u libs, %u mains, %u tests, %u benchs", diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index bcee2992e5ab9..f38fc88f72791 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -17,7 +17,8 @@ use std::tempfile::mkdtemp; use util::{PkgId, default_version}; use path_util::{target_executable_in_workspace, target_library_in_workspace, target_test_in_workspace, target_bench_in_workspace, - make_dir_rwx}; + make_dir_rwx, u_rwx}; +use core::os::mkdir_recursive; fn fake_ctxt() -> Ctx { Ctx { @@ -33,8 +34,27 @@ fn fake_pkg() -> PkgId { } } -fn mk_temp_workspace() -> Path { - mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir") +fn writeFile(file_path: &Path, contents: ~str) { + let out: @io::Writer = + result::get(&io::file_writer(file_path, + ~[io::Create, io::Truncate])); + out.write_line(contents); +} + +fn mk_temp_workspace(short_name: &Path) -> Path { + let workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); + let package_dir = workspace.push(~"src").push_rel(short_name); + assert!(mkdir_recursive(&package_dir, u_rwx)); + // Create main, lib, test, and bench files + writeFile(&package_dir.push(~"main.rs"), + ~"fn main() { let _x = (); }"); + writeFile(&package_dir.push(~"lib.rs"), + ~"pub fn f() { let _x = (); }"); + writeFile(&package_dir.push(~"test.rs"), + ~"#[test] pub fn f() { (); }"); + writeFile(&package_dir.push(~"bench.rs"), + ~"#[bench] pub fn f() { (); }"); + workspace } fn is_rwx(p: &Path) -> bool { @@ -42,11 +62,10 @@ fn is_rwx(p: &Path) -> bool { match p.get_mode() { None => return false, - Some(m) => { + Some(m) => ((m & S_IRUSR as uint) == S_IRUSR as uint && (m & S_IWUSR as uint) == S_IWUSR as uint && (m & S_IXUSR as uint) == S_IXUSR as uint) - } } } @@ -54,48 +73,60 @@ fn is_rwx(p: &Path) -> bool { fn test_make_dir_rwx() { let temp = &os::tmpdir(); let dir = temp.push(~"quux"); - let _ = os::remove_dir(&dir); + assert!(!os::path_exists(&dir) || + os::remove_dir_recursive(&dir)); + debug!("Trying to make %s", dir.to_str()); assert!(make_dir_rwx(&dir)); assert!(os::path_is_dir(&dir)); assert!(is_rwx(&dir)); - assert!(os::remove_dir(&dir)); + assert!(os::remove_dir_recursive(&dir)); } #[test] -#[ignore(reason = "install not yet implemented")] fn test_install_valid() { + use rustc::metadata::filesearch; + + let sysroot = filesearch::get_rustpkg_sysroot(); + debug!("sysroot = %s", sysroot.get().to_str()); let ctxt = fake_ctxt(); let temp_pkg_id = fake_pkg(); - let temp_workspace = mk_temp_workspace(); + let temp_workspace = mk_temp_workspace(&temp_pkg_id.path); // should have test, bench, lib, and main ctxt.install(&temp_workspace, temp_pkg_id); // Check that all files exist let exec = target_executable_in_workspace(temp_pkg_id, &temp_workspace); + debug!("exec = %s", exec.to_str()); assert!(os::path_exists(&exec)); assert!(is_rwx(&exec)); let lib = target_library_in_workspace(temp_pkg_id, &temp_workspace); + debug!("lib = %s", lib.to_str()); assert!(os::path_exists(&lib)); assert!(is_rwx(&lib)); // And that the test and bench executables aren't installed assert!(!os::path_exists(&target_test_in_workspace(temp_pkg_id, &temp_workspace))); - assert!(!os::path_exists(&target_bench_in_workspace(temp_pkg_id, &temp_workspace))); + let bench = target_bench_in_workspace(temp_pkg_id, &temp_workspace); + debug!("bench = %s", bench.to_str()); + assert!(!os::path_exists(&bench)); } #[test] -#[ignore(reason = "install not yet implemented")] fn test_install_invalid() { use conditions::nonexistent_package::cond; + use cond1 = conditions::missing_pkg_files::cond; let ctxt = fake_ctxt(); let pkgid = fake_pkg(); - let temp_workspace = mk_temp_workspace(); - let expected_path = Path(~"quux"); - let substituted: Path = do cond.trap(|_| { - expected_path + let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); + let mut error_occurred = false; + let mut error1_occurred = false; + do cond1.trap(|_| { + error1_occurred = true; }).in { - ctxt.install(&temp_workspace, pkgid); - // ok - fail!(~"test_install_invalid failed, should have raised a condition"); - }; - assert!(substituted == expected_path); + do cond.trap(|_| { + error_occurred = true; + }).in { + ctxt.install(&temp_workspace, pkgid); + } + } + assert!(error_occurred && error1_occurred); } diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 28198e59f86d4..1b3d72bf6aa64 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -477,6 +477,8 @@ pub fn compile_input(sysroot: Option, let matches = getopts(~[~"-Z", ~"time-passes"] + if building_library { ~[~"--lib"] } + else if test { ~[~"--test"] } + // bench? else { ~[] } + flags + cfgs.flat_map(|&c| { ~[~"--cfg", c] }), @@ -540,9 +542,13 @@ pub fn compile_crate_from_input(input: driver::input, let (crate, _) = driver::compile_upto(sess, cfg, &input, driver::cu_parse, Some(outputs)); + debug!("About to inject link_meta info..."); // Inject the inferred link_meta info if it's not already there // (assumes that name and vers are the only linkage metas) let mut crate_to_use = crate; + + debug!("How many attrs? %?", attr::find_linkage_metas(crate.node.attrs).len()); + if attr::find_linkage_metas(crate.node.attrs).is_empty() { crate_to_use = add_attrs(*crate, ~[mk_attr(@dummy_spanned(meta_list(@~"link", // change PkgId to have a field? @@ -552,7 +558,6 @@ pub fn compile_crate_from_input(input: driver::input, mk_string_lit(@pkg_id.version.to_str())))])))]); } - driver::compile_rest(sess, cfg, what, Some(outputs), Some(crate_to_use)); crate_to_use } diff --git a/src/libstd/tempfile.rs b/src/libstd/tempfile.rs index 6da74834b1a49..3d4e5bb8b79c1 100644 --- a/src/libstd/tempfile.rs +++ b/src/libstd/tempfile.rs @@ -27,7 +27,8 @@ pub fn mkdtemp(tmpdir: &Path, suffix: &str) -> Option { mod tests { use tempfile::mkdtemp; use tempfile; - + use core::os; + #[test] fn test_mkdtemp() { let p = mkdtemp(&Path("."), "foobar").unwrap(); @@ -89,4 +90,27 @@ mod tests { assert!(os::path_is_dir(&path2.pop())); }); } + + // Ideally this would be in core, but needs mkdtemp + #[test] + pub fn test_rmdir_recursive_ok() { + use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; + use core::os; + + let rwx = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; + + let tmpdir = mkdtemp(&os::tmpdir(), "test").expect("test_rmdir_recursive_ok: \ + couldn't create temp dir"); + let root = tmpdir.push("foo"); + + debug!("making %s", root.to_str()); + assert!(os::make_dir(&root, rwx)); + assert!(os::make_dir(&root.push("foo"), rwx)); + assert!(os::make_dir(&root.push("foo").push("bar"), rwx)); + assert!(os::make_dir(&root.push("foo").push("bar").push("blat"), rwx)); + assert!(os::remove_dir_recursive(&root)); + assert!(!os::path_exists(&root)); + assert!(!os::path_exists(&root.push("bar"))); + assert!(!os::path_exists(&root.push("bar").push("blat"))); + } } From 376a5526a78ab7acf9ba143264acc0c0e2e70541 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Thu, 2 May 2013 14:14:25 -0700 Subject: [PATCH 179/215] tidy --- src/libstd/tempfile.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/tempfile.rs b/src/libstd/tempfile.rs index 3d4e5bb8b79c1..10645e947e2d9 100644 --- a/src/libstd/tempfile.rs +++ b/src/libstd/tempfile.rs @@ -28,7 +28,7 @@ mod tests { use tempfile::mkdtemp; use tempfile; use core::os; - + #[test] fn test_mkdtemp() { let p = mkdtemp(&Path("."), "foobar").unwrap(); From c42f1218a0a7b3a5c84502f9cb4b123d65148f4c Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 3 May 2013 16:47:53 -0700 Subject: [PATCH 180/215] rustpkg: Handle sysroot more correctly In rustpkg, pass around sysroot; in rustpkg tests, set the sysroot manually so that tests can find libcore and such. With bonus metadata::filesearch refactoring to avoid copies. --- src/librustc/back/rpath.rs | 2 +- src/librustc/driver/driver.rs | 2 +- src/librustc/driver/session.rs | 2 +- src/librustc/metadata/filesearch.rs | 54 ++++++++++++++++------------ src/librustpkg/context.rs | 3 ++ src/librustpkg/path_util.rs | 6 +--- src/librustpkg/rustpkg.rc | 29 ++++++++------- src/librustpkg/tests.rs | 55 +++++++++++++++++++++++++---- src/librustpkg/util.rs | 5 +-- 9 files changed, 106 insertions(+), 52 deletions(-) diff --git a/src/librustc/back/rpath.rs b/src/librustc/back/rpath.rs index fab19b681740c..fceff55abf8d4 100644 --- a/src/librustc/back/rpath.rs +++ b/src/librustc/back/rpath.rs @@ -40,7 +40,7 @@ pub fn get_rpath_flags(sess: session::Session, out_filename: &Path) // where rustrt is and we know every rust program needs it let libs = vec::append_one(libs, get_sysroot_absolute_rt_lib(sess)); - let rpaths = get_rpaths(os, &sysroot, output, libs, + let rpaths = get_rpaths(os, sysroot, output, libs, sess.opts.target_triple); rpaths_to_flags(rpaths) } diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 5e5d0640d808e..d968cf708d938 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -603,7 +603,7 @@ pub fn build_session_options(binary: @~str, link::output_type_bitcode } else { link::output_type_exe }; let sysroot_opt = getopts::opt_maybe_str(matches, ~"sysroot"); - let sysroot_opt = sysroot_opt.map(|m| Path(*m)); + let sysroot_opt = sysroot_opt.map(|m| @Path(*m)); let target_opt = getopts::opt_maybe_str(matches, ~"target"); let target_feature_opt = getopts::opt_maybe_str(matches, ~"target-feature"); let save_temps = getopts::opt_present(matches, ~"save-temps"); diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 237b03bc20fb3..04cf3ca64f9d7 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -125,7 +125,7 @@ pub struct options { output_type: back::link::output_type, addl_lib_search_paths: ~[Path], linker_args: ~[~str], - maybe_sysroot: Option, + maybe_sysroot: Option<@Path>, target_triple: ~str, target_feature: ~str, // User-specified cfg meta items. The compiler itself will add additional diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index c88d5437c840e..ded0b314d44bb 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -20,41 +20,49 @@ pub fn pick_file(file: Path, path: &Path) -> Option { } pub trait FileSearch { - fn sysroot(&self) -> Path; - fn lib_search_paths(&self) -> ~[Path]; + fn sysroot(&self) -> @Path; + fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool); fn get_target_lib_path(&self) -> Path; fn get_target_lib_file_path(&self, file: &Path) -> Path; } -pub fn mk_filesearch(maybe_sysroot: &Option, +pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, target_triple: &str, addl_lib_search_paths: ~[Path]) -> @FileSearch { struct FileSearchImpl { - sysroot: Path, + sysroot: @Path, addl_lib_search_paths: ~[Path], target_triple: ~str } impl FileSearch for FileSearchImpl { - fn sysroot(&self) -> Path { /*bad*/copy self.sysroot } - fn lib_search_paths(&self) -> ~[Path] { - let mut paths = /*bad*/copy self.addl_lib_search_paths; - - paths.push( - make_target_lib_path(&self.sysroot, - self.target_triple)); - match get_rustpkg_lib_path_nearest() { - result::Ok(ref p) => paths.push((/*bad*/copy *p)), - result::Err(_) => () + fn sysroot(&self) -> @Path { self.sysroot } + fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) { + debug!("filesearch: searching additional lib search paths"); + if !self.addl_lib_search_paths.each(f) { + return; } - match get_rustpkg_lib_path() { - result::Ok(ref p) => paths.push((/*bad*/copy *p)), - result::Err(_) => () + + debug!("filesearch: searching target lib path"); + if !f(&make_target_lib_path(self.sysroot, + self.target_triple)) { + return; } - paths + debug!("filesearch: searching rustpkg lib path nearest"); + if match get_rustpkg_lib_path_nearest() { + result::Ok(ref p) => f(p), + result::Err(_) => true + } { + return; + } + debug!("filesearch: searching rustpkg lib path"); + match get_rustpkg_lib_path() { + result::Ok(ref p) => f(p), + result::Err(_) => true + } } fn get_target_lib_path(&self) -> Path { - make_target_lib_path(&self.sysroot, self.target_triple) + make_target_lib_path(self.sysroot, self.target_triple) } fn get_target_lib_file_path(&self, file: &Path) -> Path { self.get_target_lib_path().push_rel(file) @@ -72,7 +80,7 @@ pub fn mk_filesearch(maybe_sysroot: &Option, pub fn search(filesearch: @FileSearch, pick: pick) -> Option { let mut rslt = None; - for filesearch.lib_search_paths().each |lib_search_path| { + for filesearch.for_each_lib_search_path() |lib_search_path| { debug!("searching %s", lib_search_path.to_str()); for os::list_dir_path(lib_search_path).each |path| { debug!("testing %s", path.to_str()); @@ -108,10 +116,10 @@ fn get_or_default_sysroot() -> Path { } } -fn get_sysroot(maybe_sysroot: &Option) -> Path { +fn get_sysroot(maybe_sysroot: &Option<@Path>) -> @Path { match *maybe_sysroot { - option::Some(ref sr) => (/*bad*/copy *sr), - option::None => get_or_default_sysroot() + option::Some(sr) => sr, + option::None => @get_or_default_sysroot() } } diff --git a/src/librustpkg/context.rs b/src/librustpkg/context.rs index db036f44a185b..348d828bded2f 100644 --- a/src/librustpkg/context.rs +++ b/src/librustpkg/context.rs @@ -13,6 +13,9 @@ use core::hashmap::HashMap; pub struct Ctx { + // Sysroot -- if this is None, uses rustc filesearch's + // idea of the default + sysroot_opt: Option<@Path>, // I'm not sure what this is for json: bool, // Cache of hashes of things already installed diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs index 161cb75e9e50e..d21fdcda7f76f 100644 --- a/src/librustpkg/path_util.rs +++ b/src/librustpkg/path_util.rs @@ -29,11 +29,7 @@ pub static u_rwx: i32 = (S_IRUSR | S_IWUSR | S_IXUSR) as i32; /// Creates a directory that is readable, writeable, /// and executable by the user. Returns true iff creation /// succeeded. -pub fn make_dir_rwx(p: &Path) -> bool { - use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR}; - - os::make_dir(p, u_rwx) -} +pub fn make_dir_rwx(p: &Path) -> bool { os::make_dir(p, u_rwx) } /// Replace all occurrences of '-' in the stem part of path with '_' /// This is because we treat rust-foo-bar-quux and rust_foo_bar_quux diff --git a/src/librustpkg/rustpkg.rc b/src/librustpkg/rustpkg.rc index cc74f464e0e82..dd5806ba01568 100644 --- a/src/librustpkg/rustpkg.rc +++ b/src/librustpkg/rustpkg.rc @@ -306,7 +306,7 @@ impl Ctx { // Find crates inside the workspace src.find_crates(); // Build it! - src.build(&build_dir, cfgs); + src.build(&build_dir, cfgs, self.sysroot_opt); } } @@ -506,6 +506,7 @@ pub fn main() { } Ctx { + sysroot_opt: None, // Currently, only tests override this json: json, dep_cache: @mut HashMap::new() }.run(cmd, args); @@ -648,6 +649,8 @@ impl PkgSrc { debug!("Checking dir: %s", dir.to_str()); + // tjc: Rather than erroring out, need to try downloading the + // contents of the path to a local directory (#5679) if !os::path_exists(&dir) { cond.raise((self.id, ~"missing package dir")); } @@ -744,18 +747,20 @@ impl PkgSrc { self.benchs.len()) } - fn build_crates(&self, dst_dir: &Path, - src_dir: &Path, - crates: &[Crate], - cfgs: ~[~str], - test: bool, crate_type: crate_type) { + fn build_crates(&self, + maybe_sysroot: Option<@Path>, + dst_dir: &Path, + src_dir: &Path, + crates: &[Crate], + cfgs: ~[~str], + test: bool, crate_type: crate_type) { for crates.each |&crate| { let path = &src_dir.push_rel(&crate.file).normalize(); util::note(fmt!("build_crates: compiling %s", path.to_str())); util::note(fmt!("build_crates: destination dir is %s", dst_dir.to_str())); - let result = util::compile_crate(None, self.id, path, + let result = util::compile_crate(maybe_sysroot, self.id, path, dst_dir, crate.flags, crate.cfgs + cfgs, @@ -769,15 +774,15 @@ impl PkgSrc { } } - fn build(&self, dst_dir: &Path, cfgs: ~[~str]) { + fn build(&self, dst_dir: &Path, cfgs: ~[~str], maybe_sysroot: Option<@Path>) { let dir = self.check_dir(); debug!("Building libs"); - self.build_crates(dst_dir, &dir, self.libs, cfgs, false, lib_crate); + self.build_crates(maybe_sysroot, dst_dir, &dir, self.libs, cfgs, false, lib_crate); debug!("Building mains"); - self.build_crates(dst_dir, &dir, self.mains, cfgs, false, bin_crate); + self.build_crates(maybe_sysroot, dst_dir, &dir, self.mains, cfgs, false, bin_crate); debug!("Building tests"); - self.build_crates(dst_dir, &dir, self.tests, cfgs, true, bin_crate); + self.build_crates(maybe_sysroot, dst_dir, &dir, self.tests, cfgs, true, bin_crate); debug!("Building benches"); - self.build_crates(dst_dir, &dir, self.benchs, cfgs, true, bin_crate); + self.build_crates(maybe_sysroot, dst_dir, &dir, self.benchs, cfgs, true, bin_crate); } } diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs index f38fc88f72791..486e2959e9ed7 100644 --- a/src/librustpkg/tests.rs +++ b/src/librustpkg/tests.rs @@ -20,8 +20,9 @@ use path_util::{target_executable_in_workspace, target_library_in_workspace, make_dir_rwx, u_rwx}; use core::os::mkdir_recursive; -fn fake_ctxt() -> Ctx { +fn fake_ctxt(sysroot_opt: Option<@Path>) -> Ctx { Ctx { + sysroot_opt: sysroot_opt, json: false, dep_cache: @mut HashMap::new() } @@ -34,6 +35,13 @@ fn fake_pkg() -> PkgId { } } +fn remote_pkg() -> PkgId { + PkgId { + path: Path(~"github.com/catamorphism/test-pkg"), + version: default_version() + } +} + fn writeFile(file_path: &Path, contents: ~str) { let out: @io::Writer = result::get(&io::file_writer(file_path, @@ -69,6 +77,15 @@ fn is_rwx(p: &Path) -> bool { } } +#[cfg(test)] +fn test_sysroot() -> Path { + // Totally gross hack but it's just for test cases. + // Infer the sysroot from the exe name and tack "stage2" + // onto it. (Did I mention it was a gross hack?) + let self_path = os::self_exe_path().expect("Couldn't get self_exe path"); + self_path.pop().push("stage2") +} + #[test] fn test_make_dir_rwx() { let temp = &os::tmpdir(); @@ -84,11 +101,9 @@ fn test_make_dir_rwx() { #[test] fn test_install_valid() { - use rustc::metadata::filesearch; - - let sysroot = filesearch::get_rustpkg_sysroot(); - debug!("sysroot = %s", sysroot.get().to_str()); - let ctxt = fake_ctxt(); + let sysroot = test_sysroot(); + debug!("sysroot = %s", sysroot.to_str()); + let ctxt = fake_ctxt(Some(@sysroot)); let temp_pkg_id = fake_pkg(); let temp_workspace = mk_temp_workspace(&temp_pkg_id.path); // should have test, bench, lib, and main @@ -114,7 +129,7 @@ fn test_install_invalid() { use conditions::nonexistent_package::cond; use cond1 = conditions::missing_pkg_files::cond; - let ctxt = fake_ctxt(); + let ctxt = fake_ctxt(None); let pkgid = fake_pkg(); let temp_workspace = mkdtemp(&os::tmpdir(), "test").expect("couldn't create temp dir"); let mut error_occurred = false; @@ -130,3 +145,29 @@ fn test_install_invalid() { } assert!(error_occurred && error1_occurred); } + +#[test] +#[ignore(reason = "install from URL-fragment not yet implemented")] +fn test_install_url() { + let sysroot = test_sysroot(); + debug!("sysroot = %s", sysroot.to_str()); + let ctxt = fake_ctxt(Some(@sysroot)); + let temp_pkg_id = remote_pkg(); + let temp_workspace = mk_temp_workspace(&temp_pkg_id.path); + // should have test, bench, lib, and main + ctxt.install(&temp_workspace, temp_pkg_id); + // Check that all files exist + let exec = target_executable_in_workspace(temp_pkg_id, &temp_workspace); + debug!("exec = %s", exec.to_str()); + assert!(os::path_exists(&exec)); + assert!(is_rwx(&exec)); + let lib = target_library_in_workspace(temp_pkg_id, &temp_workspace); + debug!("lib = %s", lib.to_str()); + assert!(os::path_exists(&lib)); + assert!(is_rwx(&lib)); + // And that the test and bench executables aren't installed + assert!(!os::path_exists(&target_test_in_workspace(temp_pkg_id, &temp_workspace))); + let bench = target_bench_in_workspace(temp_pkg_id, &temp_workspace); + debug!("bench = %s", bench.to_str()); + assert!(!os::path_exists(&bench)); +} \ No newline at end of file diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs index 1b3d72bf6aa64..0762fa4ad7fd3 100644 --- a/src/librustpkg/util.rs +++ b/src/librustpkg/util.rs @@ -435,7 +435,7 @@ pub fn add_pkg(pkg: &Pkg) -> bool { } // FIXME (#4432): Use workcache to only compile when needed -pub fn compile_input(sysroot: Option, +pub fn compile_input(sysroot: Option<@Path>, pkg_id: PkgId, in_file: &Path, out_dir: &Path, @@ -474,6 +474,7 @@ pub fn compile_input(sysroot: Option, out_file.to_str()); debug!("flags: %s", str::connect(flags, ~" ")); debug!("cfgs: %s", str::connect(cfgs, ~" ")); + debug!("compile_input's sysroot = %?", sysroot); let matches = getopts(~[~"-Z", ~"time-passes"] + if building_library { ~[~"--lib"] } @@ -587,7 +588,7 @@ fn add_attrs(c: ast::crate, new_attrs: ~[attribute]) -> @ast::crate { // Called by build_crates // FIXME (#4432): Use workcache to only compile when needed -pub fn compile_crate(sysroot: Option, pkg_id: PkgId, +pub fn compile_crate(sysroot: Option<@Path>, pkg_id: PkgId, crate: &Path, dir: &Path, flags: ~[~str], cfgs: ~[~str], opt: bool, test: bool, crate_type: crate_type) -> bool { From 5fb5a94118399e50c50f25586266c317ee5ba69b Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 3 May 2013 15:47:32 -0700 Subject: [PATCH 181/215] core: Warning police --- src/libcore/task/mod.rs | 2 +- src/libcore/unstable/lang.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs index ebf2494c8ee5b..fd695c16ea7cb 100644 --- a/src/libcore/task/mod.rs +++ b/src/libcore/task/mod.rs @@ -39,7 +39,7 @@ use result::Result; use comm::{stream, Chan, GenericChan, GenericPort, Port}; use prelude::*; use result; -use task::rt::{task_id, sched_id, rust_task}; +use task::rt::{task_id, sched_id}; use util; use util::replace; use unstable::finally::Finally; diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index a8a0d40db1f62..7cd218639c0a6 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -17,7 +17,9 @@ use str; use sys; use unstable::exchange_alloc; use cast::transmute; +#[cfg(not(stage0))] use rt::{context, OldTaskContext}; +#[cfg(not(stage0))] use rt::local_services::borrow_local_services; #[allow(non_camel_case_types)] From 18bf9bd55aa87d3da19e343241d1171414e2fc92 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 3 May 2013 15:57:18 -0700 Subject: [PATCH 182/215] std: Warning police --- src/libstd/arena.rs | 3 +-- src/libstd/future.rs | 2 +- src/libstd/net_tcp.rs | 2 -- src/libstd/net_url.rs | 2 -- src/libstd/workcache.rs | 4 +--- 5 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/libstd/arena.rs b/src/libstd/arena.rs index 0e9b2ed3da89c..67b5e5e654ad0 100644 --- a/src/libstd/arena.rs +++ b/src/libstd/arena.rs @@ -33,7 +33,6 @@ // to waste time running the destructors of POD. use list::{MutList, MutCons, MutNil}; -use list; use core::at_vec; use core::cast::{transmute, transmute_mut_region}; @@ -79,7 +78,7 @@ struct Chunk { } pub struct Arena { - // The head is seperated out from the list as a unbenchmarked + // The head is separated out from the list as a unbenchmarked // microoptimization, to avoid needing to case on the list to // access the head. priv head: Chunk, diff --git a/src/libstd/future.rs b/src/libstd/future.rs index f59abfa81ca10..a0312849a35cb 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -23,7 +23,7 @@ use core::cast; use core::cell::Cell; -use core::comm::{ChanOne, PortOne, oneshot, send_one}; +use core::comm::{PortOne, oneshot, send_one}; use core::pipes::recv; use core::task; diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 764152d6812c5..6278db617c7da 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -11,8 +11,6 @@ //! High-level interface to libuv's TCP functionality // FIXME #4425: Need FFI fixes -#[allow(deprecated_mode)]; - use future; use future_spawn = future::spawn; use ip = net_ip; diff --git a/src/libstd/net_url.rs b/src/libstd/net_url.rs index 21e1733cc3075..ba3fd69e344c2 100644 --- a/src/libstd/net_url.rs +++ b/src/libstd/net_url.rs @@ -10,8 +10,6 @@ //! Types/fns concerning URLs (see RFC 3986) -#[allow(deprecated_mode)]; - use core::cmp::Eq; use core::io::{Reader, ReaderUtil}; use core::io; diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs index 2cdf36c71c79f..f44d143004ede 100644 --- a/src/libstd/workcache.rs +++ b/src/libstd/workcache.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#[allow(deprecated_mode)]; - use json; use sha1; use serialize::{Encoder, Encodable, Decoder, Decodable}; @@ -17,7 +15,7 @@ use sort; use core::cell::Cell; use core::cmp; -use core::comm::{ChanOne, PortOne, oneshot, send_one}; +use core::comm::{PortOne, oneshot, send_one}; use core::either::{Either, Left, Right}; use core::hashmap::HashMap; use core::io; From 1a5f11a11b1b12f74fdb9e81b6c428901913246f Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 3 May 2013 16:20:24 -0700 Subject: [PATCH 183/215] syntax: Warning police --- src/libsyntax/parse/parser.rs | 6 +++--- src/libsyntax/syntax.rc | 1 - 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 5ae101a567cc2..a6528160398e8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -932,8 +932,8 @@ pub impl Parser { loop { match *self.token { token::MOD_SEP => { - match self.look_ahead(1u) { - token::IDENT(id,_) => { + match self.look_ahead(1) { + token::IDENT(*) => { self.bump(); ids.push(self.parse_ident()); } @@ -3693,7 +3693,7 @@ pub impl Parser { items: _, foreign_items: foreign_items } = self.parse_foreign_items(first_item_attrs, true); - let mut initial_attrs = attrs_remaining; + let _initial_attrs = attrs_remaining; assert!(*self.token == token::RBRACE); ast::foreign_mod { sort: sort, diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index a401d9eb8ace7..cea3b20e97e7d 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -22,7 +22,6 @@ #[allow(vecs_implicitly_copyable)]; #[allow(non_camel_case_types)]; -#[deny(deprecated_mode)]; #[deny(deprecated_pattern)]; extern mod std(vers = "0.7-pre"); From 2df8799f766c3a4871fe12761843ef9a5bc83659 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 3 May 2013 16:20:29 -0700 Subject: [PATCH 184/215] rustc: Warning police --- src/librustc/metadata/loader.rs | 2 +- src/librustc/middle/trans/base.rs | 14 ++++++-------- src/librustc/middle/ty.rs | 2 +- src/librustc/rustc.rc | 1 - 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index d2982e58038dd..193f6fc8f0a3b 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -196,7 +196,7 @@ fn get_metadata_section(os: os, while llvm::LLVMIsSectionIteratorAtEnd(of.llof, si.llsi) == False { let name_buf = llvm::LLVMGetSectionName(si.llsi); let name = unsafe { str::raw::from_c_str(name_buf) }; - debug!("get_matadata_section: name %s", name); + debug!("get_metadata_section: name %s", name); if name == read_meta_section_name(os) { let cbuf = llvm::LLVMGetSectionContents(si.llsi); let csz = llvm::LLVMGetSectionSize(si.llsi) as uint; diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index b5029ee6bd7d1..b8ab360b9e4e7 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2096,8 +2096,7 @@ pub fn trans_tuple_struct(ccx: @CrateContext, } pub fn trans_enum_def(ccx: @CrateContext, enum_definition: &ast::enum_def, - id: ast::node_id, - path: @ast_map::path, vi: @~[ty::VariantInfo], + id: ast::node_id, vi: @~[ty::VariantInfo], i: &mut uint) { for vec::each(enum_definition.variants) |variant| { let disr_val = vi[*i].disr_val; @@ -2172,8 +2171,7 @@ pub fn trans_item(ccx: @CrateContext, item: &ast::item) { if !generics.is_type_parameterized() { let vi = ty::enum_variants(ccx.tcx, local_def(item.id)); let mut i = 0; - trans_enum_def(ccx, enum_definition, item.id, - path, vi, &mut i); + trans_enum_def(ccx, enum_definition, item.id, vi, &mut i); } } ast::item_const(_, expr) => consts::trans_const(ccx, expr, item.id), @@ -2430,13 +2428,13 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef { Some(&v) => v, None => { let mut exprt = false; - let val = match *ccx.tcx.items.get(&id) { + let val = match *tcx.items.get(&id) { ast_map::node_item(i, pth) => { let my_path = vec::append(/*bad*/copy *pth, ~[path_name(i.ident)]); match i.node { ast::item_const(_, expr) => { - let typ = ty::node_id_to_type(ccx.tcx, i.id); + let typ = ty::node_id_to_type(tcx, i.id); let s = mangle_exported_name(ccx, my_path, typ); // We need the translated value here, because for enums the // LLVM type is not fully determined by the Rust type. @@ -2495,7 +2493,7 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef { ni.attrs) } ast::foreign_item_const(*) => { - let typ = ty::node_id_to_type(ccx.tcx, ni.id); + let typ = ty::node_id_to_type(tcx, ni.id); let ident = ccx.sess.parse_sess.interner.get(ni.ident); let g = do str::as_c_str(*ident) |buf| { unsafe { @@ -2536,7 +2534,7 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef { // Only register the constructor if this is a tuple-like struct. match struct_def.ctor_id { None => { - ccx.tcx.sess.bug(~"attempt to register a constructor of \ + tcx.sess.bug(~"attempt to register a constructor of \ a non-tuple-like struct") } Some(ctor_id) => { diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 411c953434311..abf82c511e551 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -33,7 +33,7 @@ use core::to_bytes; use core::hashmap::{HashMap, HashSet}; use std::smallintmap::SmallIntMap; use syntax::ast::*; -use syntax::ast_util::{is_local, local_def}; +use syntax::ast_util::is_local; use syntax::ast_util; use syntax::attr; use syntax::codemap::span; diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index adb1c2fcc4171..7a7dcbb8bfd8d 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -20,7 +20,6 @@ #[allow(non_implicitly_copyable_typarams)]; #[allow(non_camel_case_types)]; #[deny(deprecated_pattern)]; -#[deny(deprecated_mode)]; extern mod std(vers = "0.7-pre"); extern mod syntax(vers = "0.7-pre"); From 86efd97a10fda1f81f5bead0de36e3343a9faa0e Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Fri, 3 May 2013 19:25:04 -0400 Subject: [PATCH 185/215] add gitattributes and fix whitespace issues --- .gitattributes | 9 +++++ COPYRIGHT | 1 - RELEASES.txt | 6 +-- doc/README | 6 +-- doc/rust.md | 1 - doc/tutorial-macros.md | 1 - doc/tutorial-tasks.md | 1 - doc/tutorial.md | 8 ++-- doc/version_info.html.template | 1 - mk/platform.mk | 6 +-- mk/rt.mk | 12 +++--- mk/stage0.mk | 6 +-- mk/tests.mk | 5 +-- src/etc/check-links.pl | 5 +-- src/etc/gedit/readme.txt | 1 - .../language-specs/rust.lang | 5 +-- src/etc/gedit/share/mime/packages/rust.xml | 2 +- src/etc/indenter | 1 - src/etc/latest-unix-snaps.py | 2 - src/etc/libc.c | 1 - src/etc/licenseck.py | 1 - src/etc/local_stage0.sh | 4 +- src/etc/mirror-all-snapshots.py | 3 -- src/etc/monodebug.pl | 1 - src/etc/sugarise-doc-comments.py | 1 - src/etc/tidy.py | 1 - src/etc/x86.supp | 4 +- src/libcore/cleanup.rs | 1 - src/libcore/logging.rs | 1 - src/libcore/owned.rs | 1 - src/libcore/rt/context.rs | 1 - src/libcore/rt/io/comm_adapters.rs | 1 - src/libcore/rt/io/net/ip.rs | 1 - src/libcore/rt/io/net/udp.rs | 1 - src/libcore/rt/io/net/unix.rs | 1 - src/libcore/rt/local_heap.rs | 1 - src/libcore/rt/sched/local_sched.rs | 1 - src/libcore/stackwalk.rs | 1 - src/libcore/unicode.rs | 1 - src/libcore/unstable/exchange_alloc.rs | 1 - src/libcore/unstable/weak_task.rs | 1 - src/librustc/metadata/common.rs | 1 - src/librustc/metadata/mod.rs | 1 - src/librustc/middle/borrowck/check_loans.rs | 1 - src/librustc/middle/borrowck/gather_loans.rs | 1 - src/librustc/middle/borrowck/loan.rs | 1 - src/librustc/middle/lang_items.rs | 1 - src/librustc/middle/mem_categorization.rs | 1 - src/librustc/middle/pat_util.rs | 1 - src/librustc/middle/privacy.rs | 1 - src/librustc/middle/region.rs | 1 - src/librustc/middle/subst.rs | 1 - src/librustc/middle/trans/cabi.rs | 1 - src/librustc/middle/trans/callee.rs | 1 - src/librustc/middle/trans/closure.rs | 1 - src/librustc/middle/trans/controlflow.rs | 1 - src/librustc/middle/trans/datum.rs | 1 - src/librustc/middle/trans/inline.rs | 1 - src/librustc/middle/trans/machine.rs | 1 - src/librustc/middle/trans/macros.rs | 1 - src/librustc/middle/trans/reachable.rs | 1 - src/librustc/middle/trans/reflect.rs | 1 - src/librustc/middle/trans/shape.rs | 1 - src/librustc/middle/trans/type_use.rs | 1 - src/librustc/middle/typeck/check/_match.rs | 1 - src/librustc/middle/typeck/check/demand.rs | 2 - src/librustc/middle/typeck/check/vtable.rs | 2 - src/librustc/middle/typeck/coherence.rs | 1 - src/librustc/middle/typeck/infer/combine.rs | 1 - src/librustc/middle/typeck/infer/glb.rs | 1 - src/librustc/middle/typeck/infer/macros.rs | 1 - .../middle/typeck/infer/region_inference.rs | 1 - src/librustc/middle/typeck/infer/resolve.rs | 1 - src/librustc/middle/typeck/infer/sub.rs | 1 - src/librustc/middle/typeck/infer/unify.rs | 2 - src/librustdoc/path_pass.rs | 1 - src/librustpkg/testsuite/pass/commands.txt | 1 - .../src/deeply/nested/path/foo/src/main.rs | 1 - src/libstd/num/bigint.rs | 1 - src/libstd/serialize.rs | 1 - src/libstd/task_pool.rs | 1 - src/libsyntax/ext/pipes/check.rs | 1 - src/libsyntax/ext/pipes/liveness.rs | 1 - src/libsyntax/ext/pipes/mod.rs | 1 - src/libsyntax/ext/pipes/proto.rs | 1 - src/libsyntax/ext/quote.rs | 1 - src/libsyntax/parse/obsolete.rs | 1 - src/libsyntax/syntax.rc | 1 - src/rt/arch/arm/_context.S | 2 - src/rt/arch/arm/gpr.cpp | 1 - src/rt/arch/arm/gpr.h | 1 - src/rt/arch/arm/morestack.S | 4 +- src/rt/arch/arm/record_sp.S | 1 - src/rt/arch/arm/regs.h | 2 - src/rt/arch/i386/_context.S | 2 - src/rt/arch/i386/gpr.cpp | 1 - src/rt/arch/i386/gpr.h | 1 - src/rt/arch/i386/morestack.S | 3 +- src/rt/arch/mips/gpr.h | 1 - src/rt/arch/x86_64/_context.S | 1 - src/rt/arch/x86_64/gpr.cpp | 1 - src/rt/arch/x86_64/gpr.h | 1 - src/rt/arch/x86_64/regs.h | 2 - src/rt/isaac/rand.h | 2 - src/rt/rust_abi.cpp | 1 - src/rt/rust_abi.h | 1 - src/rt/rust_android_dummy.h | 1 - src/rt/rust_debug.cpp | 1 - src/rt/rust_debug.h | 1 - src/rt/rust_gpr_base.h | 1 - src/rustllvm/README | 1 - src/rustllvm/RustWrapper.cpp | 22 +++++------ src/snapshots.txt | 2 +- .../auxiliary/anon_trait_static_method_lib.rs | 1 - src/test/auxiliary/cci_class_2.rs | 1 - src/test/auxiliary/cci_class_6.rs | 1 - src/test/auxiliary/cci_class_cast.rs | 2 - src/test/auxiliary/cci_no_inline_lib.rs | 1 - src/test/auxiliary/explicit_self_xcrate.rs | 2 - src/test/auxiliary/extern_mod_ordering_lib.rs | 1 - src/test/auxiliary/foreign_lib.rs | 1 - src/test/auxiliary/impl_privacy_xc_1.rs | 1 - src/test/auxiliary/impl_privacy_xc_2.rs | 2 - src/test/auxiliary/issue-2414-a.rs | 1 - src/test/auxiliary/issue-2414-b.rs | 1 - src/test/auxiliary/issue-2526.rs | 1 - src/test/auxiliary/issue_2316_b.rs | 2 - src/test/auxiliary/issue_3136_a.rs | 5 +-- src/test/auxiliary/issue_3882.rs | 2 +- src/test/auxiliary/moves_based_on_type_lib.rs | 1 - src/test/auxiliary/newtype_struct_xc.rs | 1 - src/test/auxiliary/pub_use_mods_xcrate.rs | 1 - src/test/auxiliary/static_fn_inline_xc_aux.rs | 1 - .../struct_destructuring_cross_crate.rs | 1 - .../trait_inheritance_auto_xc_2_aux.rs | 2 - .../trait_inheritance_overloading_xc.rs | 1 - src/test/auxiliary/xc_private_method_lib.rs | 1 - src/test/bench/msgsend-pipes-shared.rs | 2 +- src/test/bench/msgsend-pipes.rs | 2 +- src/test/bench/msgsend-ring-mutex-arcs.rs | 2 +- src/test/bench/msgsend-ring-pipes.rs | 2 +- src/test/bench/msgsend-ring-rw-arcs.rs | 2 +- src/test/bench/pingpong.rs | 2 +- src/test/bench/shootout-chameneos-redux.rs | 1 - src/test/bench/shootout-fannkuch-redux.rs | 1 - src/test/bench/shootout-fasta-redux.rs | 1 - src/test/bench/shootout-k-nucleotide-pipes.rs | 1 - src/test/bench/shootout-k-nucleotide.rs | 3 +- src/test/bench/shootout-mandelbrot.rs | 1 - src/test/bench/shootout-pidigits.rs | 1 - src/test/bench/shootout-reverse-complement.rs | 1 - src/test/bench/sudoku.rs | 1 - src/test/compile-fail/alt-tag-nullary.rs | 1 - src/test/compile-fail/alt-tag-unary.rs | 1 - .../compile-fail/auto-ref-borrowck-failure.rs | 1 - src/test/compile-fail/bogus-tag.rs | 1 - .../compile-fail/borrowck-assign-comp-idx.rs | 1 - src/test/compile-fail/borrowck-assign-comp.rs | 1 - ...borrowck-call-method-from-mut-aliasable.rs | 1 - ...borrowck-loan-local-as-both-mut-and-imm.rs | 2 +- .../borrowck-loan-rcvr-overloaded-op.rs | 3 +- src/test/compile-fail/borrowck-loan-rcvr.rs | 1 - .../compile-fail/borrowck-mut-boxed-vec.rs | 1 - .../compile-fail/borrowck-ref-into-rvalue.rs | 5 +-- .../compile-fail/borrowck-uniq-via-box.rs | 1 - .../borrowck-vec-pattern-loan-from-mut.rs | 1 - .../borrowck-vec-pattern-nesting.rs | 1 - .../borrowck-wg-borrow-mut-to-imm-fail-2.rs | 1 - .../borrowck-wg-borrow-mut-to-imm-fail-3.rs | 1 - .../borrowck-wg-borrow-mut-to-imm-fail.rs | 1 - .../compile-fail/borrowck-wg-move-base-2.rs | 2 - .../compile-fail/by-move-pattern-binding.rs | 1 - src/test/compile-fail/dead-code-ret.rs | 1 - src/test/compile-fail/does-nothing.rs | 1 - src/test/compile-fail/drop-on-non-struct.rs | 2 - .../compile-fail/explicit-call-to-dtor.rs | 1 - .../explicit-call-to-supertrait-dtor.rs | 2 - .../float-literal-inference-restrictions.rs | 1 - .../compile-fail/foreign-unsafe-fn-called.rs | 1 - src/test/compile-fail/foreign-unsafe-fn.rs | 2 - src/test/compile-fail/issue-1451.rs | 1 - src/test/compile-fail/issue-2951.rs | 1 - src/test/compile-fail/issue-3044.rs | 1 - src/test/compile-fail/issue-3096-2.rs | 2 +- src/test/compile-fail/issue-3991.rs | 4 +- src/test/compile-fail/issue-4265.rs | 4 +- src/test/compile-fail/issue-4366.rs | 1 - src/test/compile-fail/issue-4968.rs | 1 - .../compile-fail/kindck-destructor-owned.rs | 1 - src/test/compile-fail/lint-default-methods.rs | 1 - src/test/compile-fail/lint-type-limits.rs | 1 - src/test/compile-fail/liveness-if-no-else.rs | 4 +- src/test/compile-fail/liveness-return.rs | 4 +- .../liveness-uninit-after-item.rs | 1 - src/test/compile-fail/liveness-uninit.rs | 4 +- .../compile-fail/macro-with-seps-err-msg.rs | 2 - .../compile-fail/missing-derivable-attr.rs | 1 - src/test/compile-fail/missing-return.rs | 1 - .../moves-based-on-type-block-bad.rs | 1 - .../moves-based-on-type-capture-clause-bad.rs | 1 - ...s-based-on-type-cyclic-types-issue-4821.rs | 1 - src/test/compile-fail/no-capture-arc.rs | 2 +- src/test/compile-fail/noexporttypeexe.rs | 1 - .../non-exhaustive-match-nested.rs | 1 - src/test/compile-fail/once-fn-subtyping.rs | 1 - src/test/compile-fail/private-impl-method.rs | 1 - src/test/compile-fail/private-item-simple.rs | 1 - .../compile-fail/private-method-inherited.rs | 1 - .../compile-fail/private-struct-field-ctor.rs | 1 - .../private-struct-field-pattern.rs | 1 - src/test/compile-fail/qquote-1.rs | 1 - src/test/compile-fail/qquote-2.rs | 1 - .../refutable-pattern-in-fn-arg.rs | 1 - src/test/compile-fail/regions-addr-of-self.rs | 1 - .../regions-infer-borrow-scope-too-big.rs | 1 - .../regions-infer-borrow-scope-within-loop.rs | 4 +- src/test/compile-fail/regions-ret.rs | 1 - .../compile-fail/repeat-to-run-dtor-twice.rs | 1 - .../compile-fail/static-method-privacy.rs | 1 - src/test/compile-fail/static-region-bound.rs | 1 - .../struct-like-enum-nonexhaustive.rs | 2 - src/test/compile-fail/super-at-top-level.rs | 2 - .../trait-impl-method-mismatch.rs | 4 -- .../trait-inheritance-missing-requirement.rs | 1 - .../tuple-struct-nonexhaustive.rs | 2 - .../tutorial-suffix-inference-test.rs | 4 +- .../compile-fail/unique-object-noncopyable.rs | 1 - .../use-after-move-based-on-type.rs | 1 - .../use-after-move-self-based-on-type.rs | 1 - src/test/compile-fail/use-after-move-self.rs | 1 - src/test/compile-fail/view-items-at-top.rs | 1 - src/test/compile-fail/while-type-error.rs | 1 - src/test/compile-fail/xc-private-method.rs | 1 - src/test/pretty/doc-comments.rs | 2 +- src/test/run-fail/assert-as-macro.rs | 1 - src/test/run-fail/borrowck-wg-fail-3.rs | 1 - src/test/run-fail/borrowck-wg-fail.rs | 1 - src/test/run-fail/unwind-resource-fail3.rs | 2 +- src/test/run-pass-fulldeps/qquote.rs | 1 - src/test/run-pass-fulldeps/quote-tokens.rs | 1 - src/test/run-pass/anon-trait-static-method.rs | 1 - .../run-pass/anon_trait_static_method_exe.rs | 3 -- src/test/run-pass/auto-ref-newtype.rs | 1 - src/test/run-pass/auto-ref.rs | 1 - .../autoderef-and-borrow-method-receiver.rs | 1 - src/test/run-pass/bare-static-string.rs | 1 - src/test/run-pass/binops.rs | 2 +- src/test/run-pass/block-arg-in-parentheses.rs | 1 - .../run-pass/borrow-by-val-method-receiver.rs | 1 - src/test/run-pass/borrowck-wg-simple.rs | 1 - src/test/run-pass/boxed-trait-with-vstore.rs | 1 - src/test/run-pass/break.rs | 6 +-- .../class-cast-to-trait-cross-crate-2.rs | 1 - .../class-impl-parameterized-trait.rs | 2 +- src/test/run-pass/cleanup-copy-mode.rs | 1 - src/test/run-pass/clone-with-exterior.rs | 2 +- src/test/run-pass/conditional-compile.rs | 2 +- src/test/run-pass/const-enum-vec-index.rs | 2 +- src/test/run-pass/const-enum-vec-ptr.rs | 2 +- src/test/run-pass/const-enum-vector.rs | 2 +- .../const-expr-in-fixed-length-vec.rs | 2 +- src/test/run-pass/const-expr-in-vec-repeat.rs | 2 +- src/test/run-pass/const-tuple-struct.rs | 1 - src/test/run-pass/const-unit-struct.rs | 1 - src/test/run-pass/const-vec-syntax.rs | 1 - src/test/run-pass/consts-in-patterns.rs | 1 - src/test/run-pass/cycle-collection.rs | 1 - src/test/run-pass/default-method-simple.rs | 1 - src/test/run-pass/deriving-clone-enum.rs | 1 - .../run-pass/deriving-clone-generic-enum.rs | 1 - .../run-pass/deriving-clone-generic-struct.rs | 1 - .../deriving-clone-generic-tuple-struct.rs | 1 - .../run-pass/deriving-clone-tuple-struct.rs | 1 - .../run-pass/deriving-via-extension-c-enum.rs | 1 - .../run-pass/deriving-via-extension-enum.rs | 1 - .../deriving-via-extension-iter-bytes-enum.rs | 1 - ...eriving-via-extension-iter-bytes-struct.rs | 2 - ...-via-extension-struct-like-enum-variant.rs | 1 - .../run-pass/deriving-via-extension-struct.rs | 1 - .../deriving-via-extension-type-params.rs | 1 - src/test/run-pass/drop-trait-generic.rs | 1 - src/test/run-pass/drop-trait.rs | 1 - .../run-pass/enum-discrim-range-overflow.rs | 24 ++++++------ src/test/run-pass/enum-disr-val-pretty.rs | 1 - src/test/run-pass/enum-export-inheritance.rs | 1 - .../enum-nullable-simplifycfg-misopt.rs | 6 +-- src/test/run-pass/explicit-self-generic.rs | 1 - .../run-pass/explicit-self-objects-box.rs | 2 - .../run-pass/explicit-self-objects-simple.rs | 2 - .../run-pass/explicit-self-objects-uniq.rs | 2 - src/test/run-pass/explicit_self_xcrate_exe.rs | 1 - src/test/run-pass/expr-repeat-vstore.rs | 1 - src/test/run-pass/extern-mod-abi.rs | 1 - src/test/run-pass/extern-mod-ordering-exe.rs | 1 - src/test/run-pass/extern-mod-syntax.rs | 1 - src/test/run-pass/extern-pass-TwoU16s.rs | 1 - src/test/run-pass/extern-pass-TwoU32s.rs | 1 - src/test/run-pass/extern-pass-TwoU64s-ref.rs | 1 - src/test/run-pass/extern-pass-TwoU64s.rs | 1 - src/test/run-pass/extern-pass-TwoU8s.rs | 1 - src/test/run-pass/extern-pass-char.rs | 1 - src/test/run-pass/extern-pass-double.rs | 1 - src/test/run-pass/extern-pass-u32.rs | 1 - src/test/run-pass/extern-pass-u64.rs | 1 - src/test/run-pass/extern-pub.rs | 2 - src/test/run-pass/fat-arrow-alt.rs | 1 - src/test/run-pass/fixed_length_copy.rs | 2 +- src/test/run-pass/float-literal-inference.rs | 1 - .../run-pass/fn-pattern-expected-type-2.rs | 1 - src/test/run-pass/fn-pattern-expected-type.rs | 1 - src/test/run-pass/foreign-mod-unused-const.rs | 1 - src/test/run-pass/functional-struct-update.rs | 1 - src/test/run-pass/generic-ivec-leak.rs | 1 - src/test/run-pass/generic-ivec.rs | 1 - src/test/run-pass/generic-newtype-struct.rs | 1 - src/test/run-pass/generic-object.rs | 1 - src/test/run-pass/global-scope.rs | 1 - src/test/run-pass/impl-privacy-xc-1.rs | 1 - src/test/run-pass/impl-privacy-xc-2.rs | 1 - src/test/run-pass/infinite-loops.rs | 4 +- src/test/run-pass/instantiable.rs | 1 - src/test/run-pass/int-conversion-coherence.rs | 1 - src/test/run-pass/intrinsics-integer.rs | 2 +- src/test/run-pass/intrinsics-math.rs | 4 +- src/test/run-pass/issue-1516.rs | 1 - src/test/run-pass/issue-2185.rs | 4 +- src/test/run-pass/issue-2216.rs | 2 +- src/test/run-pass/issue-2526-a.rs | 1 - src/test/run-pass/issue-2734.rs | 4 +- src/test/run-pass/issue-2904.rs | 2 +- src/test/run-pass/issue-3176.rs | 4 +- src/test/run-pass/issue-3250.rs | 2 - src/test/run-pass/issue-3429.rs | 1 - src/test/run-pass/issue-3461.rs | 2 +- src/test/run-pass/issue-3556.rs | 8 ++-- src/test/run-pass/issue-3563-3.rs | 5 +-- src/test/run-pass/issue-3609.rs | 1 - src/test/run-pass/issue-3860.rs | 2 +- src/test/run-pass/issue-3895.rs | 2 +- src/test/run-pass/issue-3979-2.rs | 1 - src/test/run-pass/issue-4241.rs | 2 +- src/test/run-pass/issue-4875.rs | 1 - src/test/run-pass/issue-868.rs | 1 - src/test/run-pass/issue_3136_b.rs | 1 - src/test/run-pass/ivec-add.rs | 1 - src/test/run-pass/ivec-pass-by-value.rs | 1 - src/test/run-pass/labeled-break.rs | 1 - src/test/run-pass/let-assignability.rs | 1 - .../liveness-assign-imm-local-after-loop.rs | 2 +- src/test/run-pass/log-linearized.rs | 1 - src/test/run-pass/max-min-classes.rs | 1 - .../module-qualified-struct-destructure.rs | 1 - src/test/run-pass/move-self.rs | 1 - .../moves-based-on-type-capture-clause.rs | 1 - src/test/run-pass/multiple-trait-bounds.rs | 1 - src/test/run-pass/mut-vstore-expr.rs | 1 - src/test/run-pass/nested-class.rs | 22 +++++------ src/test/run-pass/new-impl-syntax.rs | 1 - src/test/run-pass/new-import-syntax.rs | 1 - src/test/run-pass/new-style-constants.rs | 1 - .../run-pass/new-style-fixed-length-vec.rs | 3 -- .../run-pass/new-vstore-mut-box-syntax.rs | 1 - src/test/run-pass/newtype-struct-with-dtor.rs | 2 - src/test/run-pass/newtype-struct-xc-2.rs | 1 - src/test/run-pass/newtype-struct-xc.rs | 1 - .../nullable-pointer-iotareduction.rs | 2 +- src/test/run-pass/one-tuple.rs | 1 - src/test/run-pass/pattern-in-closure.rs | 1 - src/test/run-pass/pipe-detect-term.rs | 4 +- src/test/run-pass/pipe-pingpong-bounded.rs | 2 +- src/test/run-pass/pipe-pingpong-proto.rs | 2 +- src/test/run-pass/pipe-select.rs | 6 +-- src/test/run-pass/pipe-sleep.rs | 2 +- src/test/run-pass/pub-use-xcrate.rs | 1 - src/test/run-pass/pub_use_mods_xcrate_exe.rs | 1 - src/test/run-pass/reexport-star.rs | 1 - .../regions-addr-of-interior-of-unique-box.rs | 1 - src/test/run-pass/regions-addr-of-ret.rs | 1 - src/test/run-pass/regions-fn-subtyping-2.rs | 4 +- .../regions-infer-borrow-scope-addr-of.rs | 16 ++++---- .../regions-infer-borrow-scope-view.rs | 1 - ...gions-infer-borrow-scope-within-loop-ok.rs | 2 +- .../run-pass/regions-infer-borrow-scope.rs | 1 - src/test/run-pass/regions-mock-trans-impls.rs | 1 - src/test/run-pass/regions-mock-trans.rs | 1 - src/test/run-pass/regions-self-impls.rs | 1 - src/test/run-pass/regions-self-in-enums.rs | 1 - src/test/run-pass/regions-simple.rs | 2 - src/test/run-pass/repeated-vector-syntax.rs | 1 - src/test/run-pass/resource-cycle.rs | 4 +- src/test/run-pass/resource-cycle3.rs | 4 +- src/test/run-pass/self-type-param.rs | 1 - src/test/run-pass/static-methods-in-traits.rs | 37 +++++++++---------- src/test/run-pass/struct-deref.rs | 1 - .../run-pass/struct-field-assignability.rs | 1 - .../run-pass/struct-like-variant-construct.rs | 1 - .../run-pass/struct-like-variant-match.rs | 1 - src/test/run-pass/struct-pattern-matching.rs | 3 -- src/test/run-pass/super.rs | 1 - src/test/run-pass/tag-disr-val-shape.rs | 1 - src/test/run-pass/tag-variant-disr-val.rs | 2 - src/test/run-pass/threads.rs | 1 - .../run-pass/trait-composition-trivial.rs | 2 - .../run-pass/trait-inheritance-auto-xc-2.rs | 1 - .../run-pass/trait-inheritance-auto-xc.rs | 1 - src/test/run-pass/trait-inheritance-auto.rs | 1 - .../trait-inheritance-call-bound-inherited.rs | 1 - ...trait-inheritance-call-bound-inherited2.rs | 1 - ...ritance-cast-without-call-to-supertrait.rs | 1 - src/test/run-pass/trait-inheritance-cast.rs | 1 - .../trait-inheritance-cross-trait-call-xc.rs | 1 - .../trait-inheritance-cross-trait-call.rs | 1 - .../trait-inheritance-overloading-simple.rs | 1 - .../trait-inheritance-overloading-xc-exe.rs | 1 - .../run-pass/trait-inheritance-overloading.rs | 1 - src/test/run-pass/trait-inheritance-self.rs | 1 - src/test/run-pass/trait-inheritance-simple.rs | 1 - src/test/run-pass/trait-inheritance-subst.rs | 1 - src/test/run-pass/trait-inheritance-subst2.rs | 1 - src/test/run-pass/trait-inheritance2.rs | 1 - .../run-pass/trait-region-pointer-simple.rs | 1 - .../trait-static-method-overwriting.rs | 6 +-- src/test/run-pass/traits.rs | 1 - src/test/run-pass/tuple-struct-construct.rs | 1 - .../run-pass/tuple-struct-destructuring.rs | 1 - src/test/run-pass/tuple-struct-matching.rs | 1 - src/test/run-pass/tuple-struct-trivial.rs | 1 - .../run-pass/typeclasses-eq-example-static.rs | 2 +- src/test/run-pass/typeclasses-eq-example.rs | 2 +- src/test/run-pass/unique-object.rs | 1 - src/test/run-pass/unit-like-struct.rs | 1 - .../run-pass/unsafe-pointer-assignability.rs | 3 -- src/test/run-pass/vec-fixed-length.rs | 1 - 433 files changed, 196 insertions(+), 597 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000..52370e4a509b0 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,9 @@ +[attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4 + +* text=auto +*.cpp rust +*.h rust +*.rs rust +src/rt/msvc/* -whitespace +src/rt/vg/* -whitespace +src/rt/linenoise/* -whitespace diff --git a/COPYRIGHT b/COPYRIGHT index 2315c6fe3cba2..ffbfadaa3391b 100644 --- a/COPYRIGHT +++ b/COPYRIGHT @@ -367,4 +367,3 @@ their own copyright notices and license terms: has chosen for the collective work, enumerated at the top of this file. The only difference is the retention of copyright itself, held by the contributor. - diff --git a/RELEASES.txt b/RELEASES.txt index 13e4e0c2039cc..fb2bbb45e7c83 100644 --- a/RELEASES.txt +++ b/RELEASES.txt @@ -250,7 +250,7 @@ Version 0.3 (July 2012) * Slices and fixed-size, interior-allocated vectors * #!-comments for lang versioning, shell execution * Destructors and iface implementation for classes; - type-parameterized classes and class methods + type-parameterized classes and class methods * 'const' type kind for types that can be used to implement shared-memory concurrency patterns @@ -261,7 +261,7 @@ Version 0.3 (July 2012) 'crust', 'native' (now 'extern'), 'cont' (now 'again') * Constructs: do-while loops ('do' repurposed), fn binding, - resources (replaced by destructors) + resources (replaced by destructors) * Compiler reorganization * Syntax-layer of compiler split into separate crate @@ -276,7 +276,7 @@ Version 0.3 (July 2012) * Extensive work on libuv interface * Much vector code moved to libraries * Syntax extensions: #line, #col, #file, #mod, #stringify, - #include, #include_str, #include_bin + #include, #include_str, #include_bin * Tool improvements * Cargo automatically resolves dependencies diff --git a/doc/README b/doc/README index 505b5383dcd80..c3bb28a9e85e9 100644 --- a/doc/README +++ b/doc/README @@ -1,6 +1,6 @@ The markdown docs are only generated by make when node is installed (use -`make doc`). If you don't have node installed you can generate them yourself. -Unfortunately there's no real standard for markdown and all the tools work +`make doc`). If you don't have node installed you can generate them yourself. +Unfortunately there's no real standard for markdown and all the tools work differently. pandoc is one that seems to work well. To generate an html version of a doc do something like: @@ -10,4 +10,4 @@ The syntax for pandoc flavored markdown can be found at: http://johnmacfarlane.net/pandoc/README.html#pandocs-markdown A nice quick reference (for non-pandoc markdown) is at: -http://kramdown.rubyforge.org/quickref.html \ No newline at end of file +http://kramdown.rubyforge.org/quickref.html diff --git a/doc/rust.md b/doc/rust.md index e23613e149ce7..ac7125be424d4 100644 --- a/doc/rust.md +++ b/doc/rust.md @@ -3351,4 +3351,3 @@ Additional specific influences can be seen from the following languages: * The typeclass system of Haskell. * The lexical identifier rule of Python. * The block syntax of Ruby. - diff --git a/doc/tutorial-macros.md b/doc/tutorial-macros.md index 24e9f4abc38e6..63fa7e06bae77 100644 --- a/doc/tutorial-macros.md +++ b/doc/tutorial-macros.md @@ -402,4 +402,3 @@ tricky. Invoking the `log_syntax!` macro can help elucidate intermediate states, invoking `trace_macros!(true)` will automatically print those intermediate states out, and passing the flag `--pretty expanded` as a command-line argument to the compiler will show the result of expansion. - diff --git a/doc/tutorial-tasks.md b/doc/tutorial-tasks.md index bed696748306e..053d9e6d98813 100644 --- a/doc/tutorial-tasks.md +++ b/doc/tutorial-tasks.md @@ -511,4 +511,3 @@ The parent task first calls `DuplexStream` to create a pair of bidirectional endpoints. It then uses `task::spawn` to create the child task, which captures one end of the communication channel. As a result, both parent and child can send and receive data to and from the other. - diff --git a/doc/tutorial.md b/doc/tutorial.md index 07eb3bc7681d7..90ae41affc9b9 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -1006,9 +1006,9 @@ let mut d = @mut 5; // mutable variable, mutable box d = @mut 15; ~~~~ -A mutable variable and an immutable variable can refer to the same box, given -that their types are compatible. Mutability of a box is a property of its type, -however, so for example a mutable handle to an immutable box cannot be +A mutable variable and an immutable variable can refer to the same box, given +that their types are compatible. Mutability of a box is a property of its type, +however, so for example a mutable handle to an immutable box cannot be assigned a reference to a mutable box. ~~~~ @@ -1041,7 +1041,7 @@ let y = x.clone(); // y is a newly allocated box let z = x; // no new memory allocated, x can no longer be used ~~~~ -Since in owned boxes mutability is a property of the owner, not the +Since in owned boxes mutability is a property of the owner, not the box, mutable boxes may become immutable when they are moved, and vice-versa. ~~~~ diff --git a/doc/version_info.html.template b/doc/version_info.html.template index 9376b29bcdf63..aa44097a337e9 100644 --- a/doc/version_info.html.template +++ b/doc/version_info.html.template @@ -7,4 +7,3 @@ - diff --git a/mk/platform.mk b/mk/platform.mk index 1e102587bf4a0..e03b7c152478f 100644 --- a/mk/platform.mk +++ b/mk/platform.mk @@ -11,7 +11,7 @@ # Create variables HOST_ containing the host part # of each target triple. For example, the triple i686-darwin-macos -# would create a variable HOST_i686-darwin-macos with the value +# would create a variable HOST_i686-darwin-macos with the value # i386. define DEF_HOST_VAR HOST_$(1) = $(subst i686,i386,$(word 1,$(subst -, ,$(1)))) @@ -276,8 +276,8 @@ CFG_GCCISH_CFLAGS_i686-pc-mingw32 := -Wall -Werror -g -march=i686 CFG_GCCISH_CXXFLAGS_i686-pc-mingw32 := -fno-rtti CFG_GCCISH_LINK_FLAGS_i686-pc-mingw32 := -shared -fPIC -g CFG_GCCISH_DEF_FLAG_i686-pc-mingw32 := -CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-mingw32 := -CFG_GCCISH_POST_LIB_FLAGS_i686-pc-mingw32 := +CFG_GCCISH_PRE_LIB_FLAGS_i686-pc-mingw32 := +CFG_GCCISH_POST_LIB_FLAGS_i686-pc-mingw32 := CFG_DEF_SUFFIX_i686-pc-mingw32 := .mingw32.def CFG_INSTALL_NAME_i686-pc-mingw32 = CFG_LIBUV_LINK_FLAGS_i686-pc-mingw32 := -lWs2_32 -lpsapi -liphlpapi diff --git a/mk/rt.mk b/mk/rt.mk index c4c80b99fc085..30dda2fb276c9 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -1,27 +1,27 @@ # This is a procedure to define the targets for building -# the runtime. +# the runtime. # # Argument 1 is the target triple. # # This is not really the right place to explain this, but # for those of you who are not Makefile gurus, let me briefly -# cover the $ expansion system in use here, because it +# cover the $ expansion system in use here, because it # confused me for a while! The variable DEF_RUNTIME_TARGETS # will be defined once and then expanded with different # values substituted for $(1) each time it is called. -# That resulting text is then eval'd. +# That resulting text is then eval'd. # # For most variables, you could use a single $ sign. The result # is that the substitution would occur when the CALL occurs, # I believe. The problem is that the automatic variables $< and $@ # need to be expanded-per-rule. Therefore, for those variables at -# least, you need $$< and $$@ in the variable text. This way, after +# least, you need $$< and $$@ in the variable text. This way, after # the CALL substitution occurs, you will have $< and $@. This text # will then be evaluated, and all will work as you like. # # Reader beware, this explanantion could be wrong, but it seems to -# fit the experimental data (i.e., I was able to get the system -# working under these assumptions). +# fit the experimental data (i.e., I was able to get the system +# working under these assumptions). # Hack for passing flags into LIBUV, see below. LIBUV_FLAGS_i386 = -m32 -fPIC diff --git a/mk/stage0.mk b/mk/stage0.mk index 7b5cbef1d72c3..ac1b3e86ac918 100644 --- a/mk/stage0.mk +++ b/mk/stage0.mk @@ -7,16 +7,16 @@ $(HBIN0_H_$(CFG_BUILD_TRIPLE))/rustc$(X_$(CFG_BUILD_TRIPLE)): \ $(S)src/etc/get-snapshot.py $(MKFILE_DEPS) @$(call E, fetch: $@) # Note: the variable "SNAPSHOT_FILE" is generally not set, and so -# we generally only pass one argument to this script. +# we generally only pass one argument to this script. ifdef CFG_ENABLE_LOCAL_RUST $(Q)$(S)src/etc/local_stage0.sh $(CFG_BUILD_TRIPLE) $(CFG_LOCAL_RUST_ROOT) -else +else $(Q)$(CFG_PYTHON) $(S)src/etc/get-snapshot.py $(CFG_BUILD_TRIPLE) $(SNAPSHOT_FILE) ifdef CFG_ENABLE_PAX_FLAGS @$(call E, apply PaX flags: $@) @"$(CFG_PAXCTL)" -cm "$@" endif -endif +endif $(Q)touch $@ # Host libs will be extracted by the above rule diff --git a/mk/tests.mk b/mk/tests.mk index f96b7325f60d4..175e33c665411 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -179,9 +179,9 @@ tidy: $(Q)find $(S)src/etc -name '*.py' \ | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py $(Q)echo $(ALL_CS) \ - | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py + | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py $(Q)echo $(ALL_HS) \ - | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py + | xargs -n 10 $(CFG_PYTHON) $(S)src/etc/tidy.py endif @@ -709,4 +709,3 @@ endef $(foreach host,$(CFG_HOST_TRIPLES), \ $(eval $(call DEF_CHECK_FAST_FOR_H,$(host)))) - diff --git a/src/etc/check-links.pl b/src/etc/check-links.pl index a280ed55ba93f..6492be53d3481 100755 --- a/src/etc/check-links.pl +++ b/src/etc/check-links.pl @@ -9,7 +9,7 @@ my $i = 0; foreach $line (@lines) { $i++; - if ($line =~ m/id="([^"]+)"/) { + if ($line =~ m/id="([^"]+)"/) { $anchors->{$1} = $i; } } @@ -17,10 +17,9 @@ $i = 0; foreach $line (@lines) { $i++; - while ($line =~ m/href="#([^"]+)"/g) { + while ($line =~ m/href="#([^"]+)"/g) { if (! exists($anchors->{$1})) { print "$file:$i: $1 referenced\n"; } } } - diff --git a/src/etc/gedit/readme.txt b/src/etc/gedit/readme.txt index 735b023627662..e394f1916088f 100644 --- a/src/etc/gedit/readme.txt +++ b/src/etc/gedit/readme.txt @@ -8,4 +8,3 @@ Instructions for Ubuntu Linux 12.04+ 2) Copy the included "share" folder into "~/.local/" 3) Open a shell in "~/.local/share/" and run "update-mime-database mime" - diff --git a/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang b/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang index 0b23808b76524..a413d0a906222 100644 --- a/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang +++ b/src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang @@ -123,11 +123,11 @@ mode_t ssize_t - + self - + true false @@ -261,4 +261,3 @@ - diff --git a/src/etc/gedit/share/mime/packages/rust.xml b/src/etc/gedit/share/mime/packages/rust.xml index 65168aae1d909..d75cffe960073 100644 --- a/src/etc/gedit/share/mime/packages/rust.xml +++ b/src/etc/gedit/share/mime/packages/rust.xml @@ -2,6 +2,6 @@ Rust Source - + diff --git a/src/etc/indenter b/src/etc/indenter index 017cb926981fb..1a3a446533572 100755 --- a/src/etc/indenter +++ b/src/etc/indenter @@ -14,4 +14,3 @@ while (<>) { $indent -= 1; } } - diff --git a/src/etc/latest-unix-snaps.py b/src/etc/latest-unix-snaps.py index 7a2ddba3a16aa..7cecf83716160 100755 --- a/src/etc/latest-unix-snaps.py +++ b/src/etc/latest-unix-snaps.py @@ -52,5 +52,3 @@ def download_new_file (date, rev, platform, hsh): for ff in newestSet["files"]: download_new_file (newestSet["date"], newestSet["rev"], ff["platform"], ff["hash"]) - - diff --git a/src/etc/libc.c b/src/etc/libc.c index 9acc122f32b99..e341f495eebb9 100644 --- a/src/etc/libc.c +++ b/src/etc/libc.c @@ -243,4 +243,3 @@ int main() { extra_consts(); printf("}\n"); } - diff --git a/src/etc/licenseck.py b/src/etc/licenseck.py index 973b7deb960db..1e0c541cd8927 100644 --- a/src/etc/licenseck.py +++ b/src/etc/licenseck.py @@ -96,4 +96,3 @@ def check_license(name, contents): return True return False - diff --git a/src/etc/local_stage0.sh b/src/etc/local_stage0.sh index 5898bc561aac3..8d2fd887e3ff7 100755 --- a/src/etc/local_stage0.sh +++ b/src/etc/local_stage0.sh @@ -1,13 +1,13 @@ #!/bin/sh -TARG_DIR=$1 +TARG_DIR=$1 PREFIX=$2 BINDIR=bin LIBDIR=lib OS=`uname -s` -case $OS in +case $OS in ("Linux"|"FreeBSD") BIN_SUF= LIB_SUF=.so diff --git a/src/etc/mirror-all-snapshots.py b/src/etc/mirror-all-snapshots.py index f1fce7a94b5b6..3b5f66c411730 100644 --- a/src/etc/mirror-all-snapshots.py +++ b/src/etc/mirror-all-snapshots.py @@ -33,6 +33,3 @@ print("got download with ok hash") else: raise Exception("bad hash on download") - - - diff --git a/src/etc/monodebug.pl b/src/etc/monodebug.pl index 324c576a4bda8..a2d27591cad93 100755 --- a/src/etc/monodebug.pl +++ b/src/etc/monodebug.pl @@ -77,4 +77,3 @@ } print "\n"; } - diff --git a/src/etc/sugarise-doc-comments.py b/src/etc/sugarise-doc-comments.py index 6399cff6b880d..7bd4175fbf0db 100755 --- a/src/etc/sugarise-doc-comments.py +++ b/src/etc/sugarise-doc-comments.py @@ -80,4 +80,3 @@ def sugarise_file(path): for (dirpath, dirnames, filenames) in os.walk('.'): for name in fnmatch.filter(filenames, '*.r[sc]'): sugarise_file(os.path.join(dirpath, name)) - diff --git a/src/etc/tidy.py b/src/etc/tidy.py index a5cf6141567be..06fcb5cb94586 100644 --- a/src/etc/tidy.py +++ b/src/etc/tidy.py @@ -81,4 +81,3 @@ def do_license_check(name, contents): sys.exit(err) - diff --git a/src/etc/x86.supp b/src/etc/x86.supp index 417f4c9d2c199..def1c5a53c1fd 100644 --- a/src/etc/x86.supp +++ b/src/etc/x86.supp @@ -366,7 +366,7 @@ ... } -{ +{ llvm-user-new-leak Memcheck:Leak fun:_Znwj @@ -401,7 +401,7 @@ Helgrind:Race fun:_ZN15lock_and_signal27lock_held_by_current_threadEv ... -} +} { lock_and_signal-probably-threadsafe-access-outside-of-lock2 diff --git a/src/libcore/cleanup.rs b/src/libcore/cleanup.rs index a07c6b4811b6c..bf92d605f2b24 100644 --- a/src/libcore/cleanup.rs +++ b/src/libcore/cleanup.rs @@ -226,4 +226,3 @@ pub mod rustrt { pub unsafe fn rust_get_task() -> *c_void; } } - diff --git a/src/libcore/logging.rs b/src/libcore/logging.rs index ba976de50ab48..afe8338f2ce6a 100644 --- a/src/libcore/logging.rs +++ b/src/libcore/logging.rs @@ -59,4 +59,3 @@ pub fn log_type(level: u32, object: &T) { rustrt::rust_log_str(level, transmute(vec::raw::to_ptr(bytes)), len); } } - diff --git a/src/libcore/owned.rs b/src/libcore/owned.rs index c483ec79e21d9..599591e2f6d7a 100644 --- a/src/libcore/owned.rs +++ b/src/libcore/owned.rs @@ -31,4 +31,3 @@ impl Ord for ~T { #[inline(always)] fn gt(&self, other: &~T) -> bool { *(*self) > *(*other) } } - diff --git a/src/libcore/rt/context.rs b/src/libcore/rt/context.rs index 4714be9e3d520..9c1e566f218f6 100644 --- a/src/libcore/rt/context.rs +++ b/src/libcore/rt/context.rs @@ -207,4 +207,3 @@ pub fn mut_offset(ptr: *mut T, count: int) -> *mut T { use core::sys::size_of; (ptr as int + count * (size_of::() as int)) as *mut T } - diff --git a/src/libcore/rt/io/comm_adapters.rs b/src/libcore/rt/io/comm_adapters.rs index 1d6893b3ca616..7e891f1718e21 100644 --- a/src/libcore/rt/io/comm_adapters.rs +++ b/src/libcore/rt/io/comm_adapters.rs @@ -56,4 +56,3 @@ impl WriterChan { impl GenericChan<~[u8]> for WriterChan { fn send(&self, _x: ~[u8]) { fail!() } } - diff --git a/src/libcore/rt/io/net/ip.rs b/src/libcore/rt/io/net/ip.rs index d9b7f4e6e4011..df1dfe4d38ad1 100644 --- a/src/libcore/rt/io/net/ip.rs +++ b/src/libcore/rt/io/net/ip.rs @@ -12,4 +12,3 @@ pub enum IpAddr { Ipv4(u8, u8, u8, u8, u16), Ipv6 } - diff --git a/src/libcore/rt/io/net/udp.rs b/src/libcore/rt/io/net/udp.rs index 0cb2978fb1a68..1f1254a7029f0 100644 --- a/src/libcore/rt/io/net/udp.rs +++ b/src/libcore/rt/io/net/udp.rs @@ -47,4 +47,3 @@ impl UdpListener { impl Listener for UdpListener { fn accept(&mut self) -> Option { fail!() } } - diff --git a/src/libcore/rt/io/net/unix.rs b/src/libcore/rt/io/net/unix.rs index 262816beecc98..f449a857467cc 100644 --- a/src/libcore/rt/io/net/unix.rs +++ b/src/libcore/rt/io/net/unix.rs @@ -47,4 +47,3 @@ impl UnixListener { impl Listener for UnixListener { fn accept(&mut self) -> Option { fail!() } } - diff --git a/src/libcore/rt/local_heap.rs b/src/libcore/rt/local_heap.rs index fbd4a77d79b98..6bf228a1b2201 100644 --- a/src/libcore/rt/local_heap.rs +++ b/src/libcore/rt/local_heap.rs @@ -78,4 +78,3 @@ extern { size: size_t) -> *OpaqueBox; fn rust_boxed_region_free(region: *BoxedRegion, box: *OpaqueBox); } - diff --git a/src/libcore/rt/sched/local_sched.rs b/src/libcore/rt/sched/local_sched.rs index 2d1e06163beb8..a7e02f30e0167 100644 --- a/src/libcore/rt/sched/local_sched.rs +++ b/src/libcore/rt/sched/local_sched.rs @@ -143,4 +143,3 @@ fn borrow_smoke_test() { } let _scheduler = take(); } - diff --git a/src/libcore/stackwalk.rs b/src/libcore/stackwalk.rs index ebf36e4e09ab4..272bdca8654f1 100644 --- a/src/libcore/stackwalk.rs +++ b/src/libcore/stackwalk.rs @@ -99,4 +99,3 @@ pub mod rusti { pub fn frame_address(+f: &once fn(x: *u8)); } } - diff --git a/src/libcore/unicode.rs b/src/libcore/unicode.rs index 34175f9888ffa..d6e2c5eee6aca 100644 --- a/src/libcore/unicode.rs +++ b/src/libcore/unicode.rs @@ -2642,4 +2642,3 @@ pub mod derived_property { bsearch_range_table(c, XID_Start_table) } } - diff --git a/src/libcore/unstable/exchange_alloc.rs b/src/libcore/unstable/exchange_alloc.rs index 8ca5486d92992..57ed579e88dda 100644 --- a/src/libcore/unstable/exchange_alloc.rs +++ b/src/libcore/unstable/exchange_alloc.rs @@ -81,4 +81,3 @@ extern { #[rust_stack] fn rust_get_exchange_count_ptr() -> *mut int; } - diff --git a/src/libcore/unstable/weak_task.rs b/src/libcore/unstable/weak_task.rs index 7a30bb92111b1..6edbdcb51b0cb 100644 --- a/src/libcore/unstable/weak_task.rs +++ b/src/libcore/unstable/weak_task.rs @@ -205,4 +205,3 @@ fn test_select_stream_and_oneshot() { chan.send(()); waitport.recv(); } - diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index 111c201d5023c..d2b71447f4778 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -169,4 +169,3 @@ pub struct LinkMeta { vers: @str, extras_hash: @str } - diff --git a/src/librustc/metadata/mod.rs b/src/librustc/metadata/mod.rs index 78d5be4d4ae19..24007380feec1 100644 --- a/src/librustc/metadata/mod.rs +++ b/src/librustc/metadata/mod.rs @@ -18,4 +18,3 @@ pub mod cstore; pub mod csearch; pub mod loader; pub mod filesearch; - diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index 526a5a3a9dd4c..4ab24a17d31b2 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -802,4 +802,3 @@ fn check_loans_in_block(blk: &ast::blk, visit::visit_block(blk, self, vt); } } - diff --git a/src/librustc/middle/borrowck/gather_loans.rs b/src/librustc/middle/borrowck/gather_loans.rs index da04853411865..fd1f6f5c450af 100644 --- a/src/librustc/middle/borrowck/gather_loans.rs +++ b/src/librustc/middle/borrowck/gather_loans.rs @@ -639,4 +639,3 @@ fn add_stmt_to_map(stmt: @ast::stmt, } visit::visit_stmt(stmt, self, vt); } - diff --git a/src/librustc/middle/borrowck/loan.rs b/src/librustc/middle/borrowck/loan.rs index 4dd727390aadc..641571373bda4 100644 --- a/src/librustc/middle/borrowck/loan.rs +++ b/src/librustc/middle/borrowck/loan.rs @@ -309,4 +309,3 @@ pub impl LoanContext { } } } - diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 7298064e1c00d..f6d138a4a699e 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -423,4 +423,3 @@ pub fn collect_language_items(crate: @crate, collector.collect(); copy items } - diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 866bd5377b9ba..29ca875806f93 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1179,4 +1179,3 @@ pub impl categorization { } } } - diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 3ca79982b7b9a..b87adb75bc37a 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -86,4 +86,3 @@ pub fn pat_binding_ids(dm: resolve::DefMap, pat: @pat) -> ~[node_id] { pat_bindings(dm, pat, |_bm, b_id, _sp, _pt| found.push(b_id) ); return found; } - diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index be98195621902..083c436c83e84 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -603,4 +603,3 @@ pub fn check_crate(tcx: ty::ctxt, }); visit::visit_crate(crate, method_map, visitor); } - diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 4faa2150003f0..753a6d25cbb3d 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -968,4 +968,3 @@ pub fn determine_rp_in_crate(sess: Session, // return final set return cx.region_paramd_items; } - diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index c3a79373931a2..bf64134704a4c 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -186,4 +186,3 @@ impl Subst for ty::ty_param_bounds_and_ty { } } } - diff --git a/src/librustc/middle/trans/cabi.rs b/src/librustc/middle/trans/cabi.rs index ed028d14bd65f..d49e8e0969a1f 100644 --- a/src/librustc/middle/trans/cabi.rs +++ b/src/librustc/middle/trans/cabi.rs @@ -190,4 +190,3 @@ pub impl FnType { Store(bcx, llretval, llretptr); } } - diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index ed7f91bf04a6b..fc645e2bb6cd4 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -799,4 +799,3 @@ pub fn trans_arg_expr(bcx: block, debug!("--- trans_arg_expr passing %s", val_str(bcx.ccx().tn, val)); return rslt(bcx, val); } - diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index e35fef6b6f66a..84100d7195ea0 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -599,4 +599,3 @@ pub fn make_opaque_cbox_free_glue( } } } - diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 113136fa58d13..c9a4f078c79db 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -398,4 +398,3 @@ pub fn trans_fail_bounds_check(bcx: block, sp: span, Unreachable(bcx); return bcx; } - diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index cf5fbb6e216ec..c6b32930c5f71 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -855,4 +855,3 @@ pub impl DatumBlock { self.datum.to_str(self.ccx()) } } - diff --git a/src/librustc/middle/trans/inline.rs b/src/librustc/middle/trans/inline.rs index ad06a9715b4af..35136410268ff 100644 --- a/src/librustc/middle/trans/inline.rs +++ b/src/librustc/middle/trans/inline.rs @@ -122,4 +122,3 @@ pub fn maybe_instantiate_inline(ccx: @CrateContext, fn_id: ast::def_id, } } } - diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs index 3ae2421a55589..b1349104e5490 100644 --- a/src/librustc/middle/trans/machine.rs +++ b/src/librustc/middle/trans/machine.rs @@ -153,4 +153,3 @@ pub fn static_size_of_enum(cx: @CrateContext, t: ty::t) -> uint { _ => cx.sess.bug(~"static_size_of_enum called on non-enum") } } - diff --git a/src/librustc/middle/trans/macros.rs b/src/librustc/middle/trans/macros.rs index 14ed7692661d4..43cc66c556867 100644 --- a/src/librustc/middle/trans/macros.rs +++ b/src/librustc/middle/trans/macros.rs @@ -51,4 +51,3 @@ macro_rules! trace( } ) ) - diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs index f301a7d297342..217eda870be9f 100644 --- a/src/librustc/middle/trans/reachable.rs +++ b/src/librustc/middle/trans/reachable.rs @@ -242,4 +242,3 @@ fn traverse_all_resources_and_impls(cx: &ctx, crate_mod: &_mod) { ..*visit::default_visitor() })); } - diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 7e59f580a2c3c..9bae056091852 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -404,4 +404,3 @@ pub fn ast_purity_constant(purity: ast::purity) -> uint { ast::extern_fn => 3u } } - diff --git a/src/librustc/middle/trans/shape.rs b/src/librustc/middle/trans/shape.rs index 08337c918b0f5..6ff9e1cfc5717 100644 --- a/src/librustc/middle/trans/shape.rs +++ b/src/librustc/middle/trans/shape.rs @@ -74,4 +74,3 @@ pub fn add_substr(dest: &mut ~[u8], src: ~[u8]) { add_u16(&mut *dest, vec::len(src) as u16); *dest += src; } - diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index e19eba6ca98f9..794912d8307bc 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -383,4 +383,3 @@ pub fn handle_body(cx: Context, body: &blk) { }); (v.visit_block)(body, cx, v); } - diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index de384d02dc3bc..8eadf3acc98fe 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -633,4 +633,3 @@ pub fn check_pointer_pat(pcx: &pat_ctxt, #[deriving(Eq)] enum PointerKind { Managed, Owned, Borrowed } - diff --git a/src/librustc/middle/typeck/check/demand.rs b/src/librustc/middle/typeck/check/demand.rs index 1bb71c156c3dc..3fa551e4b057a 100644 --- a/src/librustc/middle/typeck/check/demand.rs +++ b/src/librustc/middle/typeck/check/demand.rs @@ -66,5 +66,3 @@ pub fn coerce(fcx: @mut FnCtxt, } } } - - diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 532638faa68c7..7f390de1f4943 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -666,5 +666,3 @@ pub fn resolve_in_block(fcx: @mut FnCtxt, bl: &ast::blk) { .. *visit::default_visitor() })); } - - diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index 7fff756b01da5..fe07dc9412db2 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -1119,4 +1119,3 @@ pub fn check_coherence(crate_context: @mut CrateCtxt, crate: @crate) { let coherence_checker = @CoherenceChecker(crate_context); coherence_checker.check_coherence(crate); } - diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index de3ffcd63ab7c..362104e98b0bd 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -635,4 +635,3 @@ pub fn super_trait_refs( }) } } - diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs index 2bbcd24595cba..dc1e3e845df4e 100644 --- a/src/librustc/middle/typeck/infer/glb.rs +++ b/src/librustc/middle/typeck/infer/glb.rs @@ -313,4 +313,3 @@ impl Combine for Glb { super_trait_refs(self, a, b) } } - diff --git a/src/librustc/middle/typeck/infer/macros.rs b/src/librustc/middle/typeck/infer/macros.rs index e02772d951c55..306f124be3c8f 100644 --- a/src/librustc/middle/typeck/infer/macros.rs +++ b/src/librustc/middle/typeck/infer/macros.rs @@ -18,4 +18,3 @@ macro_rules! if_ok( } ) ) - diff --git a/src/librustc/middle/typeck/infer/region_inference.rs b/src/librustc/middle/typeck/infer/region_inference.rs index 25e65d7a18bca..1ee59c3fe0649 100644 --- a/src/librustc/middle/typeck/infer/region_inference.rs +++ b/src/librustc/middle/typeck/infer/region_inference.rs @@ -1746,4 +1746,3 @@ fn iterate_until_fixed_point( } debug!("---- %s Complete after %u iteration(s)", tag, iteration); } - diff --git a/src/librustc/middle/typeck/infer/resolve.rs b/src/librustc/middle/typeck/infer/resolve.rs index 9b648f6a05341..2b88825c49a69 100644 --- a/src/librustc/middle/typeck/infer/resolve.rs +++ b/src/librustc/middle/typeck/infer/resolve.rs @@ -278,4 +278,3 @@ pub impl ResolveState { } } } - diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs index 266d157c4d040..48d7765f88ec9 100644 --- a/src/librustc/middle/typeck/infer/sub.rs +++ b/src/librustc/middle/typeck/infer/sub.rs @@ -269,4 +269,3 @@ impl Combine for Sub { super_trait_refs(self, a, b) } } - diff --git a/src/librustc/middle/typeck/infer/unify.rs b/src/librustc/middle/typeck/infer/unify.rs index bc13074422450..e50f2089e4fb5 100644 --- a/src/librustc/middle/typeck/infer/unify.rs +++ b/src/librustc/middle/typeck/infer/unify.rs @@ -265,5 +265,3 @@ impl SimplyUnifiable for ast::float_ty { return ty::terr_float_mismatch(err); } } - - diff --git a/src/librustdoc/path_pass.rs b/src/librustdoc/path_pass.rs index 629c6955566f5..5560f21af61db 100644 --- a/src/librustdoc/path_pass.rs +++ b/src/librustdoc/path_pass.rs @@ -112,4 +112,3 @@ fn should_record_fn_paths() { assert!(doc.cratemod().mods()[0].fns()[0].path() == ~[~"a"]); } } - diff --git a/src/librustpkg/testsuite/pass/commands.txt b/src/librustpkg/testsuite/pass/commands.txt index e1a1b2462b253..baeaef1e3c791 100644 --- a/src/librustpkg/testsuite/pass/commands.txt +++ b/src/librustpkg/testsuite/pass/commands.txt @@ -32,4 +32,3 @@ Commands that should succeed: 15. `rustpkg test foo` runs tests and prints their output, if foo contains #[test]s. 16. If foo is installed, `rustpkg uninstall foo; rustpkg list` doesn't include foo in the list - diff --git a/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs b/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs index 41041ccb50912..62785c06db31a 100644 --- a/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs +++ b/src/librustpkg/testsuite/pass/src/deeply/nested/path/foo/src/main.rs @@ -15,4 +15,3 @@ The test runner should check that, after `rustpkg install deeply/nested/path/foo */ fn main() {} - diff --git a/src/libstd/num/bigint.rs b/src/libstd/num/bigint.rs index 497ce7f41aae3..cd347098e2511 100644 --- a/src/libstd/num/bigint.rs +++ b/src/libstd/num/bigint.rs @@ -1957,4 +1957,3 @@ mod bigint_tests { assert!(-Zero::zero::() == Zero::zero::()); } } - diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index 33efb2c6a5af4..39fb5a45d7e9c 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -1883,4 +1883,3 @@ impl DecoderHelpers for D { } } } - diff --git a/src/libstd/task_pool.rs b/src/libstd/task_pool.rs index 820536027552b..661247df1c144 100644 --- a/src/libstd/task_pool.rs +++ b/src/libstd/task_pool.rs @@ -100,4 +100,3 @@ fn test_task_pool() { pool.execute(|i| io::println(fmt!("Hello from thread %u!", *i))); } } - diff --git a/src/libsyntax/ext/pipes/check.rs b/src/libsyntax/ext/pipes/check.rs index c2c0c06342bae..38e43d1ade562 100644 --- a/src/libsyntax/ext/pipes/check.rs +++ b/src/libsyntax/ext/pipes/check.rs @@ -80,4 +80,3 @@ impl proto::visitor<(), (), ()> for @ext_ctxt { } } } - diff --git a/src/libsyntax/ext/pipes/liveness.rs b/src/libsyntax/ext/pipes/liveness.rs index 4597dab89cbfe..18faab8c88d70 100644 --- a/src/libsyntax/ext/pipes/liveness.rs +++ b/src/libsyntax/ext/pipes/liveness.rs @@ -104,4 +104,3 @@ pub fn analyze(proto: protocol, _cx: @ext_ctxt) { proto.bounded = Some(true); } } - diff --git a/src/libsyntax/ext/pipes/mod.rs b/src/libsyntax/ext/pipes/mod.rs index 81b2442ea8257..85c578bc2ce1a 100644 --- a/src/libsyntax/ext/pipes/mod.rs +++ b/src/libsyntax/ext/pipes/mod.rs @@ -85,4 +85,3 @@ pub fn expand_proto(cx: @ext_ctxt, _sp: span, id: ast::ident, // compile base::MRItem(proto.compile(cx)) } - diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs index 79072a2f577ff..64e2f1041c1e1 100644 --- a/src/libsyntax/ext/pipes/proto.rs +++ b/src/libsyntax/ext/pipes/proto.rs @@ -217,4 +217,3 @@ pub fn visit>( }; visitor.visit_proto(proto, states) } - diff --git a/src/libsyntax/ext/quote.rs b/src/libsyntax/ext/quote.rs index f7412a4502c16..2bf4b05aa6b02 100644 --- a/src/libsyntax/ext/quote.rs +++ b/src/libsyntax/ext/quote.rs @@ -760,4 +760,3 @@ fn expand_parse_call(cx: @ext_ctxt, id_ext(cx, parse_method), arg_exprs) } - diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index c1afc53def0c2..e486a6254e76a 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -298,4 +298,3 @@ pub impl Parser { } } - diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc index a401d9eb8ace7..d00719b259095 100644 --- a/src/libsyntax/syntax.rc +++ b/src/libsyntax/syntax.rc @@ -90,4 +90,3 @@ pub mod ext { pub mod trace_macros; } - diff --git a/src/rt/arch/arm/_context.S b/src/rt/arch/arm/_context.S index 9097ebfc07004..6441f59a4d30c 100644 --- a/src/rt/arch/arm/_context.S +++ b/src/rt/arch/arm/_context.S @@ -48,5 +48,3 @@ swap_registers: msr cpsr_cxsf, r2 mov pc, lr - - diff --git a/src/rt/arch/arm/gpr.cpp b/src/rt/arch/arm/gpr.cpp index 6dd385fb33025..77ec9d5182a17 100644 --- a/src/rt/arch/arm/gpr.cpp +++ b/src/rt/arch/arm/gpr.cpp @@ -14,4 +14,3 @@ void rust_gpr::load() { LOAD(r8); LOAD(r9); LOAD(r10); LOAD(r11); LOAD(r12); LOAD(r13); LOAD(r14); LOAD(r15); } - diff --git a/src/rt/arch/arm/gpr.h b/src/rt/arch/arm/gpr.h index 49db1429903d9..c8a3e916a371c 100644 --- a/src/rt/arch/arm/gpr.h +++ b/src/rt/arch/arm/gpr.h @@ -21,4 +21,3 @@ class rust_gpr : public rust_gpr_base { }; #endif - diff --git a/src/rt/arch/arm/morestack.S b/src/rt/arch/arm/morestack.S index 4f1431a33927a..f0ec3f4b7a511 100644 --- a/src/rt/arch/arm/morestack.S +++ b/src/rt/arch/arm/morestack.S @@ -35,7 +35,7 @@ __morestack: mov r0, r4 // The amount of stack needed add r1, fp, #20 // Address of stack arguments mov r2, r5 // Size of stack arguments - + // Create new stack bl upcall_new_stack@plt @@ -64,7 +64,7 @@ __morestack: // Restore return value mov r0, r4 mov r1, r5 - + // Return pop {r6, fp, lr} mov pc, lr diff --git a/src/rt/arch/arm/record_sp.S b/src/rt/arch/arm/record_sp.S index fe680004a89aa..95fce8746a118 100644 --- a/src/rt/arch/arm/record_sp.S +++ b/src/rt/arch/arm/record_sp.S @@ -28,4 +28,3 @@ get_sp_limit: get_sp: mov r0, sp mov pc, lr - diff --git a/src/rt/arch/arm/regs.h b/src/rt/arch/arm/regs.h index 2b44bd3af357d..0d1c24e0fb749 100644 --- a/src/rt/arch/arm/regs.h +++ b/src/rt/arch/arm/regs.h @@ -19,5 +19,3 @@ # define RUSTRT_ARG1_S r1 # define RUSTRT_ARG2_S r2 # define RUSTRT_ARG3_S r3 - - diff --git a/src/rt/arch/i386/_context.S b/src/rt/arch/i386/_context.S index d2643d07c3df6..e2e4ffe35b4e4 100644 --- a/src/rt/arch/i386/_context.S +++ b/src/rt/arch/i386/_context.S @@ -63,5 +63,3 @@ SWAP_REGISTERS: // Return! jmp *48(%eax) - - diff --git a/src/rt/arch/i386/gpr.cpp b/src/rt/arch/i386/gpr.cpp index bebf801942730..e5a59d664b0d0 100644 --- a/src/rt/arch/i386/gpr.cpp +++ b/src/rt/arch/i386/gpr.cpp @@ -20,4 +20,3 @@ void rust_gpr::load() { LOAD(eax); LOAD(ebx); LOAD(ecx); LOAD(edx); LOAD(esi); LOAD(edi); LOAD(ebp); LOAD(esi); } - diff --git a/src/rt/arch/i386/gpr.h b/src/rt/arch/i386/gpr.h index 6ae53e113f4da..1953170301c53 100644 --- a/src/rt/arch/i386/gpr.h +++ b/src/rt/arch/i386/gpr.h @@ -29,4 +29,3 @@ class rust_gpr : public rust_gpr_base { }; #endif - diff --git a/src/rt/arch/i386/morestack.S b/src/rt/arch/i386/morestack.S index e8a9c1312ed2c..c1cd11fa432af 100644 --- a/src/rt/arch/i386/morestack.S +++ b/src/rt/arch/i386/morestack.S @@ -97,7 +97,7 @@ #endif .globl MORESTACK -// FIXME: What about _WIN32? +// FIXME: What about _WIN32? #if defined(__linux__) || defined(__FreeBSD__) .hidden MORESTACK #else @@ -253,4 +253,3 @@ L_upcall_del_stack$stub: .subsections_via_symbols #endif - diff --git a/src/rt/arch/mips/gpr.h b/src/rt/arch/mips/gpr.h index 4ff0729633a64..b48c1d4e732a5 100644 --- a/src/rt/arch/mips/gpr.h +++ b/src/rt/arch/mips/gpr.h @@ -30,4 +30,3 @@ class rust_gpr : public rust_gpr_base { }; #endif - diff --git a/src/rt/arch/x86_64/_context.S b/src/rt/arch/x86_64/_context.S index bedd685546756..f718cac963470 100644 --- a/src/rt/arch/x86_64/_context.S +++ b/src/rt/arch/x86_64/_context.S @@ -121,4 +121,3 @@ SWAP_REGISTERS: // Jump to the instruction pointer // found in regs: jmp *(RUSTRT_IP*8)(ARG1) - diff --git a/src/rt/arch/x86_64/gpr.cpp b/src/rt/arch/x86_64/gpr.cpp index cf43125923ade..37247d1dfdc8b 100644 --- a/src/rt/arch/x86_64/gpr.cpp +++ b/src/rt/arch/x86_64/gpr.cpp @@ -22,4 +22,3 @@ void rust_gpr::load() { LOAD(r8); LOAD(r9); LOAD(r10); LOAD(r11); LOAD(r12); LOAD(r13); LOAD(r14); LOAD(r15); } - diff --git a/src/rt/arch/x86_64/gpr.h b/src/rt/arch/x86_64/gpr.h index 75c3b081e77e8..18ef77dbba631 100644 --- a/src/rt/arch/x86_64/gpr.h +++ b/src/rt/arch/x86_64/gpr.h @@ -30,4 +30,3 @@ class rust_gpr : public rust_gpr_base { }; #endif - diff --git a/src/rt/arch/x86_64/regs.h b/src/rt/arch/x86_64/regs.h index 7d0efd1eec87c..1aca452df108b 100644 --- a/src/rt/arch/x86_64/regs.h +++ b/src/rt/arch/x86_64/regs.h @@ -43,5 +43,3 @@ # define RUSTRT_ARG4_S %r8 # define RUSTRT_ARG5_S %r9 #endif - - diff --git a/src/rt/isaac/rand.h b/src/rt/isaac/rand.h index 3da2d71b20b2d..c28b35e688d5a 100644 --- a/src/rt/isaac/rand.h +++ b/src/rt/isaac/rand.h @@ -52,5 +52,3 @@ void isaac(randctx *r); (r)->randrsl[(r)->randcnt]) #endif /* RAND */ - - diff --git a/src/rt/rust_abi.cpp b/src/rt/rust_abi.cpp index ca8448b39a152..fd1b7860b29a4 100644 --- a/src/rt/rust_abi.cpp +++ b/src/rt/rust_abi.cpp @@ -86,4 +86,3 @@ symbolicate(const std::vector &frames) { } } // end namespace stack_walk - diff --git a/src/rt/rust_abi.h b/src/rt/rust_abi.h index c56bf96291fb2..4179bf751579f 100644 --- a/src/rt/rust_abi.h +++ b/src/rt/rust_abi.h @@ -76,4 +76,3 @@ std::string symbolicate(const std::vector &frames); uint32_t get_abi_version(); #endif - diff --git a/src/rt/rust_android_dummy.h b/src/rt/rust_android_dummy.h index 95a1774894bc5..3d6c949fd3460 100644 --- a/src/rt/rust_android_dummy.h +++ b/src/rt/rust_android_dummy.h @@ -12,4 +12,3 @@ char **backtrace_symbols (void *__const *__array, int __size); void backtrace_symbols_fd (void *__const *__array, int __size, int __fd); #endif - diff --git a/src/rt/rust_debug.cpp b/src/rt/rust_debug.cpp index 5c5be45bef8b8..f403b0434b649 100644 --- a/src/rt/rust_debug.cpp +++ b/src/rt/rust_debug.cpp @@ -58,4 +58,3 @@ dump_origin(rust_task *task, void *ptr) { } } // end namespace debug - diff --git a/src/rt/rust_debug.h b/src/rt/rust_debug.h index c9aad098d38f8..7f025bb908e2a 100644 --- a/src/rt/rust_debug.h +++ b/src/rt/rust_debug.h @@ -70,4 +70,3 @@ void dump_origin(rust_task *task, void *ptr); } // end namespace debug #endif - diff --git a/src/rt/rust_gpr_base.h b/src/rt/rust_gpr_base.h index 4df6ea3e9adbc..7ec2dda9cd40c 100644 --- a/src/rt/rust_gpr_base.h +++ b/src/rt/rust_gpr_base.h @@ -31,4 +31,3 @@ class rust_gpr_base { #endif - diff --git a/src/rustllvm/README b/src/rustllvm/README index 31495f22c0a50..c0db3f68a7620 100644 --- a/src/rustllvm/README +++ b/src/rustllvm/README @@ -1,3 +1,2 @@ This directory currently contains some LLVM support code. This will generally be sent upstream to LLVM in time; for now it lives here. - diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 451a390876c6b..04e616de22334 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -120,18 +120,18 @@ void LLVMRustInitializeTargets() { LLVMInitializeX86TargetMC(); LLVMInitializeX86AsmPrinter(); LLVMInitializeX86AsmParser(); - + LLVMInitializeARMTargetInfo(); LLVMInitializeARMTarget(); LLVMInitializeARMTargetMC(); LLVMInitializeARMAsmPrinter(); - LLVMInitializeARMAsmParser(); + LLVMInitializeARMAsmParser(); LLVMInitializeMipsTargetInfo(); LLVMInitializeMipsTarget(); LLVMInitializeMipsTargetMC(); LLVMInitializeMipsAsmPrinter(); - LLVMInitializeMipsAsmParser(); + LLVMInitializeMipsAsmParser(); } // Custom memory manager for MCJITting. It needs special features @@ -438,7 +438,7 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, const char *path, TargetMachine::CodeGenFileType FileType, CodeGenOpt::Level OptLevel, - bool EnableSegmentedStacks) { + bool EnableSegmentedStacks) { LLVMRustInitializeTargets(); @@ -449,7 +449,7 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, if (!EnableARMEHABI) { int argc = 3; const char* argv[] = {"rustc", "-arm-enable-ehabi", - "-arm-enable-ehabi-descriptors"}; + "-arm-enable-ehabi-descriptors"}; cl::ParseCommandLineOptions(argc, argv); } @@ -467,8 +467,8 @@ LLVMRustWriteOutputFile(LLVMPassManagerRef PMR, const Target *TheTarget = TargetRegistry::lookupTarget(Trip, Err); TargetMachine *Target = TheTarget->createTargetMachine(Trip, CPUStr, FeaturesStr, - Options, Reloc::PIC_, - CodeModel::Default, OptLevel); + Options, Reloc::PIC_, + CodeModel::Default, OptLevel); Target->addAnalysisPasses(*PM); bool NoVerify = false; @@ -511,10 +511,10 @@ extern "C" LLVMValueRef LLVMRustConstSmallInt(LLVMTypeRef IntTy, unsigned N, return LLVMConstInt(IntTy, (unsigned long long)N, SignExtend); } -extern "C" LLVMValueRef LLVMRustConstInt(LLVMTypeRef IntTy, - unsigned N_hi, - unsigned N_lo, - LLVMBool SignExtend) { +extern "C" LLVMValueRef LLVMRustConstInt(LLVMTypeRef IntTy, + unsigned N_hi, + unsigned N_lo, + LLVMBool SignExtend) { unsigned long long N = N_hi; N <<= 32; N |= N_lo; diff --git a/src/snapshots.txt b/src/snapshots.txt index fafd5467655ce..00cabe90d840f 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -151,7 +151,7 @@ S 2012-10-03 5585514 winnt-i386 25680d15a358cf4163e08f4e56e54fb497de5eb4 S 2012-10-02 4d30b34 - macos-i386 2bcce3cde8a7e53df202972cda85b0b59ce4e50d + macos-i386 2bcce3cde8a7e53df202972cda85b0b59ce4e50d macos-x86_64 fc5592828392f9eabe8b51cc59639be6d709cc26 freebsd-x86_64 5e09dad0800f16f5d79286330bcb82b6d2b8782e linux-i386 92fc541d4dde19fe2af5930d72a5a50ca67bad60 diff --git a/src/test/auxiliary/anon_trait_static_method_lib.rs b/src/test/auxiliary/anon_trait_static_method_lib.rs index 9a778b1887414..6e111381cba34 100644 --- a/src/test/auxiliary/anon_trait_static_method_lib.rs +++ b/src/test/auxiliary/anon_trait_static_method_lib.rs @@ -17,4 +17,3 @@ pub impl Foo { Foo { x: 3 } } } - diff --git a/src/test/auxiliary/cci_class_2.rs b/src/test/auxiliary/cci_class_2.rs index 9dc27054ef738..b120a4d759f90 100644 --- a/src/test/auxiliary/cci_class_2.rs +++ b/src/test/auxiliary/cci_class_2.rs @@ -27,4 +27,3 @@ pub mod kitties { } } } - diff --git a/src/test/auxiliary/cci_class_6.rs b/src/test/auxiliary/cci_class_6.rs index 80990099cdab5..b09606ea1e21d 100644 --- a/src/test/auxiliary/cci_class_6.rs +++ b/src/test/auxiliary/cci_class_6.rs @@ -31,4 +31,3 @@ pub mod kitties { } } } - diff --git a/src/test/auxiliary/cci_class_cast.rs b/src/test/auxiliary/cci_class_cast.rs index edda0644b16a6..ae0407a5bed33 100644 --- a/src/test/auxiliary/cci_class_cast.rs +++ b/src/test/auxiliary/cci_class_cast.rs @@ -56,5 +56,3 @@ pub mod kitty { } } } - - diff --git a/src/test/auxiliary/cci_no_inline_lib.rs b/src/test/auxiliary/cci_no_inline_lib.rs index 407f62adb0251..f79227d87cd1f 100644 --- a/src/test/auxiliary/cci_no_inline_lib.rs +++ b/src/test/auxiliary/cci_no_inline_lib.rs @@ -19,4 +19,3 @@ pub fn iter(v: ~[uint], f: &fn(uint)) { i += 1u; } } - diff --git a/src/test/auxiliary/explicit_self_xcrate.rs b/src/test/auxiliary/explicit_self_xcrate.rs index c790252244f6b..058cb53f9186b 100644 --- a/src/test/auxiliary/explicit_self_xcrate.rs +++ b/src/test/auxiliary/explicit_self_xcrate.rs @@ -23,5 +23,3 @@ impl Foo for Bar { io::println((*self).x); } } - - diff --git a/src/test/auxiliary/extern_mod_ordering_lib.rs b/src/test/auxiliary/extern_mod_ordering_lib.rs index 8276cea465fd5..d04351203da36 100644 --- a/src/test/auxiliary/extern_mod_ordering_lib.rs +++ b/src/test/auxiliary/extern_mod_ordering_lib.rs @@ -3,4 +3,3 @@ pub mod extern_mod_ordering_lib { pub fn f() {} } - diff --git a/src/test/auxiliary/foreign_lib.rs b/src/test/auxiliary/foreign_lib.rs index 1561ec51ede0e..fe5b9e45593e3 100644 --- a/src/test/auxiliary/foreign_lib.rs +++ b/src/test/auxiliary/foreign_lib.rs @@ -15,4 +15,3 @@ pub mod rustrt { pub fn rust_get_argc() -> libc::c_int; } } - diff --git a/src/test/auxiliary/impl_privacy_xc_1.rs b/src/test/auxiliary/impl_privacy_xc_1.rs index 92452cbe8fdc4..4d98c4d9d2b54 100644 --- a/src/test/auxiliary/impl_privacy_xc_1.rs +++ b/src/test/auxiliary/impl_privacy_xc_1.rs @@ -7,4 +7,3 @@ pub struct Fish { pub impl Fish { fn swim(&self) {} } - diff --git a/src/test/auxiliary/impl_privacy_xc_2.rs b/src/test/auxiliary/impl_privacy_xc_2.rs index 0fa15fa14f613..7ef36b1fb6627 100644 --- a/src/test/auxiliary/impl_privacy_xc_2.rs +++ b/src/test/auxiliary/impl_privacy_xc_2.rs @@ -11,5 +11,3 @@ mod unexported { fn ne(&self, _: &Fish) -> bool { false } } } - - diff --git a/src/test/auxiliary/issue-2414-a.rs b/src/test/auxiliary/issue-2414-a.rs index 9f4f369b70def..54bb39fd2dfad 100644 --- a/src/test/auxiliary/issue-2414-a.rs +++ b/src/test/auxiliary/issue-2414-a.rs @@ -20,4 +20,3 @@ trait foo { impl foo for ~str { fn foo(&self) {} } - diff --git a/src/test/auxiliary/issue-2414-b.rs b/src/test/auxiliary/issue-2414-b.rs index 4bebe4e14208f..f4ef02a2b7f87 100644 --- a/src/test/auxiliary/issue-2414-b.rs +++ b/src/test/auxiliary/issue-2414-b.rs @@ -14,4 +14,3 @@ #[crate_type = "lib"]; extern mod a; - diff --git a/src/test/auxiliary/issue-2526.rs b/src/test/auxiliary/issue-2526.rs index fa32b9603a5da..0e9cf39929f1c 100644 --- a/src/test/auxiliary/issue-2526.rs +++ b/src/test/auxiliary/issue-2526.rs @@ -55,4 +55,3 @@ fn context_res() -> context_res { } pub type context = arc_destruct; - diff --git a/src/test/auxiliary/issue_2316_b.rs b/src/test/auxiliary/issue_2316_b.rs index ed8e69cb4da04..32283e5373ca6 100644 --- a/src/test/auxiliary/issue_2316_b.rs +++ b/src/test/auxiliary/issue_2316_b.rs @@ -17,5 +17,3 @@ pub mod cloth { gingham, flannel, calico } } - - diff --git a/src/test/auxiliary/issue_3136_a.rs b/src/test/auxiliary/issue_3136_a.rs index f7c866da9ae29..55de208cc905a 100644 --- a/src/test/auxiliary/issue_3136_a.rs +++ b/src/test/auxiliary/issue_3136_a.rs @@ -12,7 +12,7 @@ trait x { fn use_x(&self); } struct y(()); -impl x for y { +impl x for y { fn use_x(&self) { struct foo { //~ ERROR quux i: () @@ -20,6 +20,5 @@ impl x for y { fn new_foo(i: ()) -> foo { foo { i: i } } - } + } } - diff --git a/src/test/auxiliary/issue_3882.rs b/src/test/auxiliary/issue_3882.rs index 63275a05598eb..bb75758c741e9 100644 --- a/src/test/auxiliary/issue_3882.rs +++ b/src/test/auxiliary/issue_3882.rs @@ -12,7 +12,7 @@ mod issue_3882 { struct Completions { len: libc::size_t, } - + mod c { extern { fn linenoiseAddCompletion(lc: *mut Completions); diff --git a/src/test/auxiliary/moves_based_on_type_lib.rs b/src/test/auxiliary/moves_based_on_type_lib.rs index 826bd0db12964..857593a84d2c0 100644 --- a/src/test/auxiliary/moves_based_on_type_lib.rs +++ b/src/test/auxiliary/moves_based_on_type_lib.rs @@ -25,4 +25,3 @@ pub fn f() { let y = x; let z = y; } - diff --git a/src/test/auxiliary/newtype_struct_xc.rs b/src/test/auxiliary/newtype_struct_xc.rs index 90036e0f96cd8..e0d2541dbe3d1 100644 --- a/src/test/auxiliary/newtype_struct_xc.rs +++ b/src/test/auxiliary/newtype_struct_xc.rs @@ -1,4 +1,3 @@ #[crate_type="lib"]; pub struct Au(int); - diff --git a/src/test/auxiliary/pub_use_mods_xcrate.rs b/src/test/auxiliary/pub_use_mods_xcrate.rs index e085f2312dc50..e4890f4fe2d87 100644 --- a/src/test/auxiliary/pub_use_mods_xcrate.rs +++ b/src/test/auxiliary/pub_use_mods_xcrate.rs @@ -18,4 +18,3 @@ pub mod a { } } } - diff --git a/src/test/auxiliary/static_fn_inline_xc_aux.rs b/src/test/auxiliary/static_fn_inline_xc_aux.rs index 5fc6621f18658..a17a78bcea773 100644 --- a/src/test/auxiliary/static_fn_inline_xc_aux.rs +++ b/src/test/auxiliary/static_fn_inline_xc_aux.rs @@ -21,4 +21,3 @@ pub mod float { fn from_int2(n: int) -> float { return n as float; } } } - diff --git a/src/test/auxiliary/struct_destructuring_cross_crate.rs b/src/test/auxiliary/struct_destructuring_cross_crate.rs index ab7b1a636d3e3..8887cbee3fe2b 100644 --- a/src/test/auxiliary/struct_destructuring_cross_crate.rs +++ b/src/test/auxiliary/struct_destructuring_cross_crate.rs @@ -14,4 +14,3 @@ pub struct S { x: int, y: int } - diff --git a/src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs b/src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs index 1c7ebd941c34b..7d6178db485f1 100644 --- a/src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs +++ b/src/test/auxiliary/trait_inheritance_auto_xc_2_aux.rs @@ -17,5 +17,3 @@ pub struct A { x: int } impl Foo for A { fn f(&self) -> int { 10 } } impl Bar for A { fn g(&self) -> int { 20 } } impl Baz for A { fn h(&self) -> int { 30 } } - - diff --git a/src/test/auxiliary/trait_inheritance_overloading_xc.rs b/src/test/auxiliary/trait_inheritance_overloading_xc.rs index 1b480ff17b330..1fb0db25b31a8 100644 --- a/src/test/auxiliary/trait_inheritance_overloading_xc.rs +++ b/src/test/auxiliary/trait_inheritance_overloading_xc.rs @@ -38,4 +38,3 @@ impl Eq for MyInt { impl MyNum for MyInt; fn mi(v: int) -> MyInt { MyInt { val: v } } - diff --git a/src/test/auxiliary/xc_private_method_lib.rs b/src/test/auxiliary/xc_private_method_lib.rs index f9fda2b0810b3..05325c3b935c4 100644 --- a/src/test/auxiliary/xc_private_method_lib.rs +++ b/src/test/auxiliary/xc_private_method_lib.rs @@ -7,4 +7,3 @@ pub struct Foo { impl Foo { fn new() -> Foo { Foo { x: 1 } } } - diff --git a/src/test/bench/msgsend-pipes-shared.rs b/src/test/bench/msgsend-pipes-shared.rs index 3833c88465254..6cda0a1945a0d 100644 --- a/src/test/bench/msgsend-pipes-shared.rs +++ b/src/test/bench/msgsend-pipes-shared.rs @@ -104,7 +104,7 @@ fn main() { ~[~"", ~"10000", ~"4"] } else { copy args - }; + }; debug!("%?", args); run(args); diff --git a/src/test/bench/msgsend-pipes.rs b/src/test/bench/msgsend-pipes.rs index c4044d45f36c8..a8fb29a47e2fb 100644 --- a/src/test/bench/msgsend-pipes.rs +++ b/src/test/bench/msgsend-pipes.rs @@ -101,7 +101,7 @@ fn main() { ~[~"", ~"10000", ~"4"] } else { copy args - }; + }; debug!("%?", args); run(args); diff --git a/src/test/bench/msgsend-ring-mutex-arcs.rs b/src/test/bench/msgsend-ring-mutex-arcs.rs index a1ab7384d62a5..853b057277d8e 100644 --- a/src/test/bench/msgsend-ring-mutex-arcs.rs +++ b/src/test/bench/msgsend-ring-mutex-arcs.rs @@ -72,7 +72,7 @@ fn main() { ~[~"", ~"10", ~"100"] } else { copy args - }; + }; let num_tasks = uint::from_str(args[1]).get(); let msg_per_task = uint::from_str(args[2]).get(); diff --git a/src/test/bench/msgsend-ring-pipes.rs b/src/test/bench/msgsend-ring-pipes.rs index 14e955dd7bdae..1288ac290787a 100644 --- a/src/test/bench/msgsend-ring-pipes.rs +++ b/src/test/bench/msgsend-ring-pipes.rs @@ -65,7 +65,7 @@ fn main() { ~[~"", ~"100", ~"1000"] } else { copy args - }; + }; let num_tasks = uint::from_str(args[1]).get(); let msg_per_task = uint::from_str(args[2]).get(); diff --git a/src/test/bench/msgsend-ring-rw-arcs.rs b/src/test/bench/msgsend-ring-rw-arcs.rs index 8e819cc4aba00..2cf0fbfc397f3 100644 --- a/src/test/bench/msgsend-ring-rw-arcs.rs +++ b/src/test/bench/msgsend-ring-rw-arcs.rs @@ -73,7 +73,7 @@ fn main() { ~[~"", ~"10", ~"100"] } else { copy args - }; + }; let num_tasks = uint::from_str(args[1]).get(); let msg_per_task = uint::from_str(args[2]).get(); diff --git a/src/test/bench/pingpong.rs b/src/test/bench/pingpong.rs index 4a6e90f411686..09e663325ed49 100644 --- a/src/test/bench/pingpong.rs +++ b/src/test/bench/pingpong.rs @@ -11,7 +11,7 @@ // Compare bounded and unbounded protocol performance. // xfail-pretty - + extern mod std; use core::cell::Cell; diff --git a/src/test/bench/shootout-chameneos-redux.rs b/src/test/bench/shootout-chameneos-redux.rs index 9dad24646ded2..5d893d4ec07d0 100644 --- a/src/test/bench/shootout-chameneos-redux.rs +++ b/src/test/bench/shootout-chameneos-redux.rs @@ -218,4 +218,3 @@ fn main() { rendezvous(nn, ~[Blue, Red, Yellow, Red, Yellow, Blue, Red, Yellow, Red, Blue]); } - diff --git a/src/test/bench/shootout-fannkuch-redux.rs b/src/test/bench/shootout-fannkuch-redux.rs index 21f38245ca359..cb32e0e496e95 100644 --- a/src/test/bench/shootout-fannkuch-redux.rs +++ b/src/test/bench/shootout-fannkuch-redux.rs @@ -92,4 +92,3 @@ fn main() { let n: i32 = FromStr::from_str(os::args()[1]).get(); println(fmt!("Pfannkuchen(%d) = %d", n as int, fannkuch_redux(n) as int)); } - diff --git a/src/test/bench/shootout-fasta-redux.rs b/src/test/bench/shootout-fasta-redux.rs index 5ece98102063b..d6a0f4b8b255e 100644 --- a/src/test/bench/shootout-fasta-redux.rs +++ b/src/test/bench/shootout-fasta-redux.rs @@ -201,4 +201,3 @@ fn main() { fputc('\n' as c_int, stdout); } } - diff --git a/src/test/bench/shootout-k-nucleotide-pipes.rs b/src/test/bench/shootout-k-nucleotide-pipes.rs index 4cd7b58ce12a0..d1f3dbf22ce83 100644 --- a/src/test/bench/shootout-k-nucleotide-pipes.rs +++ b/src/test/bench/shootout-k-nucleotide-pipes.rs @@ -222,4 +222,3 @@ fn main() { io::println(from_child[ii].recv()); } } - diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs index 224885a3f79b1..1791af67ed040 100644 --- a/src/test/bench/shootout-k-nucleotide.rs +++ b/src/test/bench/shootout-k-nucleotide.rs @@ -252,7 +252,7 @@ fn generate_frequencies(frequencies: &mut Table, mut input: &[u8], frame: i32) { let mut code = Code(0); - + // Pull first frame. for (frame as uint).times { code = code.push_char(input[0]); @@ -313,4 +313,3 @@ fn main() { print_occurrences(frequencies, occurrence); } } - diff --git a/src/test/bench/shootout-mandelbrot.rs b/src/test/bench/shootout-mandelbrot.rs index e62cb8ea849d1..7d2b25792ec57 100644 --- a/src/test/bench/shootout-mandelbrot.rs +++ b/src/test/bench/shootout-mandelbrot.rs @@ -57,4 +57,3 @@ fn main() { } } } - diff --git a/src/test/bench/shootout-pidigits.rs b/src/test/bench/shootout-pidigits.rs index 38e87358ee214..cb7fa969be7a7 100644 --- a/src/test/bench/shootout-pidigits.rs +++ b/src/test/bench/shootout-pidigits.rs @@ -175,4 +175,3 @@ fn main() { let n: u32 = FromStr::from_str(os::args()[1]).get(); pidigits(n); } - diff --git a/src/test/bench/shootout-reverse-complement.rs b/src/test/bench/shootout-reverse-complement.rs index 72c01c8d55cfb..a9cb3c7636a9b 100644 --- a/src/test/bench/shootout-reverse-complement.rs +++ b/src/test/bench/shootout-reverse-complement.rs @@ -152,4 +152,3 @@ fn main() { fwrite(transmute(out.unsafe_ref(0)), 1, pos as size_t, stdout); } } - diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs index 9221da8b55738..8afddd3a31e91 100644 --- a/src/test/bench/sudoku.rs +++ b/src/test/bench/sudoku.rs @@ -274,4 +274,3 @@ fn main() { sudoku.solve(); sudoku.write(io::stdout()); } - diff --git a/src/test/compile-fail/alt-tag-nullary.rs b/src/test/compile-fail/alt-tag-nullary.rs index c74ee3d852a52..2b0c3dbf8e80f 100644 --- a/src/test/compile-fail/alt-tag-nullary.rs +++ b/src/test/compile-fail/alt-tag-nullary.rs @@ -14,4 +14,3 @@ enum a { A, } enum b { B, } fn main() { let x: a = A; match x { B => { } } } - diff --git a/src/test/compile-fail/alt-tag-unary.rs b/src/test/compile-fail/alt-tag-unary.rs index e01b9a045e531..a129ff19ac63e 100644 --- a/src/test/compile-fail/alt-tag-unary.rs +++ b/src/test/compile-fail/alt-tag-unary.rs @@ -14,4 +14,3 @@ enum a { A(int), } enum b { B(int), } fn main() { let x: a = A(0); match x { B(y) => { } } } - diff --git a/src/test/compile-fail/auto-ref-borrowck-failure.rs b/src/test/compile-fail/auto-ref-borrowck-failure.rs index 90b9b44cfbea3..894b71357b75a 100644 --- a/src/test/compile-fail/auto-ref-borrowck-failure.rs +++ b/src/test/compile-fail/auto-ref-borrowck-failure.rs @@ -28,4 +28,3 @@ fn main() { let x = Foo { x: 3 }; x.printme(); //~ ERROR illegal borrow } - diff --git a/src/test/compile-fail/bogus-tag.rs b/src/test/compile-fail/bogus-tag.rs index 12e8ba56532cb..89ad7b4245a07 100644 --- a/src/test/compile-fail/bogus-tag.rs +++ b/src/test/compile-fail/bogus-tag.rs @@ -21,4 +21,3 @@ fn main() { hsl(h, s, l) => { debug!("hsl"); } } } - diff --git a/src/test/compile-fail/borrowck-assign-comp-idx.rs b/src/test/compile-fail/borrowck-assign-comp-idx.rs index 25b56abb5ba00..a284cd5b4a791 100644 --- a/src/test/compile-fail/borrowck-assign-comp-idx.rs +++ b/src/test/compile-fail/borrowck-assign-comp-idx.rs @@ -45,4 +45,3 @@ fn c() { fn main() { } - diff --git a/src/test/compile-fail/borrowck-assign-comp.rs b/src/test/compile-fail/borrowck-assign-comp.rs index 283f04a283f4e..eb832fe738da2 100644 --- a/src/test/compile-fail/borrowck-assign-comp.rs +++ b/src/test/compile-fail/borrowck-assign-comp.rs @@ -42,4 +42,3 @@ fn d() { fn main() { } - diff --git a/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs b/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs index 2c68429baec92..f2c6ae98819e2 100644 --- a/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs +++ b/src/test/compile-fail/borrowck-call-method-from-mut-aliasable.rs @@ -38,4 +38,3 @@ fn c(x: &const Foo) { fn main() { } - diff --git a/src/test/compile-fail/borrowck-loan-local-as-both-mut-and-imm.rs b/src/test/compile-fail/borrowck-loan-local-as-both-mut-and-imm.rs index a2ba5ad489167..1c2bd8dc8e10f 100644 --- a/src/test/compile-fail/borrowck-loan-local-as-both-mut-and-imm.rs +++ b/src/test/compile-fail/borrowck-loan-local-as-both-mut-and-imm.rs @@ -30,6 +30,6 @@ use core::either::{Either, Left, Right}; let y: &Either = &x; let z: &mut Either = &mut x; //~ ERROR conflicts with prior loan *z = *y; - } + } fn main() {} diff --git a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs index a4ad7e69b3336..21bb7434f8d33 100644 --- a/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs +++ b/src/test/compile-fail/borrowck-loan-rcvr-overloaded-op.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct Point { +struct Point { x: int, y: int, } @@ -56,4 +56,3 @@ fn c() { fn main() { } - diff --git a/src/test/compile-fail/borrowck-loan-rcvr.rs b/src/test/compile-fail/borrowck-loan-rcvr.rs index 4473574926a34..36007abf05ea3 100644 --- a/src/test/compile-fail/borrowck-loan-rcvr.rs +++ b/src/test/compile-fail/borrowck-loan-rcvr.rs @@ -63,4 +63,3 @@ fn c() { fn main() { } - diff --git a/src/test/compile-fail/borrowck-mut-boxed-vec.rs b/src/test/compile-fail/borrowck-mut-boxed-vec.rs index d4c0b5a1e9bf9..e8ed362176f57 100644 --- a/src/test/compile-fail/borrowck-mut-boxed-vec.rs +++ b/src/test/compile-fail/borrowck-mut-boxed-vec.rs @@ -14,4 +14,3 @@ fn main() { v[1] = 4; } } - diff --git a/src/test/compile-fail/borrowck-ref-into-rvalue.rs b/src/test/compile-fail/borrowck-ref-into-rvalue.rs index 37ee747069ccf..84acd0df20b75 100644 --- a/src/test/compile-fail/borrowck-ref-into-rvalue.rs +++ b/src/test/compile-fail/borrowck-ref-into-rvalue.rs @@ -13,9 +13,8 @@ fn main() { match Some(~"Hello") { //~ ERROR illegal borrow Some(ref m) => { msg = m; - }, + }, None => { fail!() } - } + } io::println(*msg); } - diff --git a/src/test/compile-fail/borrowck-uniq-via-box.rs b/src/test/compile-fail/borrowck-uniq-via-box.rs index e1c0e67ff8dcc..97414ff5e786c 100644 --- a/src/test/compile-fail/borrowck-uniq-via-box.rs +++ b/src/test/compile-fail/borrowck-uniq-via-box.rs @@ -52,4 +52,3 @@ fn box_imm_recs(v: @Outer) { fn main() { } - diff --git a/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs index 27902100373a9..805b162f1d363 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-loan-from-mut.rs @@ -9,4 +9,3 @@ fn a() { } fn main() {} - diff --git a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs index 05ff85d612c82..eef99aafd687c 100644 --- a/src/test/compile-fail/borrowck-vec-pattern-nesting.rs +++ b/src/test/compile-fail/borrowck-vec-pattern-nesting.rs @@ -18,4 +18,3 @@ fn b() { } fn main() {} - diff --git a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs index e47ad721b0d7b..f9e6bc1b22e8c 100644 --- a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs +++ b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-2.rs @@ -3,4 +3,3 @@ fn main() { let _x = &mut *b; //~ NOTE prior loan as mutable granted here let _y = &mut *b; //~ ERROR loan of dereference of mutable ~ pointer as mutable conflicts with prior loan } - diff --git a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs index 015f368ecb068..6c82b25a6a140 100644 --- a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs +++ b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail-3.rs @@ -5,4 +5,3 @@ fn main() { let mut d = /*move*/ a; //~ ERROR moving out of mutable local variable prohibited due to outstanding loan *d += 1; } - diff --git a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs index 36d32fddda150..dc453d981934d 100644 --- a/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs +++ b/src/test/compile-fail/borrowck-wg-borrow-mut-to-imm-fail.rs @@ -4,4 +4,3 @@ fn main() { let mut y = /*move*/ b; //~ ERROR moving out of mutable local variable prohibited *y += 1; } - diff --git a/src/test/compile-fail/borrowck-wg-move-base-2.rs b/src/test/compile-fail/borrowck-wg-move-base-2.rs index ba85616e63f28..0ede523daa4c6 100644 --- a/src/test/compile-fail/borrowck-wg-move-base-2.rs +++ b/src/test/compile-fail/borrowck-wg-move-base-2.rs @@ -7,5 +7,3 @@ fn foo(x: &mut int) { fn main() { } - - diff --git a/src/test/compile-fail/by-move-pattern-binding.rs b/src/test/compile-fail/by-move-pattern-binding.rs index 95091f15ce0e5..1efed154286ec 100644 --- a/src/test/compile-fail/by-move-pattern-binding.rs +++ b/src/test/compile-fail/by-move-pattern-binding.rs @@ -20,4 +20,3 @@ fn main() { &Bar(ref identifier) => io::println(*identifier) }; } - diff --git a/src/test/compile-fail/dead-code-ret.rs b/src/test/compile-fail/dead-code-ret.rs index 182a41c1b1735..97f6149b162fc 100644 --- a/src/test/compile-fail/dead-code-ret.rs +++ b/src/test/compile-fail/dead-code-ret.rs @@ -15,4 +15,3 @@ fn f(caller: str) { debug!(caller); } fn main() { return f("main"); debug!("Paul is dead"); } - diff --git a/src/test/compile-fail/does-nothing.rs b/src/test/compile-fail/does-nothing.rs index a360d6579574f..699baad4d4308 100644 --- a/src/test/compile-fail/does-nothing.rs +++ b/src/test/compile-fail/does-nothing.rs @@ -1,3 +1,2 @@ // error-pattern: unresolved name: `this_does_nothing_what_the`. fn main() { debug!("doing"); this_does_nothing_what_the; debug!("boing"); } - diff --git a/src/test/compile-fail/drop-on-non-struct.rs b/src/test/compile-fail/drop-on-non-struct.rs index 4e5b64c8f3db4..b2f87686ac664 100644 --- a/src/test/compile-fail/drop-on-non-struct.rs +++ b/src/test/compile-fail/drop-on-non-struct.rs @@ -19,5 +19,3 @@ impl Drop for Foo { //~ ERROR the Drop trait may only be implemented fn main() { } - - diff --git a/src/test/compile-fail/explicit-call-to-dtor.rs b/src/test/compile-fail/explicit-call-to-dtor.rs index 71674186b6125..24fedaaabe3a0 100644 --- a/src/test/compile-fail/explicit-call-to-dtor.rs +++ b/src/test/compile-fail/explicit-call-to-dtor.rs @@ -22,4 +22,3 @@ fn main() { let x = Foo { x: 3 }; x.finalize(); //~ ERROR explicit call to destructor } - diff --git a/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs b/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs index 26b13566f7a0e..fd49889a3f796 100644 --- a/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs +++ b/src/test/compile-fail/explicit-call-to-supertrait-dtor.rs @@ -31,5 +31,3 @@ impl Bar for Foo { fn main() { let x = Foo { x: 3 }; } - - diff --git a/src/test/compile-fail/float-literal-inference-restrictions.rs b/src/test/compile-fail/float-literal-inference-restrictions.rs index 80aefbbf48f81..48dbdd86b11f9 100644 --- a/src/test/compile-fail/float-literal-inference-restrictions.rs +++ b/src/test/compile-fail/float-literal-inference-restrictions.rs @@ -12,4 +12,3 @@ fn main() { let x: f32 = 1; //~ ERROR mismatched types let y: f32 = 1f; //~ ERROR mismatched types } - diff --git a/src/test/compile-fail/foreign-unsafe-fn-called.rs b/src/test/compile-fail/foreign-unsafe-fn-called.rs index 9122abab71321..ed8b8088ee41a 100644 --- a/src/test/compile-fail/foreign-unsafe-fn-called.rs +++ b/src/test/compile-fail/foreign-unsafe-fn-called.rs @@ -21,4 +21,3 @@ fn main() { test::free(); //~^ ERROR access to unsafe function requires unsafe function or block } - diff --git a/src/test/compile-fail/foreign-unsafe-fn.rs b/src/test/compile-fail/foreign-unsafe-fn.rs index 32fafe296466c..3633267d02c40 100644 --- a/src/test/compile-fail/foreign-unsafe-fn.rs +++ b/src/test/compile-fail/foreign-unsafe-fn.rs @@ -21,5 +21,3 @@ fn main() { let x = test::free; //~^ ERROR access to unsafe function requires unsafe function or block } - - diff --git a/src/test/compile-fail/issue-1451.rs b/src/test/compile-fail/issue-1451.rs index acc371076e704..a295e8eb7edb0 100644 --- a/src/test/compile-fail/issue-1451.rs +++ b/src/test/compile-fail/issue-1451.rs @@ -30,4 +30,3 @@ fn main() { fooT(T {f: x}); fooT(T {f: bar}); } - diff --git a/src/test/compile-fail/issue-2951.rs b/src/test/compile-fail/issue-2951.rs index 3874d9b13f5ca..e57d4f0917579 100644 --- a/src/test/compile-fail/issue-2951.rs +++ b/src/test/compile-fail/issue-2951.rs @@ -15,5 +15,4 @@ fn foo(x: T, y: U) { } fn main() { - } diff --git a/src/test/compile-fail/issue-3044.rs b/src/test/compile-fail/issue-3044.rs index fcd5b1deee552..635d0aa3df1e5 100644 --- a/src/test/compile-fail/issue-3044.rs +++ b/src/test/compile-fail/issue-3044.rs @@ -17,4 +17,3 @@ fn main() { // // the first error is, um, non-ideal. } - diff --git a/src/test/compile-fail/issue-3096-2.rs b/src/test/compile-fail/issue-3096-2.rs index da13d450273ba..eb58cf3e13b36 100644 --- a/src/test/compile-fail/issue-3096-2.rs +++ b/src/test/compile-fail/issue-3096-2.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum bottom { } +enum bottom { } fn main() { let x = ptr::to_unsafe_ptr(&()) as *bottom; diff --git a/src/test/compile-fail/issue-3991.rs b/src/test/compile-fail/issue-3991.rs index d1c9057b8807b..d3016f893b467 100644 --- a/src/test/compile-fail/issue-3991.rs +++ b/src/test/compile-fail/issue-3991.rs @@ -12,11 +12,11 @@ struct HasNested { mut nest: ~[~[int]], } - + impl HasNested { fn method_push_local(&self) { self.nest[0].push(0); } } - + fn main() {} diff --git a/src/test/compile-fail/issue-4265.rs b/src/test/compile-fail/issue-4265.rs index b6a32f5febae4..e76d211dedace 100644 --- a/src/test/compile-fail/issue-4265.rs +++ b/src/test/compile-fail/issue-4265.rs @@ -11,12 +11,12 @@ struct Foo { baz: uint } - + impl Foo { fn bar() { Foo { baz: 0 }.bar(); } - + fn bar() { //~ ERROR duplicate definition of value bar } } diff --git a/src/test/compile-fail/issue-4366.rs b/src/test/compile-fail/issue-4366.rs index 7d97932d9af6b..f4e571715997a 100644 --- a/src/test/compile-fail/issue-4366.rs +++ b/src/test/compile-fail/issue-4366.rs @@ -37,4 +37,3 @@ mod m1 { fn main() { foo(); //~ ERROR: unresolved name: `foo` } - diff --git a/src/test/compile-fail/issue-4968.rs b/src/test/compile-fail/issue-4968.rs index fc0c29e9a7987..700d8a61c3a39 100644 --- a/src/test/compile-fail/issue-4968.rs +++ b/src/test/compile-fail/issue-4968.rs @@ -14,4 +14,3 @@ static A: (int,int) = (4,2); fn main() { match 42 { A => () } //~ ERROR mismatched types: expected `` but found `(int,int)` (expected integral variable but found tuple) } - diff --git a/src/test/compile-fail/kindck-destructor-owned.rs b/src/test/compile-fail/kindck-destructor-owned.rs index e956f95b4229c..faad36a15d2fa 100644 --- a/src/test/compile-fail/kindck-destructor-owned.rs +++ b/src/test/compile-fail/kindck-destructor-owned.rs @@ -9,4 +9,3 @@ impl Drop for Foo { //~ ERROR cannot implement a destructor on a struct that is } fn main() { } - diff --git a/src/test/compile-fail/lint-default-methods.rs b/src/test/compile-fail/lint-default-methods.rs index 1350c3e3ad1cd..89b99fcebca5d 100644 --- a/src/test/compile-fail/lint-default-methods.rs +++ b/src/test/compile-fail/lint-default-methods.rs @@ -5,4 +5,3 @@ trait Foo { //~ ERROR default methods are experimental } fn main() {} - diff --git a/src/test/compile-fail/lint-type-limits.rs b/src/test/compile-fail/lint-type-limits.rs index e45ef38e97a94..2eb794fd1c296 100644 --- a/src/test/compile-fail/lint-type-limits.rs +++ b/src/test/compile-fail/lint-type-limits.rs @@ -32,4 +32,3 @@ fn qux() { i += 1; } } - diff --git a/src/test/compile-fail/liveness-if-no-else.rs b/src/test/compile-fail/liveness-if-no-else.rs index e37ee5bd4d4f2..22b1b5edbac70 100644 --- a/src/test/compile-fail/liveness-if-no-else.rs +++ b/src/test/compile-fail/liveness-if-no-else.rs @@ -11,6 +11,6 @@ fn foo(x: int) { debug!(x); } fn main() { - let x: int; if 1 > 2 { x = 10; } - foo(x); //~ ERROR use of possibly uninitialized variable: `x` + let x: int; if 1 > 2 { x = 10; } + foo(x); //~ ERROR use of possibly uninitialized variable: `x` } diff --git a/src/test/compile-fail/liveness-return.rs b/src/test/compile-fail/liveness-return.rs index 12f7aa434cce3..6558bc579685a 100644 --- a/src/test/compile-fail/liveness-return.rs +++ b/src/test/compile-fail/liveness-return.rs @@ -9,8 +9,8 @@ // except according to those terms. fn f() -> int { - let x: int; - return x; //~ ERROR use of possibly uninitialized variable: `x` + let x: int; + return x; //~ ERROR use of possibly uninitialized variable: `x` } fn main() { f(); } diff --git a/src/test/compile-fail/liveness-uninit-after-item.rs b/src/test/compile-fail/liveness-uninit-after-item.rs index b3ab005388837..a828b1d6b9f52 100644 --- a/src/test/compile-fail/liveness-uninit-after-item.rs +++ b/src/test/compile-fail/liveness-uninit-after-item.rs @@ -13,4 +13,3 @@ fn main() { fn baz(_x: int) { } baz(bar); //~ ERROR use of possibly uninitialized variable: `bar` } - diff --git a/src/test/compile-fail/liveness-uninit.rs b/src/test/compile-fail/liveness-uninit.rs index 8797132fd5083..a360f8e85a67d 100644 --- a/src/test/compile-fail/liveness-uninit.rs +++ b/src/test/compile-fail/liveness-uninit.rs @@ -11,6 +11,6 @@ fn foo(x: int) { debug!(x); } fn main() { - let x: int; - foo(x); //~ ERROR use of possibly uninitialized variable: `x` + let x: int; + foo(x); //~ ERROR use of possibly uninitialized variable: `x` } diff --git a/src/test/compile-fail/macro-with-seps-err-msg.rs b/src/test/compile-fail/macro-with-seps-err-msg.rs index 74c040238ac05..95250e36b8685 100644 --- a/src/test/compile-fail/macro-with-seps-err-msg.rs +++ b/src/test/compile-fail/macro-with-seps-err-msg.rs @@ -13,5 +13,3 @@ fn main() { globnar::brotz!(); } - - diff --git a/src/test/compile-fail/missing-derivable-attr.rs b/src/test/compile-fail/missing-derivable-attr.rs index 67cf67bfa5a04..eb27d51061fcc 100644 --- a/src/test/compile-fail/missing-derivable-attr.rs +++ b/src/test/compile-fail/missing-derivable-attr.rs @@ -24,4 +24,3 @@ impl MyEq for A; //~ ERROR missing method fn main() { } - diff --git a/src/test/compile-fail/missing-return.rs b/src/test/compile-fail/missing-return.rs index c0007d2bee807..1dc817cc6e6be 100644 --- a/src/test/compile-fail/missing-return.rs +++ b/src/test/compile-fail/missing-return.rs @@ -13,4 +13,3 @@ fn f() -> int { } fn main() { f(); } - diff --git a/src/test/compile-fail/moves-based-on-type-block-bad.rs b/src/test/compile-fail/moves-based-on-type-block-bad.rs index 020dadfc96cd2..67eb06ab424c5 100644 --- a/src/test/compile-fail/moves-based-on-type-block-bad.rs +++ b/src/test/compile-fail/moves-based-on-type-block-bad.rs @@ -24,4 +24,3 @@ fn main() { } } } - diff --git a/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs b/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs index 57829e72674e6..6dce011ddc896 100644 --- a/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs +++ b/src/test/compile-fail/moves-based-on-type-capture-clause-bad.rs @@ -5,4 +5,3 @@ fn main() { } io::println(x); //~ ERROR use of moved value } - diff --git a/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs b/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs index bee9596df727d..2b9291ce3284c 100644 --- a/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs +++ b/src/test/compile-fail/moves-based-on-type-cyclic-types-issue-4821.rs @@ -29,4 +29,3 @@ fn consume(v: ~List) -> int { } fn main() {} - diff --git a/src/test/compile-fail/no-capture-arc.rs b/src/test/compile-fail/no-capture-arc.rs index da75dfd010685..2c8c98ad5d6de 100644 --- a/src/test/compile-fail/no-capture-arc.rs +++ b/src/test/compile-fail/no-capture-arc.rs @@ -16,7 +16,7 @@ use std::arc; fn main() { let v = ~[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let arc_v = arc::ARC(v); - + do task::spawn() { let v = *arc::get(&arc_v); assert!(v[3] == 4); diff --git a/src/test/compile-fail/noexporttypeexe.rs b/src/test/compile-fail/noexporttypeexe.rs index 8d9796c7c419b..95428568e4c35 100644 --- a/src/test/compile-fail/noexporttypeexe.rs +++ b/src/test/compile-fail/noexporttypeexe.rs @@ -20,4 +20,3 @@ fn main() { let x: int = noexporttypelib::foo(); //~^ ERROR expected `int` but found `core::option::Option` } - diff --git a/src/test/compile-fail/non-exhaustive-match-nested.rs b/src/test/compile-fail/non-exhaustive-match-nested.rs index 4d1db36237640..34fe6b0f67870 100644 --- a/src/test/compile-fail/non-exhaustive-match-nested.rs +++ b/src/test/compile-fail/non-exhaustive-match-nested.rs @@ -20,4 +20,3 @@ fn main() { b => { fail!(~"goodbye"); } } } - diff --git a/src/test/compile-fail/once-fn-subtyping.rs b/src/test/compile-fail/once-fn-subtyping.rs index 00009c706e33e..178c04dfc793c 100644 --- a/src/test/compile-fail/once-fn-subtyping.rs +++ b/src/test/compile-fail/once-fn-subtyping.rs @@ -14,4 +14,3 @@ fn main() { let h: &fn() = ||(); let i: &once fn() = h; // ok } - diff --git a/src/test/compile-fail/private-impl-method.rs b/src/test/compile-fail/private-impl-method.rs index 74bdcdc7f82d0..a6728f82ec3b3 100644 --- a/src/test/compile-fail/private-impl-method.rs +++ b/src/test/compile-fail/private-impl-method.rs @@ -22,4 +22,3 @@ fn main() { let s = a::Foo { x: 1 }; s.foo(); //~ ERROR method `foo` is private } - diff --git a/src/test/compile-fail/private-item-simple.rs b/src/test/compile-fail/private-item-simple.rs index e8038df188b7c..8776739db2d76 100644 --- a/src/test/compile-fail/private-item-simple.rs +++ b/src/test/compile-fail/private-item-simple.rs @@ -15,4 +15,3 @@ mod a { fn main() { a::f(); //~ ERROR unresolved name } - diff --git a/src/test/compile-fail/private-method-inherited.rs b/src/test/compile-fail/private-method-inherited.rs index 7b64623e16c3e..bc27027e886ba 100644 --- a/src/test/compile-fail/private-method-inherited.rs +++ b/src/test/compile-fail/private-method-inherited.rs @@ -12,4 +12,3 @@ fn main() { let x = a::Foo; x.f(); //~ ERROR method `f` is private } - diff --git a/src/test/compile-fail/private-struct-field-ctor.rs b/src/test/compile-fail/private-struct-field-ctor.rs index 43e7427dd740f..7ab28d72965fa 100644 --- a/src/test/compile-fail/private-struct-field-ctor.rs +++ b/src/test/compile-fail/private-struct-field-ctor.rs @@ -17,4 +17,3 @@ mod a { fn main() { let s = a::Foo { x: 1 }; //~ ERROR field `x` is private } - diff --git a/src/test/compile-fail/private-struct-field-pattern.rs b/src/test/compile-fail/private-struct-field-pattern.rs index 864c9bd98d7b3..6f524a8eaa401 100644 --- a/src/test/compile-fail/private-struct-field-pattern.rs +++ b/src/test/compile-fail/private-struct-field-pattern.rs @@ -25,4 +25,3 @@ fn main() { Foo { x: _ } => {} //~ ERROR field `x` is private } } - diff --git a/src/test/compile-fail/qquote-1.rs b/src/test/compile-fail/qquote-1.rs index eda207f711d68..4710d9dee4521 100644 --- a/src/test/compile-fail/qquote-1.rs +++ b/src/test/compile-fail/qquote-1.rs @@ -65,4 +65,3 @@ fn main() { fn check_pp(expr: T, f: &fn(pprust::ps, T), expect: str) { fail!(); } - diff --git a/src/test/compile-fail/qquote-2.rs b/src/test/compile-fail/qquote-2.rs index c669053400831..d377325610598 100644 --- a/src/test/compile-fail/qquote-2.rs +++ b/src/test/compile-fail/qquote-2.rs @@ -60,4 +60,3 @@ fn main() { fn check_pp(expr: T, f: &fn(pprust::ps, T), expect: str) { fail!(); } - diff --git a/src/test/compile-fail/refutable-pattern-in-fn-arg.rs b/src/test/compile-fail/refutable-pattern-in-fn-arg.rs index 5e157c1bd7b19..957925709e179 100644 --- a/src/test/compile-fail/refutable-pattern-in-fn-arg.rs +++ b/src/test/compile-fail/refutable-pattern-in-fn-arg.rs @@ -12,4 +12,3 @@ fn main() { let f = |3: int| io::println("hello"); //~ ERROR refutable pattern f(4); } - diff --git a/src/test/compile-fail/regions-addr-of-self.rs b/src/test/compile-fail/regions-addr-of-self.rs index 732d946bf9ee5..f96ef639e756c 100644 --- a/src/test/compile-fail/regions-addr-of-self.rs +++ b/src/test/compile-fail/regions-addr-of-self.rs @@ -35,4 +35,3 @@ fn main() { d.chase_cat(); debug!("cats_chased: %u", d.cats_chased); } - diff --git a/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs b/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs index a8b7ae1b9c8e4..6ee0216655e92 100644 --- a/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs +++ b/src/test/compile-fail/regions-infer-borrow-scope-too-big.rs @@ -24,4 +24,3 @@ fn foo(p: @point) -> &int { } fn main() {} - diff --git a/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs b/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs index bf8f227b5730e..602f5dc6983c2 100644 --- a/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs +++ b/src/test/compile-fail/regions-infer-borrow-scope-within-loop.rs @@ -15,8 +15,8 @@ fn foo(cond: &fn() -> bool, box: &fn() -> @int) { loop { let x = box(); - // Here we complain because the resulting region - // of this borrow is the fn body as a whole. + // Here we complain because the resulting region + // of this borrow is the fn body as a whole. y = borrow(x); //~ ERROR illegal borrow: cannot root managed value long enough assert!(*x == *y); diff --git a/src/test/compile-fail/regions-ret.rs b/src/test/compile-fail/regions-ret.rs index be7b28f6ef4b5..cf7cb175bb8a4 100644 --- a/src/test/compile-fail/regions-ret.rs +++ b/src/test/compile-fail/regions-ret.rs @@ -14,4 +14,3 @@ fn f<'a>(_x : &'a int) -> &'a int { fn main() { } - diff --git a/src/test/compile-fail/repeat-to-run-dtor-twice.rs b/src/test/compile-fail/repeat-to-run-dtor-twice.rs index 18bdb564441d3..e1e1e2313f42a 100644 --- a/src/test/compile-fail/repeat-to-run-dtor-twice.rs +++ b/src/test/compile-fail/repeat-to-run-dtor-twice.rs @@ -26,4 +26,3 @@ fn main() { let a = Foo { x: 3 }; let _ = [ a, ..5 ]; //~ ERROR copying a value of non-copyable type } - diff --git a/src/test/compile-fail/static-method-privacy.rs b/src/test/compile-fail/static-method-privacy.rs index 50df4f04971c8..0fd82b5ace3a7 100644 --- a/src/test/compile-fail/static-method-privacy.rs +++ b/src/test/compile-fail/static-method-privacy.rs @@ -8,4 +8,3 @@ mod a { fn main() { let _ = a::S::new(); //~ ERROR function `new` is private } - diff --git a/src/test/compile-fail/static-region-bound.rs b/src/test/compile-fail/static-region-bound.rs index 500a5b0c8bcbc..ada3aebb2f420 100644 --- a/src/test/compile-fail/static-region-bound.rs +++ b/src/test/compile-fail/static-region-bound.rs @@ -6,4 +6,3 @@ fn main() { let x = &3; f(x); //~ ERROR instantiating a type parameter with an incompatible type } - diff --git a/src/test/compile-fail/struct-like-enum-nonexhaustive.rs b/src/test/compile-fail/struct-like-enum-nonexhaustive.rs index 52a61628c3562..91709e2ea7da0 100644 --- a/src/test/compile-fail/struct-like-enum-nonexhaustive.rs +++ b/src/test/compile-fail/struct-like-enum-nonexhaustive.rs @@ -20,5 +20,3 @@ fn main() { B { x: None } => {} } } - - diff --git a/src/test/compile-fail/super-at-top-level.rs b/src/test/compile-fail/super-at-top-level.rs index 21b9e5292b19e..f1064a6290561 100644 --- a/src/test/compile-fail/super-at-top-level.rs +++ b/src/test/compile-fail/super-at-top-level.rs @@ -2,6 +2,4 @@ use super::f; //~ ERROR unresolved name //~^ ERROR failed to resolve import fn main() { - } - diff --git a/src/test/compile-fail/trait-impl-method-mismatch.rs b/src/test/compile-fail/trait-impl-method-mismatch.rs index 7f4c227d2d083..54fa62f797766 100644 --- a/src/test/compile-fail/trait-impl-method-mismatch.rs +++ b/src/test/compile-fail/trait-impl-method-mismatch.rs @@ -19,7 +19,3 @@ impl Mumbo for uint { } fn main() {} - - - - diff --git a/src/test/compile-fail/trait-inheritance-missing-requirement.rs b/src/test/compile-fail/trait-inheritance-missing-requirement.rs index a341c24261135..5968c296e1382 100644 --- a/src/test/compile-fail/trait-inheritance-missing-requirement.rs +++ b/src/test/compile-fail/trait-inheritance-missing-requirement.rs @@ -30,4 +30,3 @@ impl Bar for A { fn main() { } - diff --git a/src/test/compile-fail/tuple-struct-nonexhaustive.rs b/src/test/compile-fail/tuple-struct-nonexhaustive.rs index 7cfdab2e96d57..de28a06ababcb 100644 --- a/src/test/compile-fail/tuple-struct-nonexhaustive.rs +++ b/src/test/compile-fail/tuple-struct-nonexhaustive.rs @@ -17,5 +17,3 @@ fn main() { Foo(2, b) => io::println(fmt!("%d", b)) } } - - diff --git a/src/test/compile-fail/tutorial-suffix-inference-test.rs b/src/test/compile-fail/tutorial-suffix-inference-test.rs index c68af84b95be0..d92aa8d640ab5 100644 --- a/src/test/compile-fail/tutorial-suffix-inference-test.rs +++ b/src/test/compile-fail/tutorial-suffix-inference-test.rs @@ -22,11 +22,11 @@ fn main() { //~^ ERROR mismatched types: expected `u16` but found `i32` let a = 3i; - + fn identity_i(n: int) -> int { n } identity_i(a); // ok - identity_u16(a); + identity_u16(a); //~^ ERROR mismatched types: expected `u16` but found `int` } diff --git a/src/test/compile-fail/unique-object-noncopyable.rs b/src/test/compile-fail/unique-object-noncopyable.rs index edc8a47822d72..95945b0b5baa4 100644 --- a/src/test/compile-fail/unique-object-noncopyable.rs +++ b/src/test/compile-fail/unique-object-noncopyable.rs @@ -31,4 +31,3 @@ fn main() { let y: ~Foo = x as ~Foo; let _z = copy y; //~ ERROR copying a value of non-copyable type } - diff --git a/src/test/compile-fail/use-after-move-based-on-type.rs b/src/test/compile-fail/use-after-move-based-on-type.rs index 6c268c5e13c83..3d176bb339d83 100644 --- a/src/test/compile-fail/use-after-move-based-on-type.rs +++ b/src/test/compile-fail/use-after-move-based-on-type.rs @@ -13,4 +13,3 @@ fn main() { let _y = x; io::println(x); //~ ERROR use of moved value } - diff --git a/src/test/compile-fail/use-after-move-self-based-on-type.rs b/src/test/compile-fail/use-after-move-self-based-on-type.rs index b0a2bc8ec1275..627b8924b6707 100644 --- a/src/test/compile-fail/use-after-move-self-based-on-type.rs +++ b/src/test/compile-fail/use-after-move-self-based-on-type.rs @@ -19,4 +19,3 @@ fn main() { let x = S { x: 1 }; io::println(x.foo().to_str()); } - diff --git a/src/test/compile-fail/use-after-move-self.rs b/src/test/compile-fail/use-after-move-self.rs index 3eded9fd4f39c..11f37df45417c 100644 --- a/src/test/compile-fail/use-after-move-self.rs +++ b/src/test/compile-fail/use-after-move-self.rs @@ -15,4 +15,3 @@ fn main() { let x = S { x: ~1 }; io::println(x.foo().to_str()); } - diff --git a/src/test/compile-fail/view-items-at-top.rs b/src/test/compile-fail/view-items-at-top.rs index a637836320df4..023be703cca77 100644 --- a/src/test/compile-fail/view-items-at-top.rs +++ b/src/test/compile-fail/view-items-at-top.rs @@ -19,4 +19,3 @@ use std::net; //~ ERROR view items must be declared at the top fn main() { } - diff --git a/src/test/compile-fail/while-type-error.rs b/src/test/compile-fail/while-type-error.rs index f9d3dce750890..ecab746373a98 100644 --- a/src/test/compile-fail/while-type-error.rs +++ b/src/test/compile-fail/while-type-error.rs @@ -11,4 +11,3 @@ // error-pattern: mismatched types fn main() { while main { } } - diff --git a/src/test/compile-fail/xc-private-method.rs b/src/test/compile-fail/xc-private-method.rs index d194820df9408..e8777a0a9f256 100644 --- a/src/test/compile-fail/xc-private-method.rs +++ b/src/test/compile-fail/xc-private-method.rs @@ -6,4 +6,3 @@ extern mod xc_private_method_lib; fn main() { let _ = xc_private_method_lib::Foo::new(); //~ ERROR function `new` is private } - diff --git a/src/test/pretty/doc-comments.rs b/src/test/pretty/doc-comments.rs index a866afd240592..45e242c0ca049 100644 --- a/src/test/pretty/doc-comments.rs +++ b/src/test/pretty/doc-comments.rs @@ -22,7 +22,7 @@ fn b() { ////////////////////////////////// // some single-line non-doc comment preceded by a separator -////////////////////////////////// +////////////////////////////////// /// some single-line outer-docs preceded by a separator /// (and trailing whitespaces) fn c() { } diff --git a/src/test/run-fail/assert-as-macro.rs b/src/test/run-fail/assert-as-macro.rs index 07813b91e571d..f715e21f781bd 100644 --- a/src/test/run-fail/assert-as-macro.rs +++ b/src/test/run-fail/assert-as-macro.rs @@ -3,4 +3,3 @@ fn main() { assert!(1 == 2); } - diff --git a/src/test/run-fail/borrowck-wg-fail-3.rs b/src/test/run-fail/borrowck-wg-fail-3.rs index ad4c794212121..b239bfc3b3142 100644 --- a/src/test/run-fail/borrowck-wg-fail-3.rs +++ b/src/test/run-fail/borrowck-wg-fail-3.rs @@ -5,4 +5,3 @@ fn main() { let y: &mut int = x; *x = 5; } - diff --git a/src/test/run-fail/borrowck-wg-fail.rs b/src/test/run-fail/borrowck-wg-fail.rs index d393832c6e862..93e7f9275b6cf 100644 --- a/src/test/run-fail/borrowck-wg-fail.rs +++ b/src/test/run-fail/borrowck-wg-fail.rs @@ -10,4 +10,3 @@ fn main() { let x = @mut 3; f(x, x); } - diff --git a/src/test/run-fail/unwind-resource-fail3.rs b/src/test/run-fail/unwind-resource-fail3.rs index d3ba5737b71f6..bfbad0b5aea62 100644 --- a/src/test/run-fail/unwind-resource-fail3.rs +++ b/src/test/run-fail/unwind-resource-fail3.rs @@ -14,7 +14,7 @@ struct faily_box { i: @int } // What happens to the box pointer owned by this class? - + fn faily_box(i: @int) -> faily_box { faily_box { i: i } } #[unsafe_destructor] diff --git a/src/test/run-pass-fulldeps/qquote.rs b/src/test/run-pass-fulldeps/qquote.rs index 9bfe29a5e8e4c..284195f3f04ec 100644 --- a/src/test/run-pass-fulldeps/qquote.rs +++ b/src/test/run-pass-fulldeps/qquote.rs @@ -85,4 +85,3 @@ fn check_pp(cx: fake_ext_ctxt, assert!(s == expect); } } - diff --git a/src/test/run-pass-fulldeps/quote-tokens.rs b/src/test/run-pass-fulldeps/quote-tokens.rs index ccee163eafe5b..3ec54955229d3 100644 --- a/src/test/run-pass-fulldeps/quote-tokens.rs +++ b/src/test/run-pass-fulldeps/quote-tokens.rs @@ -27,4 +27,3 @@ fn syntax_extension(ext_cx: @ext_ctxt) { fn main() { } - diff --git a/src/test/run-pass/anon-trait-static-method.rs b/src/test/run-pass/anon-trait-static-method.rs index 8e11786786ff9..91bbbf5c0a0df 100644 --- a/src/test/run-pass/anon-trait-static-method.rs +++ b/src/test/run-pass/anon-trait-static-method.rs @@ -22,4 +22,3 @@ pub fn main() { let x = Foo::new(); io::println(x.x.to_str()); } - diff --git a/src/test/run-pass/anon_trait_static_method_exe.rs b/src/test/run-pass/anon_trait_static_method_exe.rs index 5d8b79836883d..1baeca00083fd 100644 --- a/src/test/run-pass/anon_trait_static_method_exe.rs +++ b/src/test/run-pass/anon_trait_static_method_exe.rs @@ -18,6 +18,3 @@ pub fn main() { let x = Foo::new(); io::println(x.x.to_str()); } - - - diff --git a/src/test/run-pass/auto-ref-newtype.rs b/src/test/run-pass/auto-ref-newtype.rs index bac6d1aa740a8..a9fca0ccb1589 100644 --- a/src/test/run-pass/auto-ref-newtype.rs +++ b/src/test/run-pass/auto-ref-newtype.rs @@ -21,4 +21,3 @@ pub fn main() { let m = Foo(3); assert!(m.len() == 3); } - diff --git a/src/test/run-pass/auto-ref.rs b/src/test/run-pass/auto-ref.rs index f7c0f513a9df6..ee250b972190c 100644 --- a/src/test/run-pass/auto-ref.rs +++ b/src/test/run-pass/auto-ref.rs @@ -26,4 +26,3 @@ pub fn main() { let x = Foo { x: 3 }; x.printme(); } - diff --git a/src/test/run-pass/autoderef-and-borrow-method-receiver.rs b/src/test/run-pass/autoderef-and-borrow-method-receiver.rs index 883cffa792bfb..2bc6df4703042 100644 --- a/src/test/run-pass/autoderef-and-borrow-method-receiver.rs +++ b/src/test/run-pass/autoderef-and-borrow-method-receiver.rs @@ -22,4 +22,3 @@ fn g(x: &mut Foo) { pub fn main() { } - diff --git a/src/test/run-pass/bare-static-string.rs b/src/test/run-pass/bare-static-string.rs index d8015f0b92c7e..6208a9c3cc3e4 100644 --- a/src/test/run-pass/bare-static-string.rs +++ b/src/test/run-pass/bare-static-string.rs @@ -12,4 +12,3 @@ pub fn main() { let x: &'static str = "foo"; io::println(x); } - diff --git a/src/test/run-pass/binops.rs b/src/test/run-pass/binops.rs index e7624c9e3b939..e755a34f0589e 100644 --- a/src/test/run-pass/binops.rs +++ b/src/test/run-pass/binops.rs @@ -104,7 +104,7 @@ fn p(x: int, y: int) -> p { fn test_class() { let mut q = p(1, 2); let mut r = p(1, 2); - + unsafe { error!("q = %x, r = %x", (::core::cast::transmute::<*p, uint>(&q)), diff --git a/src/test/run-pass/block-arg-in-parentheses.rs b/src/test/run-pass/block-arg-in-parentheses.rs index ce0b85f414b39..ad53bd2275451 100644 --- a/src/test/run-pass/block-arg-in-parentheses.rs +++ b/src/test/run-pass/block-arg-in-parentheses.rs @@ -33,4 +33,3 @@ pub fn main() { assert!(w_paren2(~[0, 1, 2, 3]) == -4); assert!(w_ret(~[0, 1, 2, 3]) == -4); } - diff --git a/src/test/run-pass/borrow-by-val-method-receiver.rs b/src/test/run-pass/borrow-by-val-method-receiver.rs index fdb51124f0eb9..fb4316ca1f520 100644 --- a/src/test/run-pass/borrow-by-val-method-receiver.rs +++ b/src/test/run-pass/borrow-by-val-method-receiver.rs @@ -20,4 +20,3 @@ pub fn main() { let items = ~[ 3, 5, 1, 2, 4 ]; items.foo(); } - diff --git a/src/test/run-pass/borrowck-wg-simple.rs b/src/test/run-pass/borrowck-wg-simple.rs index adf2403ec63d6..f28b0e4c4ec13 100644 --- a/src/test/run-pass/borrowck-wg-simple.rs +++ b/src/test/run-pass/borrowck-wg-simple.rs @@ -6,4 +6,3 @@ pub fn main() { let x = @mut 3; f(x); } - diff --git a/src/test/run-pass/boxed-trait-with-vstore.rs b/src/test/run-pass/boxed-trait-with-vstore.rs index 1aac86238dc58..1313a17f81db0 100644 --- a/src/test/run-pass/boxed-trait-with-vstore.rs +++ b/src/test/run-pass/boxed-trait-with-vstore.rs @@ -22,4 +22,3 @@ pub fn main() { let x = @3 as @Foo; x.foo(); } - diff --git a/src/test/run-pass/break.rs b/src/test/run-pass/break.rs index b3f524c0ad713..a182dcf2ca0b2 100644 --- a/src/test/run-pass/break.rs +++ b/src/test/run-pass/break.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - - pub fn main() { let mut i = 0; while i < 20 { i += 1; if i == 10 { break; } } @@ -22,8 +20,8 @@ pub fn main() { i = 0; while i < 10 { i += 1; if i % 2 == 0 { loop; } assert!((i % 2 != 0)); } i = 0; - loop { - i += 1; if i % 2 == 0 { loop; } assert!((i % 2 != 0)); + loop { + i += 1; if i % 2 == 0 { loop; } assert!((i % 2 != 0)); if i >= 10 { break; } } for vec::each(~[1, 2, 3, 4, 5, 6]) |x| { diff --git a/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs b/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs index 68bc567cf5108..76f4e3b68f7c2 100644 --- a/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs +++ b/src/test/run-pass/class-cast-to-trait-cross-crate-2.rs @@ -24,4 +24,3 @@ pub fn main() { let nyan : @ToStr = @cat(0u, 2, ~"nyan") as @ToStr; print_out(nyan, ~"nyan"); } - diff --git a/src/test/run-pass/class-impl-parameterized-trait.rs b/src/test/run-pass/class-impl-parameterized-trait.rs index 53ae0021a91b9..04784b5c51507 100644 --- a/src/test/run-pass/class-impl-parameterized-trait.rs +++ b/src/test/run-pass/class-impl-parameterized-trait.rs @@ -48,7 +48,7 @@ class cat : map { } fn size() -> uint { self.meows as uint } - fn insert(+k: int, +v: bool) -> bool { + fn insert(+k: int, +v: bool) -> bool { if v { self.meows += k; } else { self.meows -= k; }; true } diff --git a/src/test/run-pass/cleanup-copy-mode.rs b/src/test/run-pass/cleanup-copy-mode.rs index 41f76b1b4f2f3..b334f32f344b5 100644 --- a/src/test/run-pass/cleanup-copy-mode.rs +++ b/src/test/run-pass/cleanup-copy-mode.rs @@ -16,4 +16,3 @@ pub fn main() { adder(@2, failer()); () }))); } - diff --git a/src/test/run-pass/clone-with-exterior.rs b/src/test/run-pass/clone-with-exterior.rs index 57c4f91142dd8..ae2983b159425 100644 --- a/src/test/run-pass/clone-with-exterior.rs +++ b/src/test/run-pass/clone-with-exterior.rs @@ -18,7 +18,7 @@ struct Pair { pub fn main() { let z = ~Pair { a : 10, b : 12}; - + let f: ~fn() = || { assert!((z.a == 10)); assert!((z.b == 12)); diff --git a/src/test/run-pass/conditional-compile.rs b/src/test/run-pass/conditional-compile.rs index 609bfe7a4cb2a..73fdb219c1941 100644 --- a/src/test/run-pass/conditional-compile.rs +++ b/src/test/run-pass/conditional-compile.rs @@ -27,7 +27,7 @@ mod rustrt { // module was translated pub fn bogus(); } - + #[abi = "cdecl"] pub extern {} } diff --git a/src/test/run-pass/const-enum-vec-index.rs b/src/test/run-pass/const-enum-vec-index.rs index 01bab0778329f..4c81eaae1d802 100644 --- a/src/test/run-pass/const-enum-vec-index.rs +++ b/src/test/run-pass/const-enum-vec-index.rs @@ -14,7 +14,7 @@ static C0: E = C[0]; static C1: E = C[1]; pub fn main() { - match C0 { + match C0 { V0 => (), _ => fail!() } diff --git a/src/test/run-pass/const-enum-vec-ptr.rs b/src/test/run-pass/const-enum-vec-ptr.rs index 8615356965e35..95c4ed836c769 100644 --- a/src/test/run-pass/const-enum-vec-ptr.rs +++ b/src/test/run-pass/const-enum-vec-ptr.rs @@ -16,7 +16,7 @@ pub fn main() { V1(n) => assert!(n == 0xDEADBEE), _ => fail!() } - match C[2] { + match C[2] { V0 => (), _ => fail!() } diff --git a/src/test/run-pass/const-enum-vector.rs b/src/test/run-pass/const-enum-vector.rs index 7ae2c5a2fee7c..3dc5b918f7f58 100644 --- a/src/test/run-pass/const-enum-vector.rs +++ b/src/test/run-pass/const-enum-vector.rs @@ -16,7 +16,7 @@ pub fn main() { V1(n) => assert!(n == 0xDEADBEE), _ => fail!() } - match C[2] { + match C[2] { V0 => (), _ => fail!() } diff --git a/src/test/run-pass/const-expr-in-fixed-length-vec.rs b/src/test/run-pass/const-expr-in-fixed-length-vec.rs index c593fd39aaacd..48b41d0463307 100644 --- a/src/test/run-pass/const-expr-in-fixed-length-vec.rs +++ b/src/test/run-pass/const-expr-in-fixed-length-vec.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that constant expressions can be used for declaring the +// Check that constant expressions can be used for declaring the // type of a fixed length vector. pub fn main() { diff --git a/src/test/run-pass/const-expr-in-vec-repeat.rs b/src/test/run-pass/const-expr-in-vec-repeat.rs index be54c6eb7be49..f10cef520ad24 100644 --- a/src/test/run-pass/const-expr-in-vec-repeat.rs +++ b/src/test/run-pass/const-expr-in-vec-repeat.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// Check that constant expressions can be used in vec repeat syntax. +// Check that constant expressions can be used in vec repeat syntax. pub fn main() { diff --git a/src/test/run-pass/const-tuple-struct.rs b/src/test/run-pass/const-tuple-struct.rs index a68e12b7b107a..828c20912a1cb 100644 --- a/src/test/run-pass/const-tuple-struct.rs +++ b/src/test/run-pass/const-tuple-struct.rs @@ -20,4 +20,3 @@ pub fn main() { } } } - diff --git a/src/test/run-pass/const-unit-struct.rs b/src/test/run-pass/const-unit-struct.rs index b4acde098baf3..7e6d9f0bee9b9 100644 --- a/src/test/run-pass/const-unit-struct.rs +++ b/src/test/run-pass/const-unit-struct.rs @@ -17,4 +17,3 @@ pub fn main() { Foo => {} } } - diff --git a/src/test/run-pass/const-vec-syntax.rs b/src/test/run-pass/const-vec-syntax.rs index c3e882ac04f9e..625f6ec30cc13 100644 --- a/src/test/run-pass/const-vec-syntax.rs +++ b/src/test/run-pass/const-vec-syntax.rs @@ -14,4 +14,3 @@ pub fn main() { let v = [ 1, 2, 3 ]; f(v); } - diff --git a/src/test/run-pass/consts-in-patterns.rs b/src/test/run-pass/consts-in-patterns.rs index 408c0e612f431..c0520cf737ffc 100644 --- a/src/test/run-pass/consts-in-patterns.rs +++ b/src/test/run-pass/consts-in-patterns.rs @@ -20,4 +20,3 @@ pub fn main() { }; assert!(y == 2); } - diff --git a/src/test/run-pass/cycle-collection.rs b/src/test/run-pass/cycle-collection.rs index 0512b8a1267cf..0e9be022113d6 100644 --- a/src/test/run-pass/cycle-collection.rs +++ b/src/test/run-pass/cycle-collection.rs @@ -21,4 +21,3 @@ fn f() { pub fn main() { f(); } - diff --git a/src/test/run-pass/default-method-simple.rs b/src/test/run-pass/default-method-simple.rs index 62b29d4e4eb2f..3f44f3f1ef88c 100644 --- a/src/test/run-pass/default-method-simple.rs +++ b/src/test/run-pass/default-method-simple.rs @@ -32,4 +32,3 @@ pub fn main() { let a = A { x: 1 }; a.f(); } - diff --git a/src/test/run-pass/deriving-clone-enum.rs b/src/test/run-pass/deriving-clone-enum.rs index 6caceeb2d7015..969e1fb5dd60e 100644 --- a/src/test/run-pass/deriving-clone-enum.rs +++ b/src/test/run-pass/deriving-clone-enum.rs @@ -16,4 +16,3 @@ enum E { } pub fn main() {} - diff --git a/src/test/run-pass/deriving-clone-generic-enum.rs b/src/test/run-pass/deriving-clone-generic-enum.rs index a868db2425cc2..23841017e933e 100644 --- a/src/test/run-pass/deriving-clone-generic-enum.rs +++ b/src/test/run-pass/deriving-clone-generic-enum.rs @@ -6,4 +6,3 @@ enum E { } fn main() {} - diff --git a/src/test/run-pass/deriving-clone-generic-struct.rs b/src/test/run-pass/deriving-clone-generic-struct.rs index b157cd321cf5a..0a7a5a3aa7549 100644 --- a/src/test/run-pass/deriving-clone-generic-struct.rs +++ b/src/test/run-pass/deriving-clone-generic-struct.rs @@ -16,4 +16,3 @@ struct S { } pub fn main() {} - diff --git a/src/test/run-pass/deriving-clone-generic-tuple-struct.rs b/src/test/run-pass/deriving-clone-generic-tuple-struct.rs index aeaa9ed726d2b..d6a69e8e6ac52 100644 --- a/src/test/run-pass/deriving-clone-generic-tuple-struct.rs +++ b/src/test/run-pass/deriving-clone-generic-tuple-struct.rs @@ -2,4 +2,3 @@ struct S(T, ()); fn main() {} - diff --git a/src/test/run-pass/deriving-clone-tuple-struct.rs b/src/test/run-pass/deriving-clone-tuple-struct.rs index c534883f600ce..1e5c8c80f8c49 100644 --- a/src/test/run-pass/deriving-clone-tuple-struct.rs +++ b/src/test/run-pass/deriving-clone-tuple-struct.rs @@ -12,4 +12,3 @@ struct S((), ()); pub fn main() {} - diff --git a/src/test/run-pass/deriving-via-extension-c-enum.rs b/src/test/run-pass/deriving-via-extension-c-enum.rs index 67893ae9c1eec..81c4ce013f24c 100644 --- a/src/test/run-pass/deriving-via-extension-c-enum.rs +++ b/src/test/run-pass/deriving-via-extension-c-enum.rs @@ -23,4 +23,3 @@ pub fn main() { assert!(a.eq(&b)); assert!(!a.ne(&b)); } - diff --git a/src/test/run-pass/deriving-via-extension-enum.rs b/src/test/run-pass/deriving-via-extension-enum.rs index 7481bae508b68..fac0d402a3826 100644 --- a/src/test/run-pass/deriving-via-extension-enum.rs +++ b/src/test/run-pass/deriving-via-extension-enum.rs @@ -22,4 +22,3 @@ pub fn main() { assert!(a.eq(&b)); assert!(!a.ne(&b)); } - diff --git a/src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs b/src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs index 5ceb8c48750d9..b08117b71fa2f 100644 --- a/src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs +++ b/src/test/run-pass/deriving-via-extension-iter-bytes-enum.rs @@ -25,4 +25,3 @@ enum A { } pub fn main(){} - diff --git a/src/test/run-pass/deriving-via-extension-iter-bytes-struct.rs b/src/test/run-pass/deriving-via-extension-iter-bytes-struct.rs index 9f18cb6ac58a7..8369d12ecddcb 100644 --- a/src/test/run-pass/deriving-via-extension-iter-bytes-struct.rs +++ b/src/test/run-pass/deriving-via-extension-iter-bytes-struct.rs @@ -18,5 +18,3 @@ struct Foo { } pub fn main() {} - - diff --git a/src/test/run-pass/deriving-via-extension-struct-like-enum-variant.rs b/src/test/run-pass/deriving-via-extension-struct-like-enum-variant.rs index 712767efacfa0..4ef8fb6b5d9b7 100644 --- a/src/test/run-pass/deriving-via-extension-struct-like-enum-variant.rs +++ b/src/test/run-pass/deriving-via-extension-struct-like-enum-variant.rs @@ -9,4 +9,3 @@ pub fn main() { assert!(x == x); assert!(!(x != x)); } - diff --git a/src/test/run-pass/deriving-via-extension-struct.rs b/src/test/run-pass/deriving-via-extension-struct.rs index 1e004d1a8c00a..c0e7ee36b16da 100644 --- a/src/test/run-pass/deriving-via-extension-struct.rs +++ b/src/test/run-pass/deriving-via-extension-struct.rs @@ -23,4 +23,3 @@ pub fn main() { assert!(a.eq(&b)); assert!(!a.ne(&b)); } - diff --git a/src/test/run-pass/deriving-via-extension-type-params.rs b/src/test/run-pass/deriving-via-extension-type-params.rs index f310643f94393..85a89c629895d 100644 --- a/src/test/run-pass/deriving-via-extension-type-params.rs +++ b/src/test/run-pass/deriving-via-extension-type-params.rs @@ -26,4 +26,3 @@ pub fn main() { assert!(a.eq(&b)); assert!(!a.ne(&b)); } - diff --git a/src/test/run-pass/drop-trait-generic.rs b/src/test/run-pass/drop-trait-generic.rs index 21b85084117c4..65c3faac2b304 100644 --- a/src/test/run-pass/drop-trait-generic.rs +++ b/src/test/run-pass/drop-trait-generic.rs @@ -22,4 +22,3 @@ impl ::core::ops::Drop for S { pub fn main() { let x = S { x: 1 }; } - diff --git a/src/test/run-pass/drop-trait.rs b/src/test/run-pass/drop-trait.rs index 3eddda376a836..b516c6f6de4bd 100644 --- a/src/test/run-pass/drop-trait.rs +++ b/src/test/run-pass/drop-trait.rs @@ -21,4 +21,3 @@ impl Drop for Foo { pub fn main() { let x: Foo = Foo { x: 3 }; } - diff --git a/src/test/run-pass/enum-discrim-range-overflow.rs b/src/test/run-pass/enum-discrim-range-overflow.rs index a6806fba14269..37e457d547bf9 100644 --- a/src/test/run-pass/enum-discrim-range-overflow.rs +++ b/src/test/run-pass/enum-discrim-range-overflow.rs @@ -9,23 +9,23 @@ // except according to those terms. pub enum E64 { - H64 = 0x7FFF_FFFF_FFFF_FFFF, - L64 = 0x8000_0000_0000_0000 + H64 = 0x7FFF_FFFF_FFFF_FFFF, + L64 = 0x8000_0000_0000_0000 } pub enum E32 { - H32 = 0x7FFF_FFFF, - L32 = 0x8000_0000 + H32 = 0x7FFF_FFFF, + L32 = 0x8000_0000 } pub fn f(e64: E64, e32: E32) -> (bool,bool) { - (match e64 { - H64 => true, - L64 => false - }, - match e32 { - H32 => true, - L32 => false - }) + (match e64 { + H64 => true, + L64 => false + }, + match e32 { + H32 => true, + L32 => false + }) } pub fn main() { } diff --git a/src/test/run-pass/enum-disr-val-pretty.rs b/src/test/run-pass/enum-disr-val-pretty.rs index 39a807789ecec..2c61351cf44a5 100644 --- a/src/test/run-pass/enum-disr-val-pretty.rs +++ b/src/test/run-pass/enum-disr-val-pretty.rs @@ -23,4 +23,3 @@ fn test_color(color: color, val: int, name: ~str) { assert!(color as int == val); assert!(color as float == val as float); } - diff --git a/src/test/run-pass/enum-export-inheritance.rs b/src/test/run-pass/enum-export-inheritance.rs index c3beebdb8ae85..49823155043f4 100644 --- a/src/test/run-pass/enum-export-inheritance.rs +++ b/src/test/run-pass/enum-export-inheritance.rs @@ -19,4 +19,3 @@ mod a { pub fn main() { let x = a::Bar; } - diff --git a/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs b/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs index b5cf15f3b3863..4764dbb9417fb 100644 --- a/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs +++ b/src/test/run-pass/enum-nullable-simplifycfg-misopt.rs @@ -17,8 +17,8 @@ enum List { Nil, Cons(X, @List) } pub fn main() { match Cons(10, @Nil) { - Cons(10, _) => {} - Nil => {} - _ => fail!() + Cons(10, _) => {} + Nil => {} + _ => fail!() } } diff --git a/src/test/run-pass/explicit-self-generic.rs b/src/test/run-pass/explicit-self-generic.rs index 1a2a8cab3032c..ac19592accf8b 100644 --- a/src/test/run-pass/explicit-self-generic.rs +++ b/src/test/run-pass/explicit-self-generic.rs @@ -40,4 +40,3 @@ pub fn main() { let mut m = ~linear_map::<(),()>(); assert!(m.len() == 0); } - diff --git a/src/test/run-pass/explicit-self-objects-box.rs b/src/test/run-pass/explicit-self-objects-box.rs index 105aad03083d7..12a1780e029b1 100644 --- a/src/test/run-pass/explicit-self-objects-box.rs +++ b/src/test/run-pass/explicit-self-objects-box.rs @@ -30,5 +30,3 @@ pub fn main() { y.f(); y.f(); } - - diff --git a/src/test/run-pass/explicit-self-objects-simple.rs b/src/test/run-pass/explicit-self-objects-simple.rs index de2926b0e7efc..814365a835429 100644 --- a/src/test/run-pass/explicit-self-objects-simple.rs +++ b/src/test/run-pass/explicit-self-objects-simple.rs @@ -27,5 +27,3 @@ pub fn main() { let y = x as @Foo; y.f(); } - - diff --git a/src/test/run-pass/explicit-self-objects-uniq.rs b/src/test/run-pass/explicit-self-objects-uniq.rs index e99a6bbedc06c..dadf53fb9bc6a 100644 --- a/src/test/run-pass/explicit-self-objects-uniq.rs +++ b/src/test/run-pass/explicit-self-objects-uniq.rs @@ -27,5 +27,3 @@ pub fn main() { let y = x as ~Foo; y.f(); } - - diff --git a/src/test/run-pass/explicit_self_xcrate_exe.rs b/src/test/run-pass/explicit_self_xcrate_exe.rs index e217e6ebd411d..6f6520e804043 100644 --- a/src/test/run-pass/explicit_self_xcrate_exe.rs +++ b/src/test/run-pass/explicit_self_xcrate_exe.rs @@ -18,4 +18,3 @@ pub fn main() { let x = Bar { x: ~"hello" }; x.f(); } - diff --git a/src/test/run-pass/expr-repeat-vstore.rs b/src/test/run-pass/expr-repeat-vstore.rs index 972b2763b1b59..e48abc5753492 100644 --- a/src/test/run-pass/expr-repeat-vstore.rs +++ b/src/test/run-pass/expr-repeat-vstore.rs @@ -20,4 +20,3 @@ fn main() { println((copy v[3]).to_str()); println((copy v[4]).to_str()); } - diff --git a/src/test/run-pass/extern-mod-abi.rs b/src/test/run-pass/extern-mod-abi.rs index 7eada51b7c719..84fd1b40bf7a5 100644 --- a/src/test/run-pass/extern-mod-abi.rs +++ b/src/test/run-pass/extern-mod-abi.rs @@ -13,4 +13,3 @@ extern "C" { } pub fn main() {} - diff --git a/src/test/run-pass/extern-mod-ordering-exe.rs b/src/test/run-pass/extern-mod-ordering-exe.rs index b60302277b326..5836245ff78cf 100644 --- a/src/test/run-pass/extern-mod-ordering-exe.rs +++ b/src/test/run-pass/extern-mod-ordering-exe.rs @@ -8,4 +8,3 @@ use extern_mod_ordering_lib::extern_mod_ordering_lib; fn main() { extern_mod_ordering_lib::f(); } - diff --git a/src/test/run-pass/extern-mod-syntax.rs b/src/test/run-pass/extern-mod-syntax.rs index b6b2e0042633d..c98b5ebc23854 100644 --- a/src/test/run-pass/extern-mod-syntax.rs +++ b/src/test/run-pass/extern-mod-syntax.rs @@ -16,4 +16,3 @@ use std::json::Object; pub fn main() { io::println("Hello world!"); } - diff --git a/src/test/run-pass/extern-pass-TwoU16s.rs b/src/test/run-pass/extern-pass-TwoU16s.rs index f0343c4d2a267..ec65cbb5670b9 100644 --- a/src/test/run-pass/extern-pass-TwoU16s.rs +++ b/src/test/run-pass/extern-pass-TwoU16s.rs @@ -29,4 +29,3 @@ pub fn main() { assert!(x == y); } } - diff --git a/src/test/run-pass/extern-pass-TwoU32s.rs b/src/test/run-pass/extern-pass-TwoU32s.rs index 16d14a96cfe4f..6ac5967c54fd5 100644 --- a/src/test/run-pass/extern-pass-TwoU32s.rs +++ b/src/test/run-pass/extern-pass-TwoU32s.rs @@ -27,4 +27,3 @@ pub fn main() { assert!(x == y); } } - diff --git a/src/test/run-pass/extern-pass-TwoU64s-ref.rs b/src/test/run-pass/extern-pass-TwoU64s-ref.rs index 56d3f8ebbff7f..2b18dba90f7fe 100644 --- a/src/test/run-pass/extern-pass-TwoU64s-ref.rs +++ b/src/test/run-pass/extern-pass-TwoU64s-ref.rs @@ -26,4 +26,3 @@ pub fn main() { assert!(x == y); } } - diff --git a/src/test/run-pass/extern-pass-TwoU64s.rs b/src/test/run-pass/extern-pass-TwoU64s.rs index 24dd3db8aca1c..3a1f4a51238f1 100644 --- a/src/test/run-pass/extern-pass-TwoU64s.rs +++ b/src/test/run-pass/extern-pass-TwoU64s.rs @@ -31,4 +31,3 @@ pub fn main() { assert!(x == y); } } - diff --git a/src/test/run-pass/extern-pass-TwoU8s.rs b/src/test/run-pass/extern-pass-TwoU8s.rs index 213e9a68a7f89..7d08b436908dc 100644 --- a/src/test/run-pass/extern-pass-TwoU8s.rs +++ b/src/test/run-pass/extern-pass-TwoU8s.rs @@ -29,4 +29,3 @@ pub fn main() { assert!(x == y); } } - diff --git a/src/test/run-pass/extern-pass-char.rs b/src/test/run-pass/extern-pass-char.rs index f4fa6bde392b9..645396e5a988d 100644 --- a/src/test/run-pass/extern-pass-char.rs +++ b/src/test/run-pass/extern-pass-char.rs @@ -19,4 +19,3 @@ pub fn main() { assert!(22_u8 == rust_dbg_extern_identity_u8(22_u8)); } } - diff --git a/src/test/run-pass/extern-pass-double.rs b/src/test/run-pass/extern-pass-double.rs index 4e16acb4ad580..3a6dd26a9dc6c 100644 --- a/src/test/run-pass/extern-pass-double.rs +++ b/src/test/run-pass/extern-pass-double.rs @@ -17,4 +17,3 @@ pub fn main() { assert!(22.0_f64 == rust_dbg_extern_identity_double(22.0_f64)); } } - diff --git a/src/test/run-pass/extern-pass-u32.rs b/src/test/run-pass/extern-pass-u32.rs index 14d05f821770a..19c4d6e153998 100644 --- a/src/test/run-pass/extern-pass-u32.rs +++ b/src/test/run-pass/extern-pass-u32.rs @@ -19,4 +19,3 @@ pub fn main() { assert!(22_u32 == rust_dbg_extern_identity_u32(22_u32)); } } - diff --git a/src/test/run-pass/extern-pass-u64.rs b/src/test/run-pass/extern-pass-u64.rs index 2b5a03a4d7122..cce669999222a 100644 --- a/src/test/run-pass/extern-pass-u64.rs +++ b/src/test/run-pass/extern-pass-u64.rs @@ -19,4 +19,3 @@ pub fn main() { assert!(22_u64 == rust_dbg_extern_identity_u64(22_u64)); } } - diff --git a/src/test/run-pass/extern-pub.rs b/src/test/run-pass/extern-pub.rs index 9bfeec8c7d6ce..f9b0ccbb5480e 100644 --- a/src/test/run-pass/extern-pub.rs +++ b/src/test/run-pass/extern-pub.rs @@ -6,5 +6,3 @@ extern { pub fn main() { } - - diff --git a/src/test/run-pass/fat-arrow-alt.rs b/src/test/run-pass/fat-arrow-alt.rs index 4b8b552bfaed3..f6b49960fad70 100644 --- a/src/test/run-pass/fat-arrow-alt.rs +++ b/src/test/run-pass/fat-arrow-alt.rs @@ -23,4 +23,3 @@ pub fn main() { blue => { 3 } }); } - diff --git a/src/test/run-pass/fixed_length_copy.rs b/src/test/run-pass/fixed_length_copy.rs index 5daa525d9b161..7ee3f5173b030 100644 --- a/src/test/run-pass/fixed_length_copy.rs +++ b/src/test/run-pass/fixed_length_copy.rs @@ -10,7 +10,7 @@ // error on implicit copies to check fixed length vectors -// are implicitly copyable +// are implicitly copyable #[deny(implicit_copies)] pub fn main() { let arr = [1,2,3]; diff --git a/src/test/run-pass/float-literal-inference.rs b/src/test/run-pass/float-literal-inference.rs index 2b59d7bfceeb2..a5246eef0b0ed 100644 --- a/src/test/run-pass/float-literal-inference.rs +++ b/src/test/run-pass/float-literal-inference.rs @@ -20,4 +20,3 @@ pub fn main() { let z = S { z: 1.0 }; io::println(z.z.to_str()); } - diff --git a/src/test/run-pass/fn-pattern-expected-type-2.rs b/src/test/run-pass/fn-pattern-expected-type-2.rs index f9bf9b5915eb1..501bd81d5589c 100644 --- a/src/test/run-pass/fn-pattern-expected-type-2.rs +++ b/src/test/run-pass/fn-pattern-expected-type-2.rs @@ -15,4 +15,3 @@ pub fn main() { io::println(x.to_str()); } } - diff --git a/src/test/run-pass/fn-pattern-expected-type.rs b/src/test/run-pass/fn-pattern-expected-type.rs index dc3f33a1991a4..f3949a0f43bf3 100644 --- a/src/test/run-pass/fn-pattern-expected-type.rs +++ b/src/test/run-pass/fn-pattern-expected-type.rs @@ -15,4 +15,3 @@ pub fn main() { }; f((1, 2)); } - diff --git a/src/test/run-pass/foreign-mod-unused-const.rs b/src/test/run-pass/foreign-mod-unused-const.rs index 430da7a3f608b..4909e9d7e568f 100644 --- a/src/test/run-pass/foreign-mod-unused-const.rs +++ b/src/test/run-pass/foreign-mod-unused-const.rs @@ -17,4 +17,3 @@ mod foo { pub fn main() { } - diff --git a/src/test/run-pass/functional-struct-update.rs b/src/test/run-pass/functional-struct-update.rs index f1db6db417a23..297b5e78a921c 100644 --- a/src/test/run-pass/functional-struct-update.rs +++ b/src/test/run-pass/functional-struct-update.rs @@ -18,4 +18,3 @@ pub fn main() { let c = Foo { x: 4, .. a}; io::println(fmt!("%?", c)); } - diff --git a/src/test/run-pass/generic-ivec-leak.rs b/src/test/run-pass/generic-ivec-leak.rs index 8d9b0fa6ddb85..ac6e3e1a69a99 100644 --- a/src/test/run-pass/generic-ivec-leak.rs +++ b/src/test/run-pass/generic-ivec-leak.rs @@ -11,4 +11,3 @@ enum wrapper { wrapped(T), } pub fn main() { let w = wrapped(~[1, 2, 3, 4, 5]); } - diff --git a/src/test/run-pass/generic-ivec.rs b/src/test/run-pass/generic-ivec.rs index 031821d990965..2a288c8abbf35 100644 --- a/src/test/run-pass/generic-ivec.rs +++ b/src/test/run-pass/generic-ivec.rs @@ -10,4 +10,3 @@ fn f(v: @T) { } pub fn main() { f(@~[1, 2, 3, 4, 5]); } - diff --git a/src/test/run-pass/generic-newtype-struct.rs b/src/test/run-pass/generic-newtype-struct.rs index 7c7d73eda1092..cf4279d67b84d 100644 --- a/src/test/run-pass/generic-newtype-struct.rs +++ b/src/test/run-pass/generic-newtype-struct.rs @@ -4,4 +4,3 @@ pub fn main() { let s = S(2i); io::println(s.to_str()); } - diff --git a/src/test/run-pass/generic-object.rs b/src/test/run-pass/generic-object.rs index ebfc362c72c43..54ae2c58e42ea 100644 --- a/src/test/run-pass/generic-object.rs +++ b/src/test/run-pass/generic-object.rs @@ -27,4 +27,3 @@ pub fn main() { let y = x as @Foo; assert!(y.get() == 1); } - diff --git a/src/test/run-pass/global-scope.rs b/src/test/run-pass/global-scope.rs index 3dd912dea9a13..9b292a325c03a 100644 --- a/src/test/run-pass/global-scope.rs +++ b/src/test/run-pass/global-scope.rs @@ -18,4 +18,3 @@ pub mod foo { } pub fn main() { return foo::g(); } - diff --git a/src/test/run-pass/impl-privacy-xc-1.rs b/src/test/run-pass/impl-privacy-xc-1.rs index df001c7ab212e..19d3caf818d19 100644 --- a/src/test/run-pass/impl-privacy-xc-1.rs +++ b/src/test/run-pass/impl-privacy-xc-1.rs @@ -7,4 +7,3 @@ pub fn main() { let fish = impl_privacy_xc_1::Fish { x: 1 }; fish.swim(); } - diff --git a/src/test/run-pass/impl-privacy-xc-2.rs b/src/test/run-pass/impl-privacy-xc-2.rs index 69bd31ab766da..74d9a34e1618c 100644 --- a/src/test/run-pass/impl-privacy-xc-2.rs +++ b/src/test/run-pass/impl-privacy-xc-2.rs @@ -8,4 +8,3 @@ pub fn main() { let fish2 = impl_privacy_xc_2::Fish { x: 2 }; io::println(if fish1.eq(&fish2) { "yes" } else { "no " }); } - diff --git a/src/test/run-pass/infinite-loops.rs b/src/test/run-pass/infinite-loops.rs index 611a4b9ccabdd..b2ed6d95c206a 100644 --- a/src/test/run-pass/infinite-loops.rs +++ b/src/test/run-pass/infinite-loops.rs @@ -21,9 +21,9 @@ fn loopy(n: int) { loop { } } -pub fn main() { +pub fn main() { // Commenting this out, as this will hang forever otherwise. // Even after seeing the comment above, I'm not sure what the // intention of this test is. - // do spawn { loopy(5) }; + // do spawn { loopy(5) }; } diff --git a/src/test/run-pass/instantiable.rs b/src/test/run-pass/instantiable.rs index c140a66ffe4d6..2173bae85e1e1 100644 --- a/src/test/run-pass/instantiable.rs +++ b/src/test/run-pass/instantiable.rs @@ -18,4 +18,3 @@ struct X { x: uint, nxt: *foo } pub fn main() { let x = foo(X {x: 0, nxt: ptr::null()}); } - diff --git a/src/test/run-pass/int-conversion-coherence.rs b/src/test/run-pass/int-conversion-coherence.rs index 235fab107e781..ef2a84da219c9 100644 --- a/src/test/run-pass/int-conversion-coherence.rs +++ b/src/test/run-pass/int-conversion-coherence.rs @@ -23,4 +23,3 @@ impl foo of plus for int { fn plus() -> int { self + 10 } } pub fn main() { assert!(10.plus() == 20); } - diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs index b96ea8cbb7b43..1a0d97a5c5b03 100644 --- a/src/test/run-pass/intrinsics-integer.rs +++ b/src/test/run-pass/intrinsics-integer.rs @@ -89,7 +89,7 @@ pub fn main() { assert!((cttz16(-1i16) == 0i16)); assert!((cttz32(-1i32) == 0i32)); assert!((cttz64(-1i64) == 0i64)); - + assert!((cttz8(0i8) == 8i8)); assert!((cttz16(0i16) == 16i16)); assert!((cttz32(0i32) == 32i32)); diff --git a/src/test/run-pass/intrinsics-math.rs b/src/test/run-pass/intrinsics-math.rs index 60e32a56ee5d8..6f9179bc89d09 100644 --- a/src/test/run-pass/intrinsics-math.rs +++ b/src/test/run-pass/intrinsics-math.rs @@ -83,7 +83,7 @@ pub fn main() { assert!((log2f32(8f32).fuzzy_eq(&3f32))); assert!((log2f64(f64::consts::e).fuzzy_eq(&f64::consts::log2_e))); - + assert!((fmaf32(1.0f32, 2.0f32, 5.0f32).fuzzy_eq(&7.0f32))); assert!((fmaf64(0.0f64, -2.0f64, f64::consts::e).fuzzy_eq(&f64::consts::e))); @@ -97,7 +97,7 @@ pub fn main() { // undefined reference to llvm.ceil.f32/64 //assert!((ceilf32(-2.3f32) == -2.0f32)); //assert!((ceilf64(3.8f64) == 4.0f64)); - + // Causes linker error // undefined reference to llvm.trunc.f32/64 //assert!((truncf32(0.1f32) == 0.0f32)); diff --git a/src/test/run-pass/issue-1516.rs b/src/test/run-pass/issue-1516.rs index 33be716cc5f48..fe3feeb3dbf90 100644 --- a/src/test/run-pass/issue-1516.rs +++ b/src/test/run-pass/issue-1516.rs @@ -10,4 +10,3 @@ // xfail-test pub fn main() { let early_error: @fn(str) -> ! = {|msg| fail!() }; } - diff --git a/src/test/run-pass/issue-2185.rs b/src/test/run-pass/issue-2185.rs index 8a553784c5e2e..5b320ddc06bb6 100644 --- a/src/test/run-pass/issue-2185.rs +++ b/src/test/run-pass/issue-2185.rs @@ -15,7 +15,7 @@ // notes on this test case: // On Thu, Apr 18, 2013 at 6:30 PM, John Clements wrote: // the "issue-2185.rs" test was xfailed with a ref to #2263. Issue #2263 is now fixed, so I tried it again, and after adding some &self parameters, I got this error: -// +// // Running /usr/local/bin/rustc: // issue-2185.rs:24:0: 26:1 error: conflicting implementations for a trait // issue-2185.rs:24 impl iterable for @fn(&fn(uint)) { @@ -25,7 +25,7 @@ // issue-2185.rs:20 impl iterable for @fn(&fn(A)) { // issue-2185.rs:21 fn iter(&self, blk: &fn(A)) { self(blk); } // issue-2185.rs:22 } -// +// // … so it looks like it's just not possible to implement both the generic iterable and iterable for the type iterable. Is it okay if I just remove this test? // // but Niko responded: diff --git a/src/test/run-pass/issue-2216.rs b/src/test/run-pass/issue-2216.rs index 98965cb6d9102..c3a2a4c0b7e24 100644 --- a/src/test/run-pass/issue-2216.rs +++ b/src/test/run-pass/issue-2216.rs @@ -10,7 +10,7 @@ pub fn main() { let mut x = 0; - + 'foo: loop { 'bar: loop { 'quux: loop { diff --git a/src/test/run-pass/issue-2526-a.rs b/src/test/run-pass/issue-2526-a.rs index c91b5dd303c09..39ce74947e997 100644 --- a/src/test/run-pass/issue-2526-a.rs +++ b/src/test/run-pass/issue-2526-a.rs @@ -15,4 +15,3 @@ extern mod issue_2526; use issue_2526::*; pub fn main() {} - diff --git a/src/test/run-pass/issue-2734.rs b/src/test/run-pass/issue-2734.rs index 7125e89287cbd..319146d0a810d 100644 --- a/src/test/run-pass/issue-2734.rs +++ b/src/test/run-pass/issue-2734.rs @@ -8,8 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -trait hax { } -impl hax for A { } +trait hax { } +impl hax for A { } fn perform_hax(x: @T) -> @hax { @x as @hax diff --git a/src/test/run-pass/issue-2904.rs b/src/test/run-pass/issue-2904.rs index ef7fd69157791..77cc6b3e1b5b5 100644 --- a/src/test/run-pass/issue-2904.rs +++ b/src/test/run-pass/issue-2904.rs @@ -37,7 +37,7 @@ impl to_str::ToStr for square { closed_lift => { ~"L" } open_lift => { ~"O" } earth => { ~"." } - empty => { ~" " } + empty => { ~" " } } } } diff --git a/src/test/run-pass/issue-3176.rs b/src/test/run-pass/issue-3176.rs index 03b1c127c55ff..55d62a5bf8ee3 100644 --- a/src/test/run-pass/issue-3176.rs +++ b/src/test/run-pass/issue-3176.rs @@ -20,7 +20,7 @@ pub fn main() { p2.recv(); error!("sibling fails"); fail!(); - } + } let (p3,c3) = comm::stream(); c.send(c3); c2.send(()); @@ -28,7 +28,7 @@ pub fn main() { let (p, c) = comm::stream(); (p, p3).select(); c.send(()); - }; + }; error!("parent tries"); assert!(!p.recv().try_send(())); error!("all done!"); diff --git a/src/test/run-pass/issue-3250.rs b/src/test/run-pass/issue-3250.rs index a563544b5c70d..0a93b89a94d42 100644 --- a/src/test/run-pass/issue-3250.rs +++ b/src/test/run-pass/issue-3250.rs @@ -2,6 +2,4 @@ type t = (uint, uint); - - pub fn main() { } diff --git a/src/test/run-pass/issue-3429.rs b/src/test/run-pass/issue-3429.rs index 67877795cc0d8..7bfb928e86d7d 100644 --- a/src/test/run-pass/issue-3429.rs +++ b/src/test/run-pass/issue-3429.rs @@ -13,4 +13,3 @@ pub fn main() { let y: @fn() -> int = || x; let z = y(); } - diff --git a/src/test/run-pass/issue-3461.rs b/src/test/run-pass/issue-3461.rs index 4c4144f28e891..dae35d7237b85 100644 --- a/src/test/run-pass/issue-3461.rs +++ b/src/test/run-pass/issue-3461.rs @@ -12,6 +12,6 @@ pub fn main() { fn foo() { } - + let bar: ~fn() = ~foo; } diff --git a/src/test/run-pass/issue-3556.rs b/src/test/run-pass/issue-3556.rs index 703dcd54f0ac8..ff2fa80102bfc 100644 --- a/src/test/run-pass/issue-3556.rs +++ b/src/test/run-pass/issue-3556.rs @@ -10,7 +10,7 @@ extern mod std; use core::io::WriterUtil; - + enum Token { Text(@~str), ETag(@~[~str], @~str), @@ -19,7 +19,7 @@ enum Token { IncompleteSection(@~[~str], bool, @~str, bool), Partial(@~str, @~str, @~str), } - + fn check_strs(actual: &str, expected: &str) -> bool { if actual != expected @@ -29,12 +29,12 @@ fn check_strs(actual: &str, expected: &str) -> bool } return true; } - + pub fn main() { // assert!(check_strs(fmt!("%?", Text(@~"foo")), "Text(@~\"foo\")")); // assert!(check_strs(fmt!("%?", ETag(@~[~"foo"], @~"bar")), "ETag(@~[ ~\"foo\" ], @~\"bar\")")); - + let t = Text(@~"foo"); let u = Section(@~[~"alpha"], true, @~[t], @~"foo", @~"foo", @~"foo", @~"foo", @~"foo"); let v = fmt!("%?", u); // this is the line that causes the seg fault diff --git a/src/test/run-pass/issue-3563-3.rs b/src/test/run-pass/issue-3563-3.rs index 9b7ab67c1a3e8..96925a97a1016 100644 --- a/src/test/run-pass/issue-3563-3.rs +++ b/src/test/run-pass/issue-3563-3.rs @@ -62,7 +62,7 @@ impl Drop for AsciiArt { // It's common to define a constructor sort of function to create struct instances. // If there is a canonical constructor it is typically named the same as the type. -// Other constructor sort of functions are typically named from_foo, from_bar, etc. +// Other constructor sort of functions are typically named from_foo, from_bar, etc. fn AsciiArt(width: uint, height: uint, fill: char) -> AsciiArt { // Use an anonymous function to build a vector of vectors containing @@ -72,7 +72,7 @@ fn AsciiArt(width: uint, height: uint, fill: char) -> AsciiArt { for height.times { - let mut line = ~[]; + let mut line = ~[]; vec::grow_set(&mut line, width-1, &'.', '.'); push(line); } @@ -208,4 +208,3 @@ pub fn main() { test_add_pt(); test_shapes(); } - diff --git a/src/test/run-pass/issue-3609.rs b/src/test/run-pass/issue-3609.rs index fc6ceb4130fcd..6c26ac3f65e1c 100644 --- a/src/test/run-pass/issue-3609.rs +++ b/src/test/run-pass/issue-3609.rs @@ -24,4 +24,3 @@ fn foo(name: ~str, samples_chan: Chan) { } pub fn main() {} - diff --git a/src/test/run-pass/issue-3860.rs b/src/test/run-pass/issue-3860.rs index 46aa7187c9a02..778b2b72b13d9 100644 --- a/src/test/run-pass/issue-3860.rs +++ b/src/test/run-pass/issue-3860.rs @@ -19,6 +19,6 @@ pub impl Foo { pub fn main() { let mut x = @mut Foo { x: 3 }; // Neither of the next two lines should cause an error - let _ = x.stuff(); + let _ = x.stuff(); x.stuff(); } diff --git a/src/test/run-pass/issue-3895.rs b/src/test/run-pass/issue-3895.rs index d3820c1e54712..388e09ddb3e39 100644 --- a/src/test/run-pass/issue-3895.rs +++ b/src/test/run-pass/issue-3895.rs @@ -11,7 +11,7 @@ // xfail-test pub fn main() { enum State { BadChar, BadSyntax } - + match BadChar { _ if true => BadChar, BadChar | BadSyntax => fail!() , diff --git a/src/test/run-pass/issue-3979-2.rs b/src/test/run-pass/issue-3979-2.rs index c485590f4aa17..a04e35108028c 100644 --- a/src/test/run-pass/issue-3979-2.rs +++ b/src/test/run-pass/issue-3979-2.rs @@ -24,4 +24,3 @@ trait C: B { } pub fn main() {} - diff --git a/src/test/run-pass/issue-4241.rs b/src/test/run-pass/issue-4241.rs index 18bc471afab1d..e5905e7a5be21 100644 --- a/src/test/run-pass/issue-4241.rs +++ b/src/test/run-pass/issue-4241.rs @@ -55,7 +55,7 @@ priv fn parse_list(len: uint, io: @io::Reader) -> Result { priv fn chop(s: ~str) -> ~str { s.slice(0, s.len() - 1).to_owned() } - + priv fn parse_bulk(io: @io::Reader) -> Result { match int::from_str(chop(io.read_line())) { None => fail!(), diff --git a/src/test/run-pass/issue-4875.rs b/src/test/run-pass/issue-4875.rs index 51c23e7680826..81947791881fe 100644 --- a/src/test/run-pass/issue-4875.rs +++ b/src/test/run-pass/issue-4875.rs @@ -19,4 +19,3 @@ fn foo(Foo{_}: Foo) { pub fn main() { } - diff --git a/src/test/run-pass/issue-868.rs b/src/test/run-pass/issue-868.rs index 16e8fa18c2a02..2a82f559d547c 100644 --- a/src/test/run-pass/issue-868.rs +++ b/src/test/run-pass/issue-868.rs @@ -22,4 +22,3 @@ pub fn main() { let _ = f(||{}); let _ = (||{}); } - diff --git a/src/test/run-pass/issue_3136_b.rs b/src/test/run-pass/issue_3136_b.rs index c5b6b6b220cd0..b1d28a1eb67e9 100644 --- a/src/test/run-pass/issue_3136_b.rs +++ b/src/test/run-pass/issue_3136_b.rs @@ -13,4 +13,3 @@ extern mod issue_3136_a; pub fn main() {} - diff --git a/src/test/run-pass/ivec-add.rs b/src/test/run-pass/ivec-add.rs index 1b9e818421e2e..bd58ae6565143 100644 --- a/src/test/run-pass/ivec-add.rs +++ b/src/test/run-pass/ivec-add.rs @@ -21,4 +21,3 @@ pub fn main() { assert!((d[0] == 1)); assert!((d[1] == 1)); } - diff --git a/src/test/run-pass/ivec-pass-by-value.rs b/src/test/run-pass/ivec-pass-by-value.rs index 756f38196fded..3a3b5746b9d6f 100644 --- a/src/test/run-pass/ivec-pass-by-value.rs +++ b/src/test/run-pass/ivec-pass-by-value.rs @@ -10,4 +10,3 @@ fn f(a: ~[int]) { } pub fn main() { f(~[1, 2, 3, 4, 5]); } - diff --git a/src/test/run-pass/labeled-break.rs b/src/test/run-pass/labeled-break.rs index 06ca401a136e7..32cd7f0c7f8a7 100644 --- a/src/test/run-pass/labeled-break.rs +++ b/src/test/run-pass/labeled-break.rs @@ -18,4 +18,3 @@ pub fn main() { } } } - diff --git a/src/test/run-pass/let-assignability.rs b/src/test/run-pass/let-assignability.rs index 51fa84613cae9..0afc3ee87e0f4 100644 --- a/src/test/run-pass/let-assignability.rs +++ b/src/test/run-pass/let-assignability.rs @@ -17,4 +17,3 @@ fn f() { pub fn main() { f(); } - diff --git a/src/test/run-pass/liveness-assign-imm-local-after-loop.rs b/src/test/run-pass/liveness-assign-imm-local-after-loop.rs index f352a2b527306..5d59c4c14716f 100644 --- a/src/test/run-pass/liveness-assign-imm-local-after-loop.rs +++ b/src/test/run-pass/liveness-assign-imm-local-after-loop.rs @@ -16,5 +16,5 @@ fn test(cond: bool) { } pub fn main() { - // note: don't call test()... :) + // note: don't call test()... :) } diff --git a/src/test/run-pass/log-linearized.rs b/src/test/run-pass/log-linearized.rs index 919c53e033066..0f388489000fe 100644 --- a/src/test/run-pass/log-linearized.rs +++ b/src/test/run-pass/log-linearized.rs @@ -32,4 +32,3 @@ fn f() { pub fn main() { f::(); } - diff --git a/src/test/run-pass/max-min-classes.rs b/src/test/run-pass/max-min-classes.rs index 58dcb24edf917..d986d7e676a12 100644 --- a/src/test/run-pass/max-min-classes.rs +++ b/src/test/run-pass/max-min-classes.rs @@ -37,4 +37,3 @@ pub fn main() { let foo = Foo(3, 20); io::println(fmt!("%d %d", foo.sum(), foo.product())); } - diff --git a/src/test/run-pass/module-qualified-struct-destructure.rs b/src/test/run-pass/module-qualified-struct-destructure.rs index 6fb6d21f13f1a..87c854d32be8b 100644 --- a/src/test/run-pass/module-qualified-struct-destructure.rs +++ b/src/test/run-pass/module-qualified-struct-destructure.rs @@ -19,4 +19,3 @@ pub fn main() { let x = m::S { x: 1, y: 2 }; let m::S { x: a, y: b } = x; } - diff --git a/src/test/run-pass/move-self.rs b/src/test/run-pass/move-self.rs index d84646957283a..4ed1faf65b628 100644 --- a/src/test/run-pass/move-self.rs +++ b/src/test/run-pass/move-self.rs @@ -16,4 +16,3 @@ pub fn main() { let x = S { x: ~"Hello!" }; x.foo(); } - diff --git a/src/test/run-pass/moves-based-on-type-capture-clause.rs b/src/test/run-pass/moves-based-on-type-capture-clause.rs index 2f427ca48aab2..26d4773d961aa 100644 --- a/src/test/run-pass/moves-based-on-type-capture-clause.rs +++ b/src/test/run-pass/moves-based-on-type-capture-clause.rs @@ -4,4 +4,3 @@ pub fn main() { io::println(x); } } - diff --git a/src/test/run-pass/multiple-trait-bounds.rs b/src/test/run-pass/multiple-trait-bounds.rs index 3c6559b9c0dfd..cdfa93d309459 100644 --- a/src/test/run-pass/multiple-trait-bounds.rs +++ b/src/test/run-pass/multiple-trait-bounds.rs @@ -4,4 +4,3 @@ fn f(_: T) { pub fn main() { f(3); } - diff --git a/src/test/run-pass/mut-vstore-expr.rs b/src/test/run-pass/mut-vstore-expr.rs index 0ababc43c3f30..fa6dde5b3ef88 100644 --- a/src/test/run-pass/mut-vstore-expr.rs +++ b/src/test/run-pass/mut-vstore-expr.rs @@ -11,4 +11,3 @@ pub fn main() { let x: &mut [int] = &mut [ 1, 2, 3 ]; } - diff --git a/src/test/run-pass/nested-class.rs b/src/test/run-pass/nested-class.rs index 44348223b605d..83820f87d5030 100644 --- a/src/test/run-pass/nested-class.rs +++ b/src/test/run-pass/nested-class.rs @@ -9,14 +9,13 @@ // except according to those terms. pub fn main() { - - struct b { - i: int, - } + struct b { + i: int, + } - pub impl b { - fn do_stuff(&self) -> int { return 37; } - } + pub impl b { + fn do_stuff(&self) -> int { return 37; } + } fn b(i:int) -> b { b { @@ -24,10 +23,9 @@ pub fn main() { } } - // fn b(x:int) -> int { fail!(); } + // fn b(x:int) -> int { fail!(); } - let z = b(42); - assert!((z.i == 42)); - assert!((z.do_stuff() == 37)); - + let z = b(42); + assert!((z.i == 42)); + assert!((z.do_stuff() == 37)); } diff --git a/src/test/run-pass/new-impl-syntax.rs b/src/test/run-pass/new-impl-syntax.rs index 12b41fc91485e..2603353f0cff8 100644 --- a/src/test/run-pass/new-impl-syntax.rs +++ b/src/test/run-pass/new-impl-syntax.rs @@ -23,4 +23,3 @@ pub fn main() { io::println(Thingy { x: 1, y: 2 }.to_str()); io::println(PolymorphicThingy { x: Thingy { x: 1, y: 2 } }.to_str()); } - diff --git a/src/test/run-pass/new-import-syntax.rs b/src/test/run-pass/new-import-syntax.rs index 267f365c7134c..1390ae5f7ebe0 100644 --- a/src/test/run-pass/new-import-syntax.rs +++ b/src/test/run-pass/new-import-syntax.rs @@ -13,4 +13,3 @@ use core::io::println; pub fn main() { println("Hello world!"); } - diff --git a/src/test/run-pass/new-style-constants.rs b/src/test/run-pass/new-style-constants.rs index 9a319ea6a5c50..6fe4a88d07183 100644 --- a/src/test/run-pass/new-style-constants.rs +++ b/src/test/run-pass/new-style-constants.rs @@ -15,4 +15,3 @@ static FOO: int = 3; pub fn main() { println(fmt!("%d", FOO)); } - diff --git a/src/test/run-pass/new-style-fixed-length-vec.rs b/src/test/run-pass/new-style-fixed-length-vec.rs index 5d37a42af4242..6eea23f6b2b06 100644 --- a/src/test/run-pass/new-style-fixed-length-vec.rs +++ b/src/test/run-pass/new-style-fixed-length-vec.rs @@ -15,6 +15,3 @@ static FOO: [int, ..3] = [1, 2, 3]; pub fn main() { println(fmt!("%d %d %d", FOO[0], FOO[1], FOO[2])); } - - - diff --git a/src/test/run-pass/new-vstore-mut-box-syntax.rs b/src/test/run-pass/new-vstore-mut-box-syntax.rs index 971e870d1f8c0..63569c7198260 100644 --- a/src/test/run-pass/new-vstore-mut-box-syntax.rs +++ b/src/test/run-pass/new-vstore-mut-box-syntax.rs @@ -12,4 +12,3 @@ pub fn main() { let x: @mut [int] = @mut [ 1, 2, 3 ]; } - diff --git a/src/test/run-pass/newtype-struct-with-dtor.rs b/src/test/run-pass/newtype-struct-with-dtor.rs index b33bfa0388a59..eb3b74553b7ba 100644 --- a/src/test/run-pass/newtype-struct-with-dtor.rs +++ b/src/test/run-pass/newtype-struct-with-dtor.rs @@ -13,5 +13,3 @@ impl Drop for Fd { pub fn main() { } - - diff --git a/src/test/run-pass/newtype-struct-xc-2.rs b/src/test/run-pass/newtype-struct-xc-2.rs index 1fca01f737327..cedf1d42c3dcd 100644 --- a/src/test/run-pass/newtype-struct-xc-2.rs +++ b/src/test/run-pass/newtype-struct-xc-2.rs @@ -11,4 +11,3 @@ fn f() -> Au { pub fn main() { let _ = f(); } - diff --git a/src/test/run-pass/newtype-struct-xc.rs b/src/test/run-pass/newtype-struct-xc.rs index 49ce618e37b4c..2280b335f3f93 100644 --- a/src/test/run-pass/newtype-struct-xc.rs +++ b/src/test/run-pass/newtype-struct-xc.rs @@ -6,4 +6,3 @@ extern mod newtype_struct_xc; pub fn main() { let _ = newtype_struct_xc::Au(2); } - diff --git a/src/test/run-pass/nullable-pointer-iotareduction.rs b/src/test/run-pass/nullable-pointer-iotareduction.rs index 0c4d297403cfb..206381bcef72d 100644 --- a/src/test/run-pass/nullable-pointer-iotareduction.rs +++ b/src/test/run-pass/nullable-pointer-iotareduction.rs @@ -20,7 +20,7 @@ use core::{option, cast}; enum E { Thing(int, T), Nothing((), ((), ()), [i8, ..0]) } impl E { - fn is_none(&self) -> bool { + fn is_none(&self) -> bool { match *self { Thing(*) => false, Nothing(*) => true diff --git a/src/test/run-pass/one-tuple.rs b/src/test/run-pass/one-tuple.rs index 2efa0b98b6a27..eb32e7cda1ad8 100644 --- a/src/test/run-pass/one-tuple.rs +++ b/src/test/run-pass/one-tuple.rs @@ -21,4 +21,3 @@ pub fn main() { let (y,) = x; assert!(y == 'd'); } - diff --git a/src/test/run-pass/pattern-in-closure.rs b/src/test/run-pass/pattern-in-closure.rs index 7194fca519b7a..08c749235c2c8 100644 --- a/src/test/run-pass/pattern-in-closure.rs +++ b/src/test/run-pass/pattern-in-closure.rs @@ -19,4 +19,3 @@ pub fn main() { f((2, 3)); g(Foo { x: 1, y: 2 }); } - diff --git a/src/test/run-pass/pipe-detect-term.rs b/src/test/run-pass/pipe-detect-term.rs index bd0ffa6459067..55e43075204cc 100644 --- a/src/test/run-pass/pipe-detect-term.rs +++ b/src/test/run-pass/pipe-detect-term.rs @@ -29,7 +29,7 @@ proto! oneshot ( pub fn main() { let iotask = &uv::global_loop::get(); - + let (chan, port) = oneshot::init(); let port = Cell(port); do spawn { @@ -48,7 +48,7 @@ pub fn main() { fn failtest() { let (c, p) = oneshot::init(); - do task::spawn_with(c) |_c| { + do task::spawn_with(c) |_c| { fail!(); } diff --git a/src/test/run-pass/pipe-pingpong-bounded.rs b/src/test/run-pass/pipe-pingpong-bounded.rs index 6d82663d19560..69d87804b42dd 100644 --- a/src/test/run-pass/pipe-pingpong-bounded.rs +++ b/src/test/run-pass/pipe-pingpong-bounded.rs @@ -99,7 +99,7 @@ mod test { let pong(_chan) = recv(chan); error!("Received pong"); } - + pub fn server(+chan: ::pingpong::server::ping) { use pingpong::server; diff --git a/src/test/run-pass/pipe-pingpong-proto.rs b/src/test/run-pass/pipe-pingpong-proto.rs index 65a5672941f28..d1198f3611d15 100644 --- a/src/test/run-pass/pipe-pingpong-proto.rs +++ b/src/test/run-pass/pipe-pingpong-proto.rs @@ -37,7 +37,7 @@ mod test { let pong(_chan) = recv(chan); error!(~"Received pong"); } - + pub fn server(+chan: ::pingpong::server::ping) { use pingpong::server; diff --git a/src/test/run-pass/pipe-select.rs b/src/test/run-pass/pipe-select.rs index 12d60c9d6ab01..8782f6f6ebd15 100644 --- a/src/test/run-pass/pipe-select.rs +++ b/src/test/run-pass/pipe-select.rs @@ -55,8 +55,8 @@ pub fn main() { use stream::client::*; let iotask = &uv::global_loop::get(); - - let c = spawn_service(stream::init, |p| { + + let c = spawn_service(stream::init, |p| { error!("waiting for pipes"); let stream::send(x, p) = recv(p); error!("got pipes"); @@ -86,7 +86,7 @@ pub fn main() { let (_c2, p2) = oneshot::init(); let c = send(c, (p1, p2)); - + sleep(iotask, 100); signal(c1); diff --git a/src/test/run-pass/pipe-sleep.rs b/src/test/run-pass/pipe-sleep.rs index 86ffc96e89aec..da49a4303a6d7 100644 --- a/src/test/run-pass/pipe-sleep.rs +++ b/src/test/run-pass/pipe-sleep.rs @@ -55,6 +55,6 @@ pub fn main() { let iotask = &uv::global_loop::get(); sleep(iotask, 500); - + signal(c); } diff --git a/src/test/run-pass/pub-use-xcrate.rs b/src/test/run-pass/pub-use-xcrate.rs index 03004e5e47522..74ae81e63e239 100644 --- a/src/test/run-pass/pub-use-xcrate.rs +++ b/src/test/run-pass/pub-use-xcrate.rs @@ -21,4 +21,3 @@ pub fn main() { name: 0 }; } - diff --git a/src/test/run-pass/pub_use_mods_xcrate_exe.rs b/src/test/run-pass/pub_use_mods_xcrate_exe.rs index 1d60cab3a82ef..953a99e1fd5be 100644 --- a/src/test/run-pass/pub_use_mods_xcrate_exe.rs +++ b/src/test/run-pass/pub_use_mods_xcrate_exe.rs @@ -15,4 +15,3 @@ extern mod pub_use_mods_xcrate; use pub_use_mods_xcrate::a::c; pub fn main(){} - diff --git a/src/test/run-pass/reexport-star.rs b/src/test/run-pass/reexport-star.rs index 3b9fe688d4d1e..3cc250b170744 100644 --- a/src/test/run-pass/reexport-star.rs +++ b/src/test/run-pass/reexport-star.rs @@ -25,4 +25,3 @@ pub fn main() { b::f(); b::g(); } - diff --git a/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs b/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs index 1fb9c126e74e2..7efe62236f35e 100644 --- a/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs +++ b/src/test/run-pass/regions-addr-of-interior-of-unique-box.rs @@ -26,4 +26,3 @@ fn get_x<'r>(x: &'r Character) -> &'r int { pub fn main() { } - diff --git a/src/test/run-pass/regions-addr-of-ret.rs b/src/test/run-pass/regions-addr-of-ret.rs index a9c65d012954c..9e19618f332e0 100644 --- a/src/test/run-pass/regions-addr-of-ret.rs +++ b/src/test/run-pass/regions-addr-of-ret.rs @@ -16,4 +16,3 @@ pub fn main() { let three = &3; error!(fmt!("%d", *f(three))); } - diff --git a/src/test/run-pass/regions-fn-subtyping-2.rs b/src/test/run-pass/regions-fn-subtyping-2.rs index a660b9c9ee2d5..ef8d9970c2b47 100644 --- a/src/test/run-pass/regions-fn-subtyping-2.rs +++ b/src/test/run-pass/regions-fn-subtyping-2.rs @@ -19,10 +19,8 @@ fn has_same_region(f: &fn<'a>(x: &'a int, g: &fn(y: &'a int))) { wants_same_region(f); } -fn wants_same_region(_f: &fn<'b>(x: &'b int, g: &fn(y: &'b int))) { +fn wants_same_region(_f: &fn<'b>(x: &'b int, g: &fn(y: &'b int))) { } pub fn main() { } - - diff --git a/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs b/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs index ee2682ff4ab93..39da08de6df2c 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-addr-of.rs @@ -13,15 +13,15 @@ pub fn main() { for uint::range(0, 3) |i| { // ensure that the borrow in this alt - // does not inferfere with the swap - // below. note that it would it you - // naively borrowed &x for the lifetime - // of the variable x, as we once did + // does not inferfere with the swap + // below. note that it would it you + // naively borrowed &x for the lifetime + // of the variable x, as we once did match i { - i => { - let y = &x; - assert!(i < *y); - } + i => { + let y = &x; + assert!(i < *y); + } } let mut y = 4; y <-> x; diff --git a/src/test/run-pass/regions-infer-borrow-scope-view.rs b/src/test/run-pass/regions-infer-borrow-scope-view.rs index 9358ea8a77724..8f7452f2d06ed 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-view.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-view.rs @@ -16,4 +16,3 @@ pub fn main() { let y = view(x); assert!((v[0] == x[0]) && (v[0] == y[0])); } - diff --git a/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs b/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs index 08c54c790b1f0..73535f52043eb 100644 --- a/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs +++ b/src/test/run-pass/regions-infer-borrow-scope-within-loop-ok.rs @@ -15,6 +15,6 @@ pub fn main() { loop { let y = borrow(x); assert!(*x == *y); - break; + break; } } diff --git a/src/test/run-pass/regions-infer-borrow-scope.rs b/src/test/run-pass/regions-infer-borrow-scope.rs index e06a2fea1c194..61b9000aea318 100644 --- a/src/test/run-pass/regions-infer-borrow-scope.rs +++ b/src/test/run-pass/regions-infer-borrow-scope.rs @@ -19,4 +19,3 @@ pub fn main() { let xc = x_coord(p); assert!(*xc == 3); } - diff --git a/src/test/run-pass/regions-mock-trans-impls.rs b/src/test/run-pass/regions-mock-trans-impls.rs index e916350574883..d54aae7bb6337 100644 --- a/src/test/run-pass/regions-mock-trans-impls.rs +++ b/src/test/run-pass/regions-mock-trans-impls.rs @@ -52,4 +52,3 @@ pub fn main() { let mut ccx = Ccx { x: 0 }; f(&mut ccx); } - diff --git a/src/test/run-pass/regions-mock-trans.rs b/src/test/run-pass/regions-mock-trans.rs index c46e41ab0eb1c..0ea6f852a897c 100644 --- a/src/test/run-pass/regions-mock-trans.rs +++ b/src/test/run-pass/regions-mock-trans.rs @@ -52,4 +52,3 @@ pub fn main() { let ccx = Ccx { x: 0 }; f(&ccx); } - diff --git a/src/test/run-pass/regions-self-impls.rs b/src/test/run-pass/regions-self-impls.rs index 2f4eefe5243ad..c43fd0db5666c 100644 --- a/src/test/run-pass/regions-self-impls.rs +++ b/src/test/run-pass/regions-self-impls.rs @@ -25,4 +25,3 @@ pub fn main() { debug!(*clam.get_chowder()); clam.get_chowder(); } - diff --git a/src/test/run-pass/regions-self-in-enums.rs b/src/test/run-pass/regions-self-in-enums.rs index 78045e5e5d410..5f8b9ee333289 100644 --- a/src/test/run-pass/regions-self-in-enums.rs +++ b/src/test/run-pass/regions-self-in-enums.rs @@ -21,4 +21,3 @@ pub fn main() { } debug!(*z); } - diff --git a/src/test/run-pass/regions-simple.rs b/src/test/run-pass/regions-simple.rs index f7a50e6b114a3..436fede4dc11e 100644 --- a/src/test/run-pass/regions-simple.rs +++ b/src/test/run-pass/regions-simple.rs @@ -14,5 +14,3 @@ pub fn main() { *y = 5; debug!(*y); } - - diff --git a/src/test/run-pass/repeated-vector-syntax.rs b/src/test/run-pass/repeated-vector-syntax.rs index a22384a6b53d0..f3d6c1640d881 100644 --- a/src/test/run-pass/repeated-vector-syntax.rs +++ b/src/test/run-pass/repeated-vector-syntax.rs @@ -21,4 +21,3 @@ pub fn main() { error!("%?", x); error!("%?", y); } - diff --git a/src/test/run-pass/resource-cycle.rs b/src/test/run-pass/resource-cycle.rs index fdb8c2a496c6b..f498553834a1e 100644 --- a/src/test/run-pass/resource-cycle.rs +++ b/src/test/run-pass/resource-cycle.rs @@ -57,7 +57,7 @@ pub fn main() { debug!("r = %x", cast::transmute::<*r, uint>(&rs)); rs } }); - + debug!("x1 = %x, x1.r = %x", cast::transmute::<@mut t, uint>(x1), cast::transmute::<*r, uint>(&x1.r)); @@ -70,7 +70,7 @@ pub fn main() { rs } }); - + debug!("x2 = %x, x2.r = %x", cast::transmute::<@mut t, uint>(x2), cast::transmute::<*r, uint>(&(x2.r))); diff --git a/src/test/run-pass/resource-cycle3.rs b/src/test/run-pass/resource-cycle3.rs index 0d699a6e49b6c..ef71372477862 100644 --- a/src/test/run-pass/resource-cycle3.rs +++ b/src/test/run-pass/resource-cycle3.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// same as resource-cycle2, but be sure to give r multiple fields... +// same as resource-cycle2, but be sure to give r multiple fields... // Don't leak the unique pointers @@ -50,7 +50,7 @@ struct Node { r: R } -pub fn main() { +pub fn main() { unsafe { let i1 = ~0xA; let i1p = cast::transmute_copy(&i1); diff --git a/src/test/run-pass/self-type-param.rs b/src/test/run-pass/self-type-param.rs index 0af197968040f..d90ec51bedfa2 100644 --- a/src/test/run-pass/self-type-param.rs +++ b/src/test/run-pass/self-type-param.rs @@ -13,4 +13,3 @@ impl MyTrait for S { } pub fn main() {} - diff --git a/src/test/run-pass/static-methods-in-traits.rs b/src/test/run-pass/static-methods-in-traits.rs index d171434aa482d..42d0f02d6425c 100644 --- a/src/test/run-pass/static-methods-in-traits.rs +++ b/src/test/run-pass/static-methods-in-traits.rs @@ -9,27 +9,26 @@ // except according to those terms. mod a { - pub trait Foo { - pub fn foo() -> Self; - } + pub trait Foo { + pub fn foo() -> Self; + } - impl Foo for int { - pub fn foo() -> int { - 3 - } - } - - impl Foo for uint { - pub fn foo() -> uint { - 5u - } - } + impl Foo for int { + pub fn foo() -> int { + 3 + } + } + + impl Foo for uint { + pub fn foo() -> uint { + 5u + } + } } pub fn main() { - let x: int = a::Foo::foo(); - let y: uint = a::Foo::foo(); - assert!(x == 3); - assert!(y == 5); + let x: int = a::Foo::foo(); + let y: uint = a::Foo::foo(); + assert!(x == 3); + assert!(y == 5); } - diff --git a/src/test/run-pass/struct-deref.rs b/src/test/run-pass/struct-deref.rs index f71bc06a1cf8d..a52a2851689bb 100644 --- a/src/test/run-pass/struct-deref.rs +++ b/src/test/run-pass/struct-deref.rs @@ -14,4 +14,3 @@ pub fn main() { let x: Foo = Foo(2); assert!(*x == 2); } - diff --git a/src/test/run-pass/struct-field-assignability.rs b/src/test/run-pass/struct-field-assignability.rs index 1e13c7b86bf8c..0aca1a3d05fdf 100644 --- a/src/test/run-pass/struct-field-assignability.rs +++ b/src/test/run-pass/struct-field-assignability.rs @@ -6,4 +6,3 @@ pub fn main() { let f = Foo { x: @3 }; assert!(*f.x == 3); } - diff --git a/src/test/run-pass/struct-like-variant-construct.rs b/src/test/run-pass/struct-like-variant-construct.rs index 0d14d90c1f1aa..bc2dce680c956 100644 --- a/src/test/run-pass/struct-like-variant-construct.rs +++ b/src/test/run-pass/struct-like-variant-construct.rs @@ -22,4 +22,3 @@ enum Foo { pub fn main() { let x = Bar { a: 2, b: 3 }; } - diff --git a/src/test/run-pass/struct-like-variant-match.rs b/src/test/run-pass/struct-like-variant-match.rs index 3158d2836ddde..64a75ddab22b7 100644 --- a/src/test/run-pass/struct-like-variant-match.rs +++ b/src/test/run-pass/struct-like-variant-match.rs @@ -38,4 +38,3 @@ pub fn main() { let y = Baz { x: 1.0, y: 2.0 }; f(&y); } - diff --git a/src/test/run-pass/struct-pattern-matching.rs b/src/test/run-pass/struct-pattern-matching.rs index 1d7bcb2585fbd..1bda2d2412d2a 100644 --- a/src/test/run-pass/struct-pattern-matching.rs +++ b/src/test/run-pass/struct-pattern-matching.rs @@ -19,6 +19,3 @@ pub fn main() { Foo { x: x, y: y } => io::println(fmt!("yes, %d, %d", x, y)) } } - - - diff --git a/src/test/run-pass/super.rs b/src/test/run-pass/super.rs index 2fe0696b2f261..b5eb6e850456e 100644 --- a/src/test/run-pass/super.rs +++ b/src/test/run-pass/super.rs @@ -9,4 +9,3 @@ pub mod a { pub fn main() { } - diff --git a/src/test/run-pass/tag-disr-val-shape.rs b/src/test/run-pass/tag-disr-val-shape.rs index 50ab17fdeeae9..dd78dff0d6ea7 100644 --- a/src/test/run-pass/tag-disr-val-shape.rs +++ b/src/test/run-pass/tag-disr-val-shape.rs @@ -23,4 +23,3 @@ pub fn main() { assert!(~"green" == fmt!("%?", green)); assert!(~"white" == fmt!("%?", white)); } - diff --git a/src/test/run-pass/tag-variant-disr-val.rs b/src/test/run-pass/tag-variant-disr-val.rs index 0806f1ea92aec..d4eadd366de06 100644 --- a/src/test/run-pass/tag-variant-disr-val.rs +++ b/src/test/run-pass/tag-variant-disr-val.rs @@ -69,5 +69,3 @@ fn get_color_if(color: color) -> ~str { else if color == orange {~"orange"} else {~"unknown"} } - - diff --git a/src/test/run-pass/threads.rs b/src/test/run-pass/threads.rs index f736ded3db2a5..288a23b855b60 100644 --- a/src/test/run-pass/threads.rs +++ b/src/test/run-pass/threads.rs @@ -19,4 +19,3 @@ pub fn main() { } fn child(&&x: int) { debug!(x); } - diff --git a/src/test/run-pass/trait-composition-trivial.rs b/src/test/run-pass/trait-composition-trivial.rs index 328c0b6888cc9..de130bf1b41fe 100644 --- a/src/test/run-pass/trait-composition-trivial.rs +++ b/src/test/run-pass/trait-composition-trivial.rs @@ -17,5 +17,3 @@ trait Bar : Foo { } pub fn main() {} - - diff --git a/src/test/run-pass/trait-inheritance-auto-xc-2.rs b/src/test/run-pass/trait-inheritance-auto-xc-2.rs index 446dd4b3d8ee1..996f55d4019a8 100644 --- a/src/test/run-pass/trait-inheritance-auto-xc-2.rs +++ b/src/test/run-pass/trait-inheritance-auto-xc-2.rs @@ -30,4 +30,3 @@ pub fn main() { let a = &A { x: 3 }; f(a); } - diff --git a/src/test/run-pass/trait-inheritance-auto-xc.rs b/src/test/run-pass/trait-inheritance-auto-xc.rs index 03287809a9be1..3af8d606bf4ae 100644 --- a/src/test/run-pass/trait-inheritance-auto-xc.rs +++ b/src/test/run-pass/trait-inheritance-auto-xc.rs @@ -31,4 +31,3 @@ pub fn main() { let a = &A { x: 3 }; f(a); } - diff --git a/src/test/run-pass/trait-inheritance-auto.rs b/src/test/run-pass/trait-inheritance-auto.rs index b74064591d3bc..fb97dd5e7741a 100644 --- a/src/test/run-pass/trait-inheritance-auto.rs +++ b/src/test/run-pass/trait-inheritance-auto.rs @@ -34,4 +34,3 @@ pub fn main() { let a = &A { x: 3 }; f(a); } - diff --git a/src/test/run-pass/trait-inheritance-call-bound-inherited.rs b/src/test/run-pass/trait-inheritance-call-bound-inherited.rs index 26b96f933269b..805c9655d81d4 100644 --- a/src/test/run-pass/trait-inheritance-call-bound-inherited.rs +++ b/src/test/run-pass/trait-inheritance-call-bound-inherited.rs @@ -25,4 +25,3 @@ pub fn main() { let a = &A { x: 3 }; assert!(gg(a) == 10); } - diff --git a/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs b/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs index 5e612bbca6487..0b35fd90bbd19 100644 --- a/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs +++ b/src/test/run-pass/trait-inheritance-call-bound-inherited2.rs @@ -28,4 +28,3 @@ pub fn main() { let a = &A { x: 3 }; assert!(gg(a) == 10); } - diff --git a/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs b/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs index 6efd854e01b42..df9cc4fb8b6d4 100644 --- a/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs +++ b/src/test/run-pass/trait-inheritance-cast-without-call-to-supertrait.rs @@ -38,4 +38,3 @@ pub fn main() { assert!(afoo.f() == 10); assert!(abar.g() == 20); } - diff --git a/src/test/run-pass/trait-inheritance-cast.rs b/src/test/run-pass/trait-inheritance-cast.rs index 023827977976e..75c121e10b014 100644 --- a/src/test/run-pass/trait-inheritance-cast.rs +++ b/src/test/run-pass/trait-inheritance-cast.rs @@ -40,4 +40,3 @@ pub fn main() { assert!(abar.g() == 20); assert!(abar.f() == 10); } - diff --git a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs index 3c1bf2035aa71..976c9a0243927 100644 --- a/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs +++ b/src/test/run-pass/trait-inheritance-cross-trait-call-xc.rs @@ -27,4 +27,3 @@ pub fn main() { let a = &aux::A { x: 3 }; assert!(a.g() == 10); } - diff --git a/src/test/run-pass/trait-inheritance-cross-trait-call.rs b/src/test/run-pass/trait-inheritance-cross-trait-call.rs index 997f13d0e5e35..20dac16b4927d 100644 --- a/src/test/run-pass/trait-inheritance-cross-trait-call.rs +++ b/src/test/run-pass/trait-inheritance-cross-trait-call.rs @@ -24,4 +24,3 @@ pub fn main() { let a = &A { x: 3 }; assert!(a.g() == 10); } - diff --git a/src/test/run-pass/trait-inheritance-overloading-simple.rs b/src/test/run-pass/trait-inheritance-overloading-simple.rs index 711571e8c64f5..3a1c3716df442 100644 --- a/src/test/run-pass/trait-inheritance-overloading-simple.rs +++ b/src/test/run-pass/trait-inheritance-overloading-simple.rs @@ -32,4 +32,3 @@ pub fn main() { assert!(x != y); assert!(x == z); } - diff --git a/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs b/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs index 9f745db76386c..d89852e2b05f9 100644 --- a/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs +++ b/src/test/run-pass/trait-inheritance-overloading-xc-exe.rs @@ -27,4 +27,3 @@ pub fn main() { assert!(b == mi(-2)); assert!(c == mi(15)); } - diff --git a/src/test/run-pass/trait-inheritance-overloading.rs b/src/test/run-pass/trait-inheritance-overloading.rs index 5b68aff269e3c..e58ec24f1b7d4 100644 --- a/src/test/run-pass/trait-inheritance-overloading.rs +++ b/src/test/run-pass/trait-inheritance-overloading.rs @@ -46,4 +46,3 @@ pub fn main() { assert!(b == mi(-2)); assert!(c == mi(15)); } - diff --git a/src/test/run-pass/trait-inheritance-self.rs b/src/test/run-pass/trait-inheritance-self.rs index 02ed518ff6591..5eb87b7a96b8b 100644 --- a/src/test/run-pass/trait-inheritance-self.rs +++ b/src/test/run-pass/trait-inheritance-self.rs @@ -26,4 +26,3 @@ pub fn main() { let s = S { x: 1 }; s.g(); } - diff --git a/src/test/run-pass/trait-inheritance-simple.rs b/src/test/run-pass/trait-inheritance-simple.rs index 779dfb65944c9..2da1f02779e0a 100644 --- a/src/test/run-pass/trait-inheritance-simple.rs +++ b/src/test/run-pass/trait-inheritance-simple.rs @@ -29,4 +29,3 @@ pub fn main() { assert!(ff(a) == 10); assert!(gg(a) == 20); } - diff --git a/src/test/run-pass/trait-inheritance-subst.rs b/src/test/run-pass/trait-inheritance-subst.rs index 22efdabec83ab..479f293a396e3 100644 --- a/src/test/run-pass/trait-inheritance-subst.rs +++ b/src/test/run-pass/trait-inheritance-subst.rs @@ -33,4 +33,3 @@ pub fn main() { let z = f(x, y); assert!(z.val == 8) } - diff --git a/src/test/run-pass/trait-inheritance-subst2.rs b/src/test/run-pass/trait-inheritance-subst2.rs index 4f3b808f8ebc0..5d1741a45f327 100644 --- a/src/test/run-pass/trait-inheritance-subst2.rs +++ b/src/test/run-pass/trait-inheritance-subst2.rs @@ -43,4 +43,3 @@ pub fn main() { let z = f(x, y); assert!(z.val == 13); } - diff --git a/src/test/run-pass/trait-inheritance2.rs b/src/test/run-pass/trait-inheritance2.rs index 5d6913d4146b9..adb7ab018d6c4 100644 --- a/src/test/run-pass/trait-inheritance2.rs +++ b/src/test/run-pass/trait-inheritance2.rs @@ -31,4 +31,3 @@ pub fn main() { let a = &A { x: 3 }; f(a); } - diff --git a/src/test/run-pass/trait-region-pointer-simple.rs b/src/test/run-pass/trait-region-pointer-simple.rs index 285b0e65daf67..a2742828a1bc0 100644 --- a/src/test/run-pass/trait-region-pointer-simple.rs +++ b/src/test/run-pass/trait-region-pointer-simple.rs @@ -28,4 +28,3 @@ pub fn main() { let b = (&a) as &Foo; assert!(b.f() == 3); } - diff --git a/src/test/run-pass/trait-static-method-overwriting.rs b/src/test/run-pass/trait-static-method-overwriting.rs index a8a579422a372..86ebc5356ebdc 100644 --- a/src/test/run-pass/trait-static-method-overwriting.rs +++ b/src/test/run-pass/trait-static-method-overwriting.rs @@ -21,7 +21,7 @@ mod base { impl ::base::HasNew for Foo { fn new() -> Foo { - unsafe { io::println("Foo"); } + unsafe { io::println("Foo"); } Foo { dummy: () } } } @@ -32,7 +32,7 @@ mod base { impl ::base::HasNew for Bar { fn new() -> Bar { - unsafe { io::println("Bar"); } + unsafe { io::println("Bar"); } Bar { dummy: () } } } @@ -40,5 +40,5 @@ mod base { pub fn main() { let f: base::Foo = base::HasNew::new::(); - let b: base::Bar = base::HasNew::new::(); + let b: base::Bar = base::HasNew::new::(); } diff --git a/src/test/run-pass/traits.rs b/src/test/run-pass/traits.rs index c4ec15ff2730a..ba3e8e082b345 100644 --- a/src/test/run-pass/traits.rs +++ b/src/test/run-pass/traits.rs @@ -53,4 +53,3 @@ impl Ord for int { self == (*a) } } - diff --git a/src/test/run-pass/tuple-struct-construct.rs b/src/test/run-pass/tuple-struct-construct.rs index ea410093c4bd2..c5ea3e14d3924 100644 --- a/src/test/run-pass/tuple-struct-construct.rs +++ b/src/test/run-pass/tuple-struct-construct.rs @@ -14,4 +14,3 @@ pub fn main() { let x = Foo(1, 2); io::println(fmt!("%?", x)); } - diff --git a/src/test/run-pass/tuple-struct-destructuring.rs b/src/test/run-pass/tuple-struct-destructuring.rs index 7e6b9570defae..1cb944da0403e 100644 --- a/src/test/run-pass/tuple-struct-destructuring.rs +++ b/src/test/run-pass/tuple-struct-destructuring.rs @@ -17,4 +17,3 @@ pub fn main() { assert!(y == 1); assert!(z == 2); } - diff --git a/src/test/run-pass/tuple-struct-matching.rs b/src/test/run-pass/tuple-struct-matching.rs index 405616f9b1fef..e3cbd1201c127 100644 --- a/src/test/run-pass/tuple-struct-matching.rs +++ b/src/test/run-pass/tuple-struct-matching.rs @@ -20,4 +20,3 @@ pub fn main() { } } } - diff --git a/src/test/run-pass/tuple-struct-trivial.rs b/src/test/run-pass/tuple-struct-trivial.rs index 8ddc04a186f2c..c6c32cf49c682 100644 --- a/src/test/run-pass/tuple-struct-trivial.rs +++ b/src/test/run-pass/tuple-struct-trivial.rs @@ -14,4 +14,3 @@ struct Foo(int, int, int); pub fn main() { } - diff --git a/src/test/run-pass/typeclasses-eq-example-static.rs b/src/test/run-pass/typeclasses-eq-example-static.rs index 9c5f8c3218a93..c14dd0471f91e 100644 --- a/src/test/run-pass/typeclasses-eq-example-static.rs +++ b/src/test/run-pass/typeclasses-eq-example-static.rs @@ -38,7 +38,7 @@ impl Equal for ColorTree { fn isEq(a: ColorTree, b: ColorTree) -> bool { match (a, b) { (leaf(x), leaf(y)) => { Equal::isEq(x, y) } - (branch(l1, r1), branch(l2, r2)) => { + (branch(l1, r1), branch(l2, r2)) => { Equal::isEq(*l1, *l2) && Equal::isEq(*r1, *r2) } _ => { false } diff --git a/src/test/run-pass/typeclasses-eq-example.rs b/src/test/run-pass/typeclasses-eq-example.rs index 51c19cef50afd..18a68bc1c34f9 100644 --- a/src/test/run-pass/typeclasses-eq-example.rs +++ b/src/test/run-pass/typeclasses-eq-example.rs @@ -37,7 +37,7 @@ impl Equal for ColorTree { fn isEq(&self, a: ColorTree) -> bool { match (*self, a) { (leaf(x), leaf(y)) => { x.isEq(y) } - (branch(l1, r1), branch(l2, r2)) => { + (branch(l1, r1), branch(l2, r2)) => { (*l1).isEq(*l2) && (*r1).isEq(*r2) } _ => { false } diff --git a/src/test/run-pass/unique-object.rs b/src/test/run-pass/unique-object.rs index 1cf4cf09b81cd..5e0954969ef8d 100644 --- a/src/test/run-pass/unique-object.rs +++ b/src/test/run-pass/unique-object.rs @@ -27,4 +27,3 @@ pub fn main() { let y = x as ~Foo; assert!(y.f() == 10); } - diff --git a/src/test/run-pass/unit-like-struct.rs b/src/test/run-pass/unit-like-struct.rs index 837bfa50b8e05..1b81015b02910 100644 --- a/src/test/run-pass/unit-like-struct.rs +++ b/src/test/run-pass/unit-like-struct.rs @@ -16,4 +16,3 @@ pub fn main() { Foo => { io::println("hi"); } } } - diff --git a/src/test/run-pass/unsafe-pointer-assignability.rs b/src/test/run-pass/unsafe-pointer-assignability.rs index 05c9cd8a57400..f19558fbb1d01 100644 --- a/src/test/run-pass/unsafe-pointer-assignability.rs +++ b/src/test/run-pass/unsafe-pointer-assignability.rs @@ -17,6 +17,3 @@ fn f(x: *int) { pub fn main() { f(&3); } - - - diff --git a/src/test/run-pass/vec-fixed-length.rs b/src/test/run-pass/vec-fixed-length.rs index 5ce1b04dbe9a0..2c4add63e8b87 100644 --- a/src/test/run-pass/vec-fixed-length.rs +++ b/src/test/run-pass/vec-fixed-length.rs @@ -12,4 +12,3 @@ pub fn main() { let x: [int, ..4] = [1, 2, 3, 4]; io::println(fmt!("%d", x[0])); } - From 9f76ca6508d82036e6ff1723dcd395998a4baa81 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Fri, 3 May 2013 17:24:44 -0700 Subject: [PATCH 186/215] rustpkg: Make code actually compile oops. --- src/librustc/metadata/filesearch.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index ded0b314d44bb..7547f7f763af0 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -39,9 +39,8 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, fn sysroot(&self) -> @Path { self.sysroot } fn for_each_lib_search_path(&self, f: &fn(&Path) -> bool) { debug!("filesearch: searching additional lib search paths"); - if !self.addl_lib_search_paths.each(f) { - return; - } + // a little weird + self.addl_lib_search_paths.each(f); debug!("filesearch: searching target lib path"); if !f(&make_target_lib_path(self.sysroot, @@ -59,7 +58,7 @@ pub fn mk_filesearch(maybe_sysroot: &Option<@Path>, match get_rustpkg_lib_path() { result::Ok(ref p) => f(p), result::Err(_) => true - } + }; } fn get_target_lib_path(&self) -> Path { make_target_lib_path(self.sysroot, self.target_triple) From 5681571f6c3480ececdefd07eb313baa6c13ae22 Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Sat, 4 May 2013 10:35:07 +0900 Subject: [PATCH 187/215] compiletest: remove --host and cleanup --- mk/tests.mk | 3 +- src/compiletest/common.rs | 9 +- src/compiletest/compiletest.rc | 29 ++-- src/compiletest/runtest.rs | 250 +++++++++++++++++---------------- 4 files changed, 145 insertions(+), 146 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index 9997f170a98f0..35ced32f1f2e9 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -497,9 +497,8 @@ CTEST_COMMON_ARGS$(1)-T-$(2)-H-$(3) := \ --compile-lib-path $$(HLIB$(1)_H_$(3)) \ --run-lib-path $$(TLIB$(1)_T_$(2)_H_$(3)) \ --rustc-path $$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \ - --aux-base $$(S)src/test/auxiliary/ \ + --aux-base $$(S)src/test/auxiliary/ \ --stage-id stage$(1)-$(2) \ - --host $(CFG_BUILD_TRIPLE) \ --target $(2) \ --adb-path=$(CFG_ADB) \ --adb-test-dir=$(CFG_ADB_TEST_DIR) \ diff --git a/src/compiletest/common.rs b/src/compiletest/common.rs index 87a7dae5a7f6e..38289f6274180 100644 --- a/src/compiletest/common.rs +++ b/src/compiletest/common.rs @@ -64,10 +64,7 @@ pub struct config { // Run tests using the new runtime newrt: bool, - // Host System to be built - host: ~str, - - // Target System to be executed + // Target system to be tested target: ~str, // Extra parameter to run adb on arm-linux-androideabi @@ -76,8 +73,8 @@ pub struct config { // Extra parameter to run test sute on arm-linux-androideabi adb_test_dir: ~str, - // check if can be run or not - flag_runnable: bool, + // status whether android device available or not + adb_device_status: bool, // Explain what's going on verbose: bool diff --git a/src/compiletest/compiletest.rc b/src/compiletest/compiletest.rc index fab73d78021c2..3fb6937819ee3 100644 --- a/src/compiletest/compiletest.rc +++ b/src/compiletest/compiletest.rc @@ -61,7 +61,6 @@ pub fn parse_config(args: ~[~str]) -> config { getopts::optopt(~"logfile"), getopts::optflag(~"jit"), getopts::optflag(~"newrt"), - getopts::optopt(~"host"), getopts::optopt(~"target"), getopts::optopt(~"adb-path"), getopts::optopt(~"adb-test-dir") @@ -98,25 +97,18 @@ pub fn parse_config(args: ~[~str]) -> config { rustcflags: getopts::opt_maybe_str(matches, ~"rustcflags"), jit: getopts::opt_present(matches, ~"jit"), newrt: getopts::opt_present(matches, ~"newrt"), - host: opt_str(getopts::opt_maybe_str(matches, ~"host")), target: opt_str(getopts::opt_maybe_str(matches, ~"target")), adb_path: opt_str(getopts::opt_maybe_str(matches, ~"adb-path")), adb_test_dir: opt_str(getopts::opt_maybe_str(matches, ~"adb-test-dir")), - flag_runnable: - if (getopts::opt_maybe_str(matches, ~"host") == - getopts::opt_maybe_str(matches, ~"target")) { true } - else { - match getopts::opt_maybe_str(matches, ~"target") { - Some(~"arm-linux-androideabi") => { - if (opt_str(getopts::opt_maybe_str(matches, ~"adb-test-dir")) != - ~"(none)" && - opt_str(getopts::opt_maybe_str(matches, ~"adb-test-dir")) != - ~"") { true } - else { false } - } - _ => { true } - } - }, + adb_device_status: + if (opt_str(getopts::opt_maybe_str(matches, ~"target")) == + ~"arm-linux-androideabi") { + if (opt_str(getopts::opt_maybe_str(matches, ~"adb-test-dir")) != + ~"(none)" && + opt_str(getopts::opt_maybe_str(matches, ~"adb-test-dir")) != + ~"") { true } + else { false } + } else { false }, verbose: getopts::opt_present(matches, ~"verbose") } } @@ -137,11 +129,10 @@ pub fn log_config(config: config) { logv(c, fmt!("rustcflags: %s", opt_str(config.rustcflags))); logv(c, fmt!("jit: %b", config.jit)); logv(c, fmt!("newrt: %b", config.newrt)); - logv(c, fmt!("host: %s", config.host)); logv(c, fmt!("target: %s", config.target)); logv(c, fmt!("adb_path: %s", config.adb_path)); logv(c, fmt!("adb_test_dir: %s", config.adb_test_dir)); - logv(c, fmt!("flag_runnable: %b", config.flag_runnable)); + logv(c, fmt!("adb_device_status: %b", config.adb_device_status)); logv(c, fmt!("verbose: %b", config.verbose)); logv(c, fmt!("\n")); } diff --git a/src/compiletest/runtest.rs b/src/compiletest/runtest.rs index d1319c395add6..07b439174be33 100644 --- a/src/compiletest/runtest.rs +++ b/src/compiletest/runtest.rs @@ -77,18 +77,19 @@ fn run_rfail_test(config: config, props: TestProps, testfile: &Path) { fatal_ProcRes(~"run-fail test isn't valgrind-clean!", ProcRes); } - if (config.host == config.target) { - check_correct_failure_status(ProcRes); - check_error_patterns(props, testfile, ProcRes); - } else { - match (config.target, config.flag_runnable) { + match config.target { - (~"arm-linux-androideabi", false) => { } - _ => { + ~"arm-linux-androideabi" => { + if (config.adb_device_status) { check_correct_failure_status(ProcRes); check_error_patterns(props, testfile, ProcRes); } } + + _=> { + check_correct_failure_status(ProcRes); + check_error_patterns(props, testfile, ProcRes); + } } } @@ -494,99 +495,21 @@ fn exec_compiled_test(config: config, props: TestProps, props.exec_env }; - if (config.host == config.target) { - compose_and_run(config, testfile, - make_run_args(config, props, testfile), - env, - config.run_lib_path, None) - } else { - let args = make_run_args(config, props, testfile); - let cmdline = make_cmdline(~"", args.prog, args.args); - - match (config.target, config.flag_runnable) { - - (~"arm-linux-androideabi", true) => { - - // get bare program string - let mut tvec = ~[]; - let tstr = args.prog; - for str::each_split_char(tstr, '/') |ts| { tvec.push(ts.to_owned()) } - let prog_short = tvec.pop(); - - // copy to target - let copy_result = procsrv::run(~"", config.adb_path, - ~[~"push", args.prog, config.adb_test_dir], - ~[(~"",~"")], Some(~"")); - - if config.verbose { - io::stdout().write_str(fmt!("push (%s) %s %s %s", - config.target, args.prog, - copy_result.out, copy_result.err)); - } - - // execute program - logv(config, fmt!("executing (%s) %s", config.target, cmdline)); - - // NOTE: adb shell dose not forward stdout and stderr of internal result - // to stdout and stderr seperately but to stdout only - let mut newargs_out = ~[]; - let mut newargs_err = ~[]; - let subargs = args.args; - newargs_out.push(~"shell"); - newargs_err.push(~"shell"); - - let mut newcmd_out = ~""; - let mut newcmd_err = ~""; - - newcmd_out.push_str(fmt!("LD_LIBRARY_PATH=%s %s/%s", - config.adb_test_dir, config.adb_test_dir, prog_short)); - - newcmd_err.push_str(fmt!("LD_LIBRARY_PATH=%s %s/%s", - config.adb_test_dir, config.adb_test_dir, prog_short)); - - for vec::each(subargs) |tv| { - newcmd_out.push_str(" "); - newcmd_err.push_str(" "); - newcmd_out.push_str(tv.to_owned()); - newcmd_err.push_str(tv.to_owned()); - } - - newcmd_out.push_str(" 2>/dev/null"); - newcmd_err.push_str(" 1>/dev/null"); - - newargs_out.push(newcmd_out); - newargs_err.push(newcmd_err); - - let exe_result_out = procsrv::run(~"", config.adb_path, - newargs_out, ~[(~"",~"")], Some(~"")); - let exe_result_err = procsrv::run(~"", config.adb_path, - newargs_err, ~[(~"",~"")], Some(~"")); + match config.target { - dump_output(config, testfile, exe_result_out.out, exe_result_err.out); - - match exe_result_err.out { - ~"" => ProcRes {status: exe_result_out.status, stdout: exe_result_out.out, - stderr: exe_result_err.out, cmdline: cmdline }, - _ => ProcRes {status: 101, stdout: exe_result_out.out, - stderr: exe_result_err.out, cmdline: cmdline } - } - } - - (~"arm-linux-androideabi", false) => { - match config.mode { - mode_run_fail => ProcRes {status: 101, stdout: ~"", - stderr: ~"", cmdline: cmdline}, - _ => ProcRes {status: 0, stdout: ~"", - stderr: ~"", cmdline: cmdline} - } + ~"arm-linux-androideabi" => { + if (config.adb_device_status) { + _arm_exec_compiled_test(config, props, testfile) + } else { + _dummy_exec_compiled_test(config, props, testfile) } + } - _=> { - compose_and_run(config, testfile, - make_run_args(config, props, testfile), - env, - config.run_lib_path, None) - } + _=> { + compose_and_run(config, testfile, + make_run_args(config, props, testfile), + env, + config.run_lib_path, None) } } } @@ -618,32 +541,16 @@ fn compose_and_run_compiler( abs_ab.to_str()), auxres); } - if (config.host != config.target) - { - match (config.target, config.flag_runnable) { - - (~"arm-linux-androideabi", true) => { - - let tstr = aux_output_dir_name(config, testfile).to_str(); - - for os::list_dir_path(&Path(tstr)).each |file| { - if (file.filetype() == Some(~".so")) { + match config.target { - let copy_result = procsrv::run(~"", config.adb_path, - ~[~"push", file.to_str(), config.adb_test_dir], - ~[(~"",~"")], Some(~"")); - - if config.verbose { - io::stdout().write_str(fmt!("push (%s) %s %s %s", - config.target, file.to_str(), - copy_result.out, copy_result.err)); - } - } - } + ~"arm-linux-androideabi" => { + if (config.adb_device_status) { + _arm_push_aux_shared_library(config, testfile); } - _=> () } + + _=> { } } } @@ -829,3 +736,108 @@ stderr:\n\ io::stdout().write_str(msg); fail!(); } + +fn _arm_exec_compiled_test(config: config, props: TestProps, + testfile: &Path) -> ProcRes { + + let args = make_run_args(config, props, testfile); + let cmdline = make_cmdline(~"", args.prog, args.args); + + // get bare program string + let mut tvec = ~[]; + let tstr = args.prog; + for str::each_split_char(tstr, '/') |ts| { tvec.push(ts.to_owned()) } + let prog_short = tvec.pop(); + + // copy to target + let copy_result = procsrv::run(~"", config.adb_path, + ~[~"push", args.prog, config.adb_test_dir], + ~[(~"",~"")], Some(~"")); + + if config.verbose { + io::stdout().write_str(fmt!("push (%s) %s %s %s", + config.target, args.prog, + copy_result.out, copy_result.err)); + } + + // execute program + logv(config, fmt!("executing (%s) %s", config.target, cmdline)); + + // adb shell dose not forward stdout and stderr of internal result + // to stdout and stderr seperately but to stdout only + let mut newargs_out = ~[]; + let mut newargs_err = ~[]; + let subargs = args.args; + newargs_out.push(~"shell"); + newargs_err.push(~"shell"); + + let mut newcmd_out = ~""; + let mut newcmd_err = ~""; + + newcmd_out.push_str(fmt!("LD_LIBRARY_PATH=%s %s/%s", + config.adb_test_dir, config.adb_test_dir, prog_short)); + + newcmd_err.push_str(fmt!("LD_LIBRARY_PATH=%s %s/%s", + config.adb_test_dir, config.adb_test_dir, prog_short)); + + for vec::each(subargs) |tv| { + newcmd_out.push_str(" "); + newcmd_err.push_str(" "); + newcmd_out.push_str(tv.to_owned()); + newcmd_err.push_str(tv.to_owned()); + } + + newcmd_out.push_str(" 2>/dev/null"); + newcmd_err.push_str(" 1>/dev/null"); + + newargs_out.push(newcmd_out); + newargs_err.push(newcmd_err); + + let exe_result_out = procsrv::run(~"", config.adb_path, + newargs_out, ~[(~"",~"")], Some(~"")); + let exe_result_err = procsrv::run(~"", config.adb_path, + newargs_err, ~[(~"",~"")], Some(~"")); + + dump_output(config, testfile, exe_result_out.out, exe_result_err.out); + + match exe_result_err.out { + ~"" => ProcRes {status: exe_result_out.status, stdout: exe_result_out.out, + stderr: exe_result_err.out, cmdline: cmdline }, + _ => ProcRes {status: 101, stdout: exe_result_out.out, + stderr: exe_result_err.out, cmdline: cmdline } + } +} + +fn _dummy_exec_compiled_test(config: config, props: TestProps, + testfile: &Path) -> ProcRes { + + let args = make_run_args(config, props, testfile); + let cmdline = make_cmdline(~"", args.prog, args.args); + + match config.mode { + mode_run_fail => ProcRes {status: 101, stdout: ~"", + stderr: ~"", cmdline: cmdline}, + _ => ProcRes {status: 0, stdout: ~"", + stderr: ~"", cmdline: cmdline} + } +} + +fn _arm_push_aux_shared_library(config: config, testfile: &Path) { + let tstr = aux_output_dir_name(config, testfile).to_str(); + + for os::list_dir_path(&Path(tstr)).each |file| { + + if (file.filetype() == Some(~".so")) { + + let copy_result = procsrv::run(~"", config.adb_path, + ~[~"push", file.to_str(), config.adb_test_dir], + ~[(~"",~"")], Some(~"")); + + if config.verbose { + io::stdout().write_str(fmt!("push (%s) %s %s %s", + config.target, file.to_str(), + copy_result.out, copy_result.err)); + } + } + } +} From 0ff8200671c38e0068ba40267d02f99737e77cab Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 3 May 2013 22:07:33 -0400 Subject: [PATCH 188/215] factor code for write guards into its own module; add neglected resolve_stage0 --- src/librustc/middle/resolve_stage0.rs | 5313 ++++++++++++++++++++++ src/librustc/middle/trans/write_guard.rs | 201 + 2 files changed, 5514 insertions(+) create mode 100644 src/librustc/middle/resolve_stage0.rs create mode 100644 src/librustc/middle/trans/write_guard.rs diff --git a/src/librustc/middle/resolve_stage0.rs b/src/librustc/middle/resolve_stage0.rs new file mode 100644 index 0000000000000..ff46abaf7128c --- /dev/null +++ b/src/librustc/middle/resolve_stage0.rs @@ -0,0 +1,5313 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use driver::session; +use driver::session::Session; +use metadata::csearch::{each_path, get_trait_method_def_ids}; +use metadata::csearch::get_method_name_and_self_ty; +use metadata::csearch::get_static_methods_if_impl; +use metadata::csearch::get_type_name_if_impl; +use metadata::cstore::find_extern_mod_stmt_cnum; +use metadata::decoder::{def_like, dl_def, dl_field, dl_impl}; +use middle::lang_items::LanguageItems; +use middle::lint::{allow, level, unused_imports}; +use middle::lint::{get_lint_level, get_lint_settings_level}; +use middle::pat_util::pat_bindings; + +use syntax::ast::{RegionTyParamBound, TraitTyParamBound, _mod, add, arm}; +use syntax::ast::{binding_mode, bitand, bitor, bitxor, blk}; +use syntax::ast::{bind_infer, bind_by_ref, bind_by_copy}; +use syntax::ast::{crate, decl_item, def, def_arg, def_binding}; +use syntax::ast::{def_const, def_foreign_mod, def_fn, def_id, def_label}; +use syntax::ast::{def_local, def_mod, def_prim_ty, def_region, def_self}; +use syntax::ast::{def_self_ty, def_static_method, def_struct, def_ty}; +use syntax::ast::{def_ty_param, def_typaram_binder, def_trait}; +use syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op}; +use syntax::ast::{expr_binary, expr_break, expr_field}; +use syntax::ast::{expr_fn_block, expr_index, expr_method_call, expr_path}; +use syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param}; +use syntax::ast::{def_upvar, def_use, def_variant, quot, eq}; +use syntax::ast::{expr, expr_again, expr_assign_op}; +use syntax::ast::{expr_index, expr_loop}; +use syntax::ast::{expr_path, expr_struct, expr_unary, fn_decl}; +use syntax::ast::{foreign_item, foreign_item_const, foreign_item_fn, ge}; +use syntax::ast::Generics; +use syntax::ast::{gt, ident, inherited, item, item_struct}; +use syntax::ast::{item_const, item_enum, item_fn, item_foreign_mod}; +use syntax::ast::{item_impl, item_mac, item_mod, item_trait, item_ty, le}; +use syntax::ast::{local, local_crate, lt, method, mul}; +use syntax::ast::{named_field, ne, neg, node_id, pat, pat_enum, pat_ident}; +use syntax::ast::{Path, pat_lit, pat_range, pat_struct}; +use syntax::ast::{prim_ty, private, provided}; +use syntax::ast::{public, required, rem, self_ty_, shl, shr, stmt_decl}; +use syntax::ast::{struct_dtor, struct_field, struct_variant_kind}; +use syntax::ast::{sty_static, subtract, trait_ref, tuple_variant_kind, Ty}; +use syntax::ast::{ty_bool, ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i}; +use syntax::ast::{ty_i16, ty_i32, ty_i64, ty_i8, ty_int, TyParam, ty_path}; +use syntax::ast::{ty_str, ty_u, ty_u16, ty_u32, ty_u64, ty_u8, ty_uint}; +use syntax::ast::unnamed_field; +use syntax::ast::{variant, view_item, view_item_extern_mod}; +use syntax::ast::{view_item_use, view_path_glob, view_path_list}; +use syntax::ast::{view_path_simple, anonymous, named, not}; +use syntax::ast::{unsafe_fn}; +use syntax::ast_util::{def_id_of_def, local_def}; +use syntax::ast_util::{path_to_ident, walk_pat, trait_method_to_ty_method}; +use syntax::ast_util::{Privacy, Public, Private}; +use syntax::ast_util::{variant_visibility_to_privacy, visibility_to_privacy}; +use syntax::attr::{attr_metas, contains_name, attrs_contains_name}; +use syntax::parse::token::ident_interner; +use syntax::parse::token::special_idents; +use syntax::print::pprust::path_to_str; +use syntax::codemap::{span, dummy_sp}; +use syntax::visit::{default_visitor, mk_vt, Visitor, visit_block}; +use syntax::visit::{visit_crate, visit_expr, visit_expr_opt}; +use syntax::visit::{visit_foreign_item, visit_item}; +use syntax::visit::{visit_mod, visit_ty, vt}; +use syntax::opt_vec::OptVec; + +use core::option::Some; +use core::str::each_split_str; +use core::hashmap::{HashMap, HashSet}; +use core::util; + +// Definition mapping +pub type DefMap = @mut HashMap; + +pub struct binding_info { + span: span, + binding_mode: binding_mode, +} + +// Map from the name in a pattern to its binding mode. +pub type BindingMap = HashMap; + +// Implementation resolution +// +// FIXME #4946: This kind of duplicates information kept in +// ty::method. Maybe it should go away. + +pub struct MethodInfo { + did: def_id, + n_tps: uint, + ident: ident, + self_type: self_ty_ +} + +pub struct Impl { + did: def_id, + ident: ident, + methods: ~[@MethodInfo] +} + +// Trait method resolution +pub type TraitMap = HashMap; + +// This is the replacement export map. It maps a module to all of the exports +// within. +pub type ExportMap2 = @mut HashMap; + +pub struct Export2 { + name: @~str, // The name of the target. + def_id: def_id, // The definition of the target. + reexport: bool, // Whether this is a reexport. +} + +#[deriving(Eq)] +pub enum PatternBindingMode { + RefutableMode, + LocalIrrefutableMode, + ArgumentIrrefutableMode, +} + +#[deriving(Eq)] +pub enum Namespace { + TypeNS, + ValueNS +} + +/// A NamespaceResult represents the result of resolving an import in +/// a particular namespace. The result is either definitely-resolved, +/// definitely- unresolved, or unknown. +pub enum NamespaceResult { + /// Means that resolve hasn't gathered enough information yet to determine + /// whether the name is bound in this namespace. (That is, it hasn't + /// resolved all `use` directives yet.) + UnknownResult, + /// Means that resolve has determined that the name is definitely + /// not bound in the namespace. + UnboundResult, + /// Means that resolve has determined that the name is bound in the Module + /// argument, and specified by the NameBindings argument. + BoundResult(@mut Module, @mut NameBindings) +} + +pub impl NamespaceResult { + fn is_unknown(&self) -> bool { + match *self { + UnknownResult => true, + _ => false + } + } +} + +pub enum NameDefinition { + NoNameDefinition, //< The name was unbound. + ChildNameDefinition(def), //< The name identifies an immediate child. + ImportNameDefinition(def) //< The name identifies an import. +} + +#[deriving(Eq)] +pub enum Mutability { + Mutable, + Immutable +} + +pub enum SelfBinding { + NoSelfBinding, + HasSelfBinding(node_id, bool /* is implicit */) +} + +pub type ResolveVisitor = vt<()>; + +/// Contains data for specific types of import directives. +pub enum ImportDirectiveSubclass { + SingleImport(ident /* target */, ident /* source */), + GlobImport +} + +/// The context that we thread through while building the reduced graph. +pub enum ReducedGraphParent { + ModuleReducedGraphParent(@mut Module) +} + +pub enum ResolveResult { + Failed, // Failed to resolve the name. + Indeterminate, // Couldn't determine due to unresolved globs. + Success(T) // Successfully resolved the import. +} + +pub impl ResolveResult { + fn failed(&self) -> bool { + match *self { Failed => true, _ => false } + } + fn indeterminate(&self) -> bool { + match *self { Indeterminate => true, _ => false } + } +} + +pub enum TypeParameters<'self> { + NoTypeParameters, //< No type parameters. + HasTypeParameters(&'self Generics, //< Type parameters. + node_id, //< ID of the enclosing item + + // The index to start numbering the type parameters at. + // This is zero if this is the outermost set of type + // parameters, or equal to the number of outer type + // parameters. For example, if we have: + // + // impl I { + // fn method() { ... } + // } + // + // The index at the method site will be 1, because the + // outer T had index 0. + uint, + + // The kind of the rib used for type parameters. + RibKind) +} + +// The rib kind controls the translation of argument or local definitions +// (`def_arg` or `def_local`) to upvars (`def_upvar`). + +pub enum RibKind { + // No translation needs to be applied. + NormalRibKind, + + // We passed through a function scope at the given node ID. Translate + // upvars as appropriate. + FunctionRibKind(node_id /* func id */, node_id /* body id */), + + // We passed through an impl or trait and are now in one of its + // methods. Allow references to ty params that that impl or trait + // binds. Disallow any other upvars (including other ty params that are + // upvars). + // parent; method itself + MethodRibKind(node_id, MethodSort), + + // We passed through a function *item* scope. Disallow upvars. + OpaqueFunctionRibKind, + + // We're in a constant item. Can't refer to dynamic stuff. + ConstantItemRibKind +} + +// Methods can be required or provided. Required methods only occur in traits. +pub enum MethodSort { + Required, + Provided(node_id) +} + +// The X-ray flag indicates that a context has the X-ray privilege, which +// allows it to reference private names. Currently, this is used for the test +// runner. +// +// FIXME #4947: The X-ray flag is kind of questionable in the first +// place. It might be better to introduce an expr_xray_path instead. + +#[deriving(Eq)] +pub enum XrayFlag { + NoXray, //< Private items cannot be accessed. + Xray //< Private items can be accessed. +} + +pub enum UseLexicalScopeFlag { + DontUseLexicalScope, + UseLexicalScope +} + +pub enum SearchThroughModulesFlag { + DontSearchThroughModules, + SearchThroughModules +} + +pub enum ModulePrefixResult { + NoPrefixFound, + PrefixFound(@mut Module, uint) +} + +#[deriving(Eq)] +pub enum AllowCapturingSelfFlag { + AllowCapturingSelf, //< The "self" definition can be captured. + DontAllowCapturingSelf, //< The "self" definition cannot be captured. +} + +#[deriving(Eq)] +enum NameSearchType { + SearchItemsAndPublicImports, //< Search items and public imports. + SearchItemsAndAllImports, //< Search items and all imports. +} + +pub enum BareIdentifierPatternResolution { + FoundStructOrEnumVariant(def), + FoundConst(def), + BareIdentifierPatternUnresolved +} + +// Specifies how duplicates should be handled when adding a child item if +// another item exists with the same name in some namespace. +#[deriving(Eq)] +pub enum DuplicateCheckingMode { + ForbidDuplicateModules, + ForbidDuplicateTypes, + ForbidDuplicateValues, + ForbidDuplicateTypesAndValues, + OverwriteDuplicates +} + +// Returns the namespace associated with the given duplicate checking mode, +// or fails for OverwriteDuplicates. This is used for error messages. +pub fn namespace_for_duplicate_checking_mode(mode: DuplicateCheckingMode) + -> Namespace { + match mode { + ForbidDuplicateModules | ForbidDuplicateTypes | + ForbidDuplicateTypesAndValues => TypeNS, + ForbidDuplicateValues => ValueNS, + OverwriteDuplicates => fail!(~"OverwriteDuplicates has no namespace") + } +} + +/// One local scope. +pub struct Rib { + bindings: @mut HashMap, + kind: RibKind, +} + +pub fn Rib(kind: RibKind) -> Rib { + Rib { + bindings: @mut HashMap::new(), + kind: kind + } +} + + +/// One import directive. +pub struct ImportDirective { + privacy: Privacy, + module_path: ~[ident], + subclass: @ImportDirectiveSubclass, + span: span, +} + +pub fn ImportDirective(privacy: Privacy, + module_path: ~[ident], + subclass: @ImportDirectiveSubclass, + span: span) + -> ImportDirective { + ImportDirective { + privacy: privacy, + module_path: module_path, + subclass: subclass, + span: span + } +} + +/// The item that an import resolves to. +pub struct Target { + target_module: @mut Module, + bindings: @mut NameBindings, +} + +pub fn Target(target_module: @mut Module, + bindings: @mut NameBindings) + -> Target { + Target { + target_module: target_module, + bindings: bindings + } +} + +/// An ImportResolution represents a particular `use` directive. +pub struct ImportResolution { + /// The privacy of this `use` directive (whether it's `use` or + /// `pub use`. + privacy: Privacy, + span: span, + + // The number of outstanding references to this name. When this reaches + // zero, outside modules can count on the targets being correct. Before + // then, all bets are off; future imports could override this name. + + outstanding_references: uint, + + /// The value that this `use` directive names, if there is one. + value_target: Option, + /// The type that this `use` directive names, if there is one. + type_target: Option, + + /// There exists one state per import statement + state: @mut ImportState, +} + +pub fn ImportResolution(privacy: Privacy, + span: span, + state: @mut ImportState) -> ImportResolution { + ImportResolution { + privacy: privacy, + span: span, + outstanding_references: 0, + value_target: None, + type_target: None, + state: state, + } +} + +pub impl ImportResolution { + fn target_for_namespace(&self, namespace: Namespace) -> Option { + match namespace { + TypeNS => return copy self.type_target, + ValueNS => return copy self.value_target + } + } +} + +pub struct ImportState { + used: bool, + warned: bool +} + +pub fn ImportState() -> ImportState { + ImportState{ used: false, warned: false } +} + +/// The link from a module up to its nearest parent node. +pub enum ParentLink { + NoParentLink, + ModuleParentLink(@mut Module, ident), + BlockParentLink(@mut Module, node_id) +} + +/// The type of module this is. +pub enum ModuleKind { + NormalModuleKind, + ExternModuleKind, + TraitModuleKind, + AnonymousModuleKind, +} + +/// One node in the tree of modules. +pub struct Module { + parent_link: ParentLink, + def_id: Option, + kind: ModuleKind, + + children: @mut HashMap, + imports: @mut ~[@ImportDirective], + + // The external module children of this node that were declared with + // `extern mod`. + external_module_children: @mut HashMap, + + // The anonymous children of this node. Anonymous children are pseudo- + // modules that are implicitly created around items contained within + // blocks. + // + // For example, if we have this: + // + // fn f() { + // fn g() { + // ... + // } + // } + // + // There will be an anonymous module created around `g` with the ID of the + // entry block for `f`. + + anonymous_children: @mut HashMap, + + // The status of resolving each import in this module. + import_resolutions: @mut HashMap, + + // The number of unresolved globs that this module exports. + glob_count: uint, + + // The index of the import we're resolving. + resolved_import_count: uint, +} + +pub fn Module(parent_link: ParentLink, + def_id: Option, + kind: ModuleKind) + -> Module { + Module { + parent_link: parent_link, + def_id: def_id, + kind: kind, + children: @mut HashMap::new(), + imports: @mut ~[], + external_module_children: @mut HashMap::new(), + anonymous_children: @mut HashMap::new(), + import_resolutions: @mut HashMap::new(), + glob_count: 0, + resolved_import_count: 0 + } +} + +pub impl Module { + fn all_imports_resolved(&self) -> bool { + let imports = &mut *self.imports; + return imports.len() == self.resolved_import_count; + } +} + +// Records a possibly-private type definition. +pub struct TypeNsDef { + privacy: Privacy, + module_def: Option<@mut Module>, + type_def: Option +} + +// Records a possibly-private value definition. +pub struct ValueNsDef { + privacy: Privacy, + def: def, +} + +// Records the definitions (at most one for each namespace) that a name is +// bound to. +pub struct NameBindings { + type_def: Option, //< Meaning in type namespace. + value_def: Option, //< Meaning in value namespace. + + // For error reporting + // FIXME (#3783): Merge me into TypeNsDef and ValueNsDef. + type_span: Option, + value_span: Option, +} + +pub impl NameBindings { + /// Creates a new module in this set of name bindings. + fn define_module(@mut self, + privacy: Privacy, + parent_link: ParentLink, + def_id: Option, + kind: ModuleKind, + sp: span) { + // Merges the module with the existing type def or creates a new one. + let module_ = @mut Module(parent_link, def_id, kind); + match self.type_def { + None => { + self.type_def = Some(TypeNsDef { + privacy: privacy, + module_def: Some(module_), + type_def: None + }); + } + Some(copy type_def) => { + self.type_def = Some(TypeNsDef { + privacy: privacy, + module_def: Some(module_), + .. type_def + }); + } + } + self.type_span = Some(sp); + } + + /// Records a type definition. + fn define_type(@mut self, privacy: Privacy, def: def, sp: span) { + // Merges the type with the existing type def or creates a new one. + match self.type_def { + None => { + self.type_def = Some(TypeNsDef { + privacy: privacy, + module_def: None, + type_def: Some(def) + }); + } + Some(copy type_def) => { + self.type_def = Some(TypeNsDef { + privacy: privacy, + type_def: Some(def), + .. type_def + }); + } + } + self.type_span = Some(sp); + } + + /// Records a value definition. + fn define_value(@mut self, privacy: Privacy, def: def, sp: span) { + self.value_def = Some(ValueNsDef { privacy: privacy, def: def }); + self.value_span = Some(sp); + } + + /// Returns the module node if applicable. + fn get_module_if_available(&self) -> Option<@mut Module> { + match self.type_def { + Some(ref type_def) => (*type_def).module_def, + None => None + } + } + + /** + * Returns the module node. Fails if this node does not have a module + * definition. + */ + fn get_module(@mut self) -> @mut Module { + match self.get_module_if_available() { + None => { + fail!(~"get_module called on a node with no module \ + definition!") + } + Some(module_def) => module_def + } + } + + fn defined_in_namespace(&self, namespace: Namespace) -> bool { + match namespace { + TypeNS => return self.type_def.is_some(), + ValueNS => return self.value_def.is_some() + } + } + + fn defined_in_public_namespace(&self, namespace: Namespace) -> bool { + match namespace { + TypeNS => match self.type_def { + Some(def) => def.privacy != Private, + None => false + }, + ValueNS => match self.value_def { + Some(def) => def.privacy != Private, + None => false + } + } + } + + fn def_for_namespace(&self, namespace: Namespace) -> Option { + match namespace { + TypeNS => { + match self.type_def { + None => None, + Some(ref type_def) => { + // FIXME (#3784): This is reallllly questionable. + // Perhaps the right thing to do is to merge def_mod + // and def_ty. + match (*type_def).type_def { + Some(type_def) => Some(type_def), + None => { + match (*type_def).module_def { + Some(module_def) => { + let module_def = &mut *module_def; + module_def.def_id.map(|def_id| + def_mod(*def_id)) + } + None => None + } + } + } + } + } + } + ValueNS => { + match self.value_def { + None => None, + Some(value_def) => Some(value_def.def) + } + } + } + } + + fn privacy_for_namespace(&self, namespace: Namespace) -> Option { + match namespace { + TypeNS => { + match self.type_def { + None => None, + Some(ref type_def) => Some((*type_def).privacy) + } + } + ValueNS => { + match self.value_def { + None => None, + Some(value_def) => Some(value_def.privacy) + } + } + } + } + + fn span_for_namespace(&self, namespace: Namespace) -> Option { + if self.defined_in_namespace(namespace) { + match namespace { + TypeNS => self.type_span, + ValueNS => self.value_span, + } + } else { + None + } + } +} + +pub fn NameBindings() -> NameBindings { + NameBindings { + type_def: None, + value_def: None, + type_span: None, + value_span: None + } +} + +/// Interns the names of the primitive types. +pub struct PrimitiveTypeTable { + primitive_types: HashMap, +} + +pub impl PrimitiveTypeTable { + fn intern(&mut self, intr: @ident_interner, string: @~str, + primitive_type: prim_ty) { + let ident = intr.intern(string); + self.primitive_types.insert(ident, primitive_type); + } +} + +pub fn PrimitiveTypeTable(intr: @ident_interner) -> PrimitiveTypeTable { + let mut table = PrimitiveTypeTable { + primitive_types: HashMap::new() + }; + + table.intern(intr, @~"bool", ty_bool); + table.intern(intr, @~"char", ty_int(ty_char)); + table.intern(intr, @~"float", ty_float(ty_f)); + table.intern(intr, @~"f32", ty_float(ty_f32)); + table.intern(intr, @~"f64", ty_float(ty_f64)); + table.intern(intr, @~"int", ty_int(ty_i)); + table.intern(intr, @~"i8", ty_int(ty_i8)); + table.intern(intr, @~"i16", ty_int(ty_i16)); + table.intern(intr, @~"i32", ty_int(ty_i32)); + table.intern(intr, @~"i64", ty_int(ty_i64)); + table.intern(intr, @~"str", ty_str); + table.intern(intr, @~"uint", ty_uint(ty_u)); + table.intern(intr, @~"u8", ty_uint(ty_u8)); + table.intern(intr, @~"u16", ty_uint(ty_u16)); + table.intern(intr, @~"u32", ty_uint(ty_u32)); + table.intern(intr, @~"u64", ty_uint(ty_u64)); + + return table; +} + + +pub fn namespace_to_str(ns: Namespace) -> ~str { + match ns { + TypeNS => ~"type", + ValueNS => ~"value", + } +} + +pub fn Resolver(session: Session, + lang_items: LanguageItems, + crate: @crate) + -> Resolver { + let graph_root = @mut NameBindings(); + + graph_root.define_module(Public, + NoParentLink, + Some(def_id { crate: 0, node: 0 }), + NormalModuleKind, + crate.span); + + let current_module = graph_root.get_module(); + + let self = Resolver { + session: @session, + lang_items: copy lang_items, + crate: crate, + + // The outermost module has def ID 0; this is not reflected in the + // AST. + + graph_root: graph_root, + + trait_info: HashMap::new(), + structs: HashSet::new(), + + unresolved_imports: 0, + + current_module: current_module, + value_ribs: ~[], + type_ribs: ~[], + label_ribs: ~[], + + xray_context: NoXray, + current_trait_refs: None, + + self_ident: special_idents::self_, + type_self_ident: special_idents::type_self, + + primitive_type_table: @PrimitiveTypeTable(session. + parse_sess.interner), + + namespaces: ~[ TypeNS, ValueNS ], + + attr_main_fn: None, + main_fns: ~[], + + start_fn: None, + + def_map: @mut HashMap::new(), + export_map2: @mut HashMap::new(), + trait_map: HashMap::new(), + + intr: session.intr() + }; + + self +} + +/// The main resolver class. +pub struct Resolver { + session: @Session, + lang_items: LanguageItems, + crate: @crate, + + intr: @ident_interner, + + graph_root: @mut NameBindings, + + trait_info: HashMap>, + structs: HashSet, + + // The number of imports that are currently unresolved. + unresolved_imports: uint, + + // The module that represents the current item scope. + current_module: @mut Module, + + // The current set of local scopes, for values. + // FIXME #4948: Reuse ribs to avoid allocation. + value_ribs: ~[@Rib], + + // The current set of local scopes, for types. + type_ribs: ~[@Rib], + + // The current set of local scopes, for labels. + label_ribs: ~[@Rib], + + // Whether the current context is an X-ray context. An X-ray context is + // allowed to access private names of any module. + xray_context: XrayFlag, + + // The trait that the current context can refer to. + current_trait_refs: Option<~[def_id]>, + + // The ident for the keyword "self". + self_ident: ident, + // The ident for the non-keyword "Self". + type_self_ident: ident, + + // The idents for the primitive types. + primitive_type_table: @PrimitiveTypeTable, + + // The four namespaces. + namespaces: ~[Namespace], + + // The function that has attribute named 'main' + attr_main_fn: Option<(node_id, span)>, + + // The functions that could be main functions + main_fns: ~[Option<(node_id, span)>], + + // The function that has the attribute 'start' on it + start_fn: Option<(node_id, span)>, + + def_map: DefMap, + export_map2: ExportMap2, + trait_map: TraitMap, +} + +pub impl Resolver { + /// The main name resolution procedure. + fn resolve(@mut self) { + self.build_reduced_graph(); + self.session.abort_if_errors(); + + self.resolve_imports(); + self.session.abort_if_errors(); + + self.record_exports(); + self.session.abort_if_errors(); + + self.resolve_crate(); + self.session.abort_if_errors(); + + self.check_duplicate_main(); + self.check_for_unused_imports_if_necessary(); + } + + // + // Reduced graph building + // + // Here we build the "reduced graph": the graph of the module tree without + // any imports resolved. + // + + /// Constructs the reduced graph for the entire crate. + fn build_reduced_graph(@mut self) { + let initial_parent = + ModuleReducedGraphParent(self.graph_root.get_module()); + visit_crate(self.crate, initial_parent, mk_vt(@Visitor { + visit_item: |item, context, visitor| + self.build_reduced_graph_for_item(item, context, visitor), + + visit_foreign_item: |foreign_item, context, visitor| + self.build_reduced_graph_for_foreign_item(foreign_item, + context, + visitor), + + visit_view_item: |view_item, context, visitor| + self.build_reduced_graph_for_view_item(view_item, + context, + visitor), + + visit_block: |block, context, visitor| + self.build_reduced_graph_for_block(block, + context, + visitor), + + .. *default_visitor() + })); + } + + /// Returns the current module tracked by the reduced graph parent. + fn get_module_from_parent(@mut self, + reduced_graph_parent: ReducedGraphParent) + -> @mut Module { + match reduced_graph_parent { + ModuleReducedGraphParent(module_) => { + return module_; + } + } + } + + /** + * Adds a new child item to the module definition of the parent node and + * returns its corresponding name bindings as well as the current parent. + * Or, if we're inside a block, creates (or reuses) an anonymous module + * corresponding to the innermost block ID and returns the name bindings + * as well as the newly-created parent. + * + * If this node does not have a module definition and we are not inside + * a block, fails. + */ + fn add_child(@mut self, + name: ident, + reduced_graph_parent: ReducedGraphParent, + duplicate_checking_mode: DuplicateCheckingMode, + // For printing errors + sp: span) + -> (@mut NameBindings, ReducedGraphParent) { + + // If this is the immediate descendant of a module, then we add the + // child name directly. Otherwise, we create or reuse an anonymous + // module and add the child to that. + + let module_; + match reduced_graph_parent { + ModuleReducedGraphParent(parent_module) => { + module_ = parent_module; + } + } + + // Add or reuse the child. + let new_parent = ModuleReducedGraphParent(module_); + match module_.children.find(&name) { + None => { + let child = @mut NameBindings(); + module_.children.insert(name, child); + return (child, new_parent); + } + Some(&child) => { + // Enforce the duplicate checking mode: + // + // * If we're requesting duplicate module checking, check that + // there isn't a module in the module with the same name. + // + // * If we're requesting duplicate type checking, check that + // there isn't a type in the module with the same name. + // + // * If we're requesting duplicate value checking, check that + // there isn't a value in the module with the same name. + // + // * If we're requesting duplicate type checking and duplicate + // value checking, check that there isn't a duplicate type + // and a duplicate value with the same name. + // + // * If no duplicate checking was requested at all, do + // nothing. + + let mut is_duplicate = false; + match duplicate_checking_mode { + ForbidDuplicateModules => { + is_duplicate = + child.get_module_if_available().is_some(); + } + ForbidDuplicateTypes => { + match child.def_for_namespace(TypeNS) { + Some(def_mod(_)) | None => {} + Some(_) => is_duplicate = true + } + } + ForbidDuplicateValues => { + is_duplicate = child.defined_in_namespace(ValueNS); + } + ForbidDuplicateTypesAndValues => { + match child.def_for_namespace(TypeNS) { + Some(def_mod(_)) | None => {} + Some(_) => is_duplicate = true + }; + if child.defined_in_namespace(ValueNS) { + is_duplicate = true; + } + } + OverwriteDuplicates => {} + } + if duplicate_checking_mode != OverwriteDuplicates && + is_duplicate { + // Return an error here by looking up the namespace that + // had the duplicate. + let ns = namespace_for_duplicate_checking_mode( + duplicate_checking_mode); + self.session.span_err(sp, + fmt!("duplicate definition of %s %s", + namespace_to_str(ns), + *self.session.str_of(name))); + for child.span_for_namespace(ns).each |sp| { + self.session.span_note(*sp, + fmt!("first definition of %s %s here:", + namespace_to_str(ns), + *self.session.str_of(name))); + } + } + return (child, new_parent); + } + } + } + + fn block_needs_anonymous_module(@mut self, block: &blk) -> bool { + // If the block has view items, we need an anonymous module. + if block.node.view_items.len() > 0 { + return true; + } + + // Check each statement. + for block.node.stmts.each |statement| { + match statement.node { + stmt_decl(declaration, _) => { + match declaration.node { + decl_item(_) => { + return true; + } + _ => { + // Keep searching. + } + } + } + _ => { + // Keep searching. + } + } + } + + // If we found neither view items nor items, we don't need to create + // an anonymous module. + + return false; + } + + fn get_parent_link(@mut self, + parent: ReducedGraphParent, + name: ident) + -> ParentLink { + match parent { + ModuleReducedGraphParent(module_) => { + return ModuleParentLink(module_, name); + } + } + } + + /// Constructs the reduced graph for one item. + fn build_reduced_graph_for_item(@mut self, + item: @item, + parent: ReducedGraphParent, + visitor: vt) { + let ident = item.ident; + let sp = item.span; + let privacy = visibility_to_privacy(item.vis); + + match item.node { + item_mod(ref module_) => { + let (name_bindings, new_parent) = + self.add_child(ident, parent, ForbidDuplicateModules, sp); + + let parent_link = self.get_parent_link(new_parent, ident); + let def_id = def_id { crate: 0, node: item.id }; + name_bindings.define_module(privacy, + parent_link, + Some(def_id), + NormalModuleKind, + sp); + + let new_parent = + ModuleReducedGraphParent(name_bindings.get_module()); + + visit_mod(module_, sp, item.id, new_parent, visitor); + } + + item_foreign_mod(ref fm) => { + let new_parent = match fm.sort { + named => { + let (name_bindings, new_parent) = + self.add_child(ident, parent, + ForbidDuplicateModules, sp); + + let parent_link = self.get_parent_link(new_parent, + ident); + let def_id = def_id { crate: 0, node: item.id }; + name_bindings.define_module(privacy, + parent_link, + Some(def_id), + ExternModuleKind, + sp); + + ModuleReducedGraphParent(name_bindings.get_module()) + } + + // For anon foreign mods, the contents just go in the + // current scope + anonymous => parent + }; + + visit_item(item, new_parent, visitor); + } + + // These items live in the value namespace. + item_const(*) => { + let (name_bindings, _) = + self.add_child(ident, parent, ForbidDuplicateValues, sp); + + name_bindings.define_value + (privacy, def_const(local_def(item.id)), sp); + } + item_fn(_, purity, _, _, _) => { + let (name_bindings, new_parent) = + self.add_child(ident, parent, ForbidDuplicateValues, sp); + + let def = def_fn(local_def(item.id), purity); + name_bindings.define_value(privacy, def, sp); + visit_item(item, new_parent, visitor); + } + + // These items live in the type namespace. + item_ty(*) => { + let (name_bindings, _) = + self.add_child(ident, parent, ForbidDuplicateTypes, sp); + + name_bindings.define_type + (privacy, def_ty(local_def(item.id)), sp); + } + + item_enum(ref enum_definition, _) => { + let (name_bindings, new_parent) = + self.add_child(ident, parent, ForbidDuplicateTypes, sp); + + name_bindings.define_type + (privacy, def_ty(local_def(item.id)), sp); + + for (*enum_definition).variants.each |variant| { + self.build_reduced_graph_for_variant(variant, + local_def(item.id), + // inherited => privacy of the enum item + variant_visibility_to_privacy(variant.node.vis, + privacy == Public), + new_parent, + visitor); + } + } + + // These items live in both the type and value namespaces. + item_struct(struct_def, _) => { + let (name_bindings, new_parent) = + self.add_child(ident, parent, ForbidDuplicateTypes, sp); + + name_bindings.define_type( + privacy, def_ty(local_def(item.id)), sp); + + // If this struct is tuple-like or enum-like, define a name + // in the value namespace. + match struct_def.ctor_id { + None => {} + Some(ctor_id) => { + name_bindings.define_value( + privacy, + def_struct(local_def(ctor_id)), + sp); + } + } + + // Record the def ID of this struct. + self.structs.insert(local_def(item.id)); + + visit_item(item, new_parent, visitor); + } + + item_impl(_, trait_ref_opt, ty, ref methods) => { + // If this implements an anonymous trait and it has static + // methods, then add all the static methods within to a new + // module, if the type was defined within this module. + // + // FIXME (#3785): This is quite unsatisfactory. Perhaps we + // should modify anonymous traits to only be implementable in + // the same module that declared the type. + + // Bail out early if there are no static methods. + let mut has_static_methods = false; + for methods.each |method| { + match method.self_ty.node { + sty_static => has_static_methods = true, + _ => {} + } + } + + // If there are static methods, then create the module + // and add them. + match (trait_ref_opt, ty) { + (None, @Ty { node: ty_path(path, _), _ }) if + has_static_methods && path.idents.len() == 1 => { + // Create the module. + let name = path_to_ident(path); + let (name_bindings, new_parent) = + self.add_child(name, + parent, + ForbidDuplicateModules, + sp); + + let parent_link = self.get_parent_link(new_parent, + ident); + let def_id = local_def(item.id); + name_bindings.define_module(Public, + parent_link, + Some(def_id), + TraitModuleKind, + sp); + + let new_parent = ModuleReducedGraphParent( + name_bindings.get_module()); + + // For each static method... + for methods.each |method| { + match method.self_ty.node { + sty_static => { + // Add the static method to the + // module. + let ident = method.ident; + let (method_name_bindings, _) = + self.add_child( + ident, + new_parent, + ForbidDuplicateValues, + method.span); + let def = def_fn(local_def(method.id), + method.purity); + method_name_bindings.define_value( + Public, def, method.span); + } + _ => {} + } + } + } + _ => {} + } + + visit_item(item, parent, visitor); + } + + item_trait(_, _, ref methods) => { + let (name_bindings, new_parent) = + self.add_child(ident, parent, ForbidDuplicateTypes, sp); + + // If the trait has static methods, then add all the static + // methods within to a new module. + // + // We only need to create the module if the trait has static + // methods, so check that first. + let mut has_static_methods = false; + for (*methods).each |method| { + let ty_m = trait_method_to_ty_method(method); + match ty_m.self_ty.node { + sty_static => { + has_static_methods = true; + break; + } + _ => {} + } + } + + // Create the module if necessary. + let module_parent_opt; + if has_static_methods { + let parent_link = self.get_parent_link(parent, ident); + name_bindings.define_module(privacy, + parent_link, + Some(local_def(item.id)), + TraitModuleKind, + sp); + module_parent_opt = Some(ModuleReducedGraphParent( + name_bindings.get_module())); + } else { + module_parent_opt = None; + } + + // Add the names of all the methods to the trait info. + let mut method_names = HashSet::new(); + for methods.each |method| { + let ty_m = trait_method_to_ty_method(method); + + let ident = ty_m.ident; + // Add it to the trait info if not static, + // add it as a name in the trait module otherwise. + match ty_m.self_ty.node { + sty_static => { + let def = def_static_method( + local_def(ty_m.id), + Some(local_def(item.id)), + ty_m.purity); + + let (method_name_bindings, _) = + self.add_child(ident, + module_parent_opt.get(), + ForbidDuplicateValues, + ty_m.span); + method_name_bindings.define_value(Public, + def, + ty_m.span); + } + _ => { + method_names.insert(ident); + } + } + } + + let def_id = local_def(item.id); + self.trait_info.insert(def_id, method_names); + + name_bindings.define_type(privacy, def_trait(def_id), sp); + visit_item(item, new_parent, visitor); + } + + item_mac(*) => { + fail!(~"item macros unimplemented") + } + } + } + + // Constructs the reduced graph for one variant. Variants exist in the + // type and/or value namespaces. + fn build_reduced_graph_for_variant(@mut self, + variant: &variant, + item_id: def_id, + parent_privacy: Privacy, + parent: ReducedGraphParent, + _visitor: vt) { + let ident = variant.node.name; + let (child, _) = self.add_child(ident, parent, ForbidDuplicateValues, + variant.span); + + let privacy; + match variant.node.vis { + public => privacy = Public, + private => privacy = Private, + inherited => privacy = parent_privacy + } + + match variant.node.kind { + tuple_variant_kind(_) => { + child.define_value(privacy, + def_variant(item_id, + local_def(variant.node.id)), + variant.span); + } + struct_variant_kind(_) => { + child.define_type(privacy, + def_variant(item_id, + local_def(variant.node.id)), + variant.span); + self.structs.insert(local_def(variant.node.id)); + } + } + } + + /** + * Constructs the reduced graph for one 'view item'. View items consist + * of imports and use directives. + */ + fn build_reduced_graph_for_view_item(@mut self, + view_item: @view_item, + parent: ReducedGraphParent, + _visitor: vt) { + let privacy = visibility_to_privacy(view_item.vis); + match view_item.node { + view_item_use(ref view_paths) => { + for view_paths.each |view_path| { + // Extract and intern the module part of the path. For + // globs and lists, the path is found directly in the AST; + // for simple paths we have to munge the path a little. + + let mut module_path = ~[]; + match view_path.node { + view_path_simple(_, full_path, _) => { + let path_len = full_path.idents.len(); + assert!(path_len != 0); + + for full_path.idents.eachi |i, ident| { + if i != path_len - 1 { + module_path.push(*ident); + } + } + } + + view_path_glob(module_ident_path, _) | + view_path_list(module_ident_path, _, _) => { + for module_ident_path.idents.each |ident| { + module_path.push(*ident); + } + } + } + + // Build up the import directives. + let module_ = self.get_module_from_parent(parent); + match view_path.node { + view_path_simple(binding, full_path, _) => { + let source_ident = *full_path.idents.last(); + let subclass = @SingleImport(binding, + source_ident); + self.build_import_directive(privacy, + module_, + module_path, + subclass, + view_path.span); + } + view_path_list(_, ref source_idents, _) => { + for source_idents.each |source_ident| { + let name = source_ident.node.name; + let subclass = @SingleImport(name, name); + self.build_import_directive(privacy, + module_, + copy module_path, + subclass, + source_ident.span); + } + } + view_path_glob(_, _) => { + self.build_import_directive(privacy, + module_, + module_path, + @GlobImport, + view_path.span); + } + } + } + } + + view_item_extern_mod(name, _, node_id) => { + match find_extern_mod_stmt_cnum(self.session.cstore, + node_id) { + Some(crate_id) => { + let def_id = def_id { crate: crate_id, node: 0 }; + let parent_link = ModuleParentLink + (self.get_module_from_parent(parent), name); + let external_module = @mut Module(parent_link, + Some(def_id), + NormalModuleKind); + + parent.external_module_children.insert( + name, + external_module); + + self.build_reduced_graph_for_external_crate( + external_module); + } + None => {} // Ignore. + } + } + } + } + + /// Constructs the reduced graph for one foreign item. + fn build_reduced_graph_for_foreign_item(@mut self, + foreign_item: @foreign_item, + parent: ReducedGraphParent, + visitor: + vt) { + let name = foreign_item.ident; + let (name_bindings, new_parent) = + self.add_child(name, parent, ForbidDuplicateValues, + foreign_item.span); + + match foreign_item.node { + foreign_item_fn(_, _, ref generics) => { + let def = def_fn(local_def(foreign_item.id), unsafe_fn); + name_bindings.define_value(Public, def, foreign_item.span); + + do self.with_type_parameter_rib( + HasTypeParameters( + generics, foreign_item.id, 0, NormalRibKind)) + { + visit_foreign_item(foreign_item, new_parent, visitor); + } + } + foreign_item_const(*) => { + let def = def_const(local_def(foreign_item.id)); + name_bindings.define_value(Public, def, foreign_item.span); + + visit_foreign_item(foreign_item, new_parent, visitor); + } + } + } + + fn build_reduced_graph_for_block(@mut self, + block: &blk, + parent: ReducedGraphParent, + visitor: vt) { + let new_parent; + if self.block_needs_anonymous_module(block) { + let block_id = block.node.id; + + debug!("(building reduced graph for block) creating a new \ + anonymous module for block %d", + block_id); + + let parent_module = self.get_module_from_parent(parent); + let new_module = @mut Module( + BlockParentLink(parent_module, block_id), + None, + AnonymousModuleKind); + parent_module.anonymous_children.insert(block_id, new_module); + new_parent = ModuleReducedGraphParent(new_module); + } else { + new_parent = parent; + } + + visit_block(block, new_parent, visitor); + } + + fn handle_external_def(@mut self, + def: def, + modules: &mut HashMap, + child_name_bindings: @mut NameBindings, + final_ident: &str, + ident: ident, + new_parent: ReducedGraphParent) { + match def { + def_mod(def_id) | def_foreign_mod(def_id) => { + match child_name_bindings.type_def { + Some(TypeNsDef { module_def: Some(copy module_def), _ }) => { + debug!("(building reduced graph for external crate) \ + already created module"); + module_def.def_id = Some(def_id); + modules.insert(def_id, module_def); + } + Some(_) | None => { + debug!("(building reduced graph for \ + external crate) building module \ + %s", final_ident); + let parent_link = self.get_parent_link(new_parent, ident); + + // FIXME (#5074): this should be a match on find + if !modules.contains_key(&def_id) { + child_name_bindings.define_module(Public, + parent_link, + Some(def_id), + NormalModuleKind, + dummy_sp()); + modules.insert(def_id, + child_name_bindings.get_module()); + } else { + let existing_module = *modules.get(&def_id); + // Create an import resolution to + // avoid creating cycles in the + // module graph. + + let resolution = + @mut ImportResolution(Public, + dummy_sp(), + @mut ImportState()); + resolution.outstanding_references = 0; + + match existing_module.parent_link { + NoParentLink | + BlockParentLink(*) => { + fail!(~"can't happen"); + } + ModuleParentLink(parent_module, ident) => { + let name_bindings = parent_module.children.get( + &ident); + resolution.type_target = + Some(Target(parent_module, *name_bindings)); + } + } + + debug!("(building reduced graph for external crate) \ + ... creating import resolution"); + + new_parent.import_resolutions.insert(ident, resolution); + } + } + } + } + def_fn(*) | def_static_method(*) | def_const(*) | + def_variant(*) => { + debug!("(building reduced graph for external \ + crate) building value %s", final_ident); + child_name_bindings.define_value(Public, def, dummy_sp()); + } + def_trait(def_id) => { + debug!("(building reduced graph for external \ + crate) building type %s", final_ident); + + // If this is a trait, add all the method names + // to the trait info. + + let method_def_ids = get_trait_method_def_ids(self.session.cstore, + def_id); + let mut interned_method_names = HashSet::new(); + for method_def_ids.each |&method_def_id| { + let (method_name, self_ty) = + get_method_name_and_self_ty(self.session.cstore, + method_def_id); + + debug!("(building reduced graph for \ + external crate) ... adding \ + trait method '%s'", + *self.session.str_of(method_name)); + + // Add it to the trait info if not static. + if self_ty != sty_static { + interned_method_names.insert(method_name); + } + } + self.trait_info.insert(def_id, interned_method_names); + + child_name_bindings.define_type(Public, def, dummy_sp()); + } + def_ty(_) => { + debug!("(building reduced graph for external \ + crate) building type %s", final_ident); + + child_name_bindings.define_type(Public, def, dummy_sp()); + } + def_struct(def_id) => { + debug!("(building reduced graph for external \ + crate) building type %s", + final_ident); + child_name_bindings.define_type(Public, def, dummy_sp()); + self.structs.insert(def_id); + } + def_self(*) | def_arg(*) | def_local(*) | + def_prim_ty(*) | def_ty_param(*) | def_binding(*) | + def_use(*) | def_upvar(*) | def_region(*) | + def_typaram_binder(*) | def_label(*) | def_self_ty(*) => { + fail!(fmt!("didn't expect `%?`", def)); + } + } + } + + /** + * Builds the reduced graph rooted at the 'use' directive for an external + * crate. + */ + fn build_reduced_graph_for_external_crate(@mut self, root: @mut Module) { + let mut modules = HashMap::new(); + + // Create all the items reachable by paths. + for each_path(self.session.cstore, root.def_id.get().crate) + |path_string, def_like| { + + debug!("(building reduced graph for external crate) found path \ + entry: %s (%?)", + path_string, def_like); + + let mut pieces = ~[]; + for each_split_str(path_string, "::") |s| { pieces.push(s.to_owned()) } + let final_ident_str = pieces.pop(); + let final_ident = self.session.ident_of(final_ident_str); + + // Find the module we need, creating modules along the way if we + // need to. + + let mut current_module = root; + for pieces.each |ident_str| { + let ident = self.session.ident_of(/*bad*/copy *ident_str); + // Create or reuse a graph node for the child. + let (child_name_bindings, new_parent) = + self.add_child(ident, + ModuleReducedGraphParent(current_module), + OverwriteDuplicates, + dummy_sp()); + + // Define or reuse the module node. + match child_name_bindings.type_def { + None => { + debug!("(building reduced graph for external crate) \ + autovivifying missing type def %s", + *ident_str); + let parent_link = self.get_parent_link(new_parent, + ident); + child_name_bindings.define_module(Public, + parent_link, + None, + NormalModuleKind, + dummy_sp()); + } + Some(copy type_ns_def) + if type_ns_def.module_def.is_none() => { + debug!("(building reduced graph for external crate) \ + autovivifying missing module def %s", + *ident_str); + let parent_link = self.get_parent_link(new_parent, + ident); + child_name_bindings.define_module(Public, + parent_link, + None, + NormalModuleKind, + dummy_sp()); + } + _ => {} // Fall through. + } + + current_module = child_name_bindings.get_module(); + } + + match def_like { + dl_def(def) => { + // Add the new child item. + let (child_name_bindings, new_parent) = + self.add_child(final_ident, + ModuleReducedGraphParent( + current_module), + OverwriteDuplicates, + dummy_sp()); + + self.handle_external_def(def, + &mut modules, + child_name_bindings, + *self.session.str_of( + final_ident), + final_ident, + new_parent); + } + dl_impl(def) => { + // We only process static methods of impls here. + match get_type_name_if_impl(self.session.cstore, def) { + None => {} + Some(final_ident) => { + let static_methods_opt = + get_static_methods_if_impl( + self.session.cstore, def); + match static_methods_opt { + Some(ref static_methods) if + static_methods.len() >= 1 => { + debug!("(building reduced graph for \ + external crate) processing \ + static methods for type name %s", + *self.session.str_of( + final_ident)); + + let (child_name_bindings, new_parent) = + self.add_child(final_ident, + ModuleReducedGraphParent( + current_module), + OverwriteDuplicates, + dummy_sp()); + + // Process the static methods. First, + // create the module. + let type_module; + match child_name_bindings.type_def { + Some(TypeNsDef { + module_def: Some(copy module_def), + _ + }) => { + // We already have a module. This + // is OK. + type_module = module_def; + } + Some(_) | None => { + let parent_link = + self.get_parent_link( + new_parent, final_ident); + child_name_bindings.define_module( + Public, + parent_link, + Some(def), + NormalModuleKind, + dummy_sp()); + type_module = + child_name_bindings. + get_module(); + } + } + + // Add each static method to the module. + let new_parent = ModuleReducedGraphParent( + type_module); + for static_methods.each + |static_method_info| { + let ident = static_method_info.ident; + debug!("(building reduced graph for \ + external crate) creating \ + static method '%s'", + *self.session.str_of(ident)); + + let (method_name_bindings, _) = + self.add_child( + ident, + new_parent, + OverwriteDuplicates, + dummy_sp()); + let def = def_fn( + static_method_info.def_id, + static_method_info.purity); + method_name_bindings.define_value( + Public, def, dummy_sp()); + } + } + + // Otherwise, do nothing. + Some(_) | None => {} + } + } + } + } + dl_field => { + debug!("(building reduced graph for external crate) \ + ignoring field"); + } + } + } + } + + /// Creates and adds an import directive to the given module. + fn build_import_directive(@mut self, + privacy: Privacy, + module_: @mut Module, + module_path: ~[ident], + subclass: @ImportDirectiveSubclass, + span: span) { + let directive = @ImportDirective(privacy, module_path, + subclass, span); + module_.imports.push(directive); + + // Bump the reference count on the name. Or, if this is a glob, set + // the appropriate flag. + + match *subclass { + SingleImport(target, _) => { + debug!("(building import directive) building import \ + directive: privacy %? %s::%s", + privacy, + self.idents_to_str(directive.module_path), + *self.session.str_of(target)); + + match module_.import_resolutions.find(&target) { + Some(&resolution) => { + debug!("(building import directive) bumping \ + reference"); + resolution.outstanding_references += 1; + } + None => { + debug!("(building import directive) creating new"); + let state = @mut ImportState(); + let resolution = @mut ImportResolution(privacy, + span, + state); + let name = self.idents_to_str(directive.module_path); + // Don't warn about unused intrinsics because they're + // automatically appended to all files + if name == ~"intrinsic::rusti" { + resolution.state.warned = true; + } + resolution.outstanding_references = 1; + module_.import_resolutions.insert(target, resolution); + } + } + } + GlobImport => { + // Set the glob flag. This tells us that we don't know the + // module's exports ahead of time. + + module_.glob_count += 1; + } + } + + self.unresolved_imports += 1; + } + + // Import resolution + // + // This is a fixed-point algorithm. We resolve imports until our efforts + // are stymied by an unresolved import; then we bail out of the current + // module and continue. We terminate successfully once no more imports + // remain or unsuccessfully when no forward progress in resolving imports + // is made. + + /** + * Resolves all imports for the crate. This method performs the fixed- + * point iteration. + */ + fn resolve_imports(@mut self) { + let mut i = 0; + let mut prev_unresolved_imports = 0; + loop { + debug!("(resolving imports) iteration %u, %u imports left", + i, self.unresolved_imports); + + let module_root = self.graph_root.get_module(); + self.resolve_imports_for_module_subtree(module_root); + + if self.unresolved_imports == 0 { + debug!("(resolving imports) success"); + break; + } + + if self.unresolved_imports == prev_unresolved_imports { + self.session.err(~"failed to resolve imports"); + self.report_unresolved_imports(module_root); + break; + } + + i += 1; + prev_unresolved_imports = self.unresolved_imports; + } + } + + /// Attempts to resolve imports for the given module and all of its + /// submodules. + fn resolve_imports_for_module_subtree(@mut self, module_: @mut Module) { + debug!("(resolving imports for module subtree) resolving %s", + self.module_to_str(module_)); + self.resolve_imports_for_module(module_); + + for module_.children.each_value |&child_node| { + match child_node.get_module_if_available() { + None => { + // Nothing to do. + } + Some(child_module) => { + self.resolve_imports_for_module_subtree(child_module); + } + } + } + + for module_.anonymous_children.each_value |&child_module| { + self.resolve_imports_for_module_subtree(child_module); + } + } + + /// Attempts to resolve imports for the given module only. + fn resolve_imports_for_module(@mut self, module: @mut Module) { + if module.all_imports_resolved() { + debug!("(resolving imports for module) all imports resolved for \ + %s", + self.module_to_str(module)); + return; + } + + let imports = &mut *module.imports; + let import_count = imports.len(); + while module.resolved_import_count < import_count { + let import_index = module.resolved_import_count; + let import_directive = imports[import_index]; + match self.resolve_import_for_module(module, import_directive) { + Failed => { + // We presumably emitted an error. Continue. + let msg = fmt!("failed to resolve import: %s", + *self.import_path_to_str( + import_directive.module_path, + *import_directive.subclass)); + self.session.span_err(import_directive.span, msg); + } + Indeterminate => { + // Bail out. We'll come around next time. + break; + } + Success(()) => { + // Good. Continue. + } + } + + module.resolved_import_count += 1; + } + } + + fn idents_to_str(@mut self, idents: &[ident]) -> ~str { + let mut first = true; + let mut result = ~""; + for idents.each |ident| { + if first { first = false; } else { result += "::" }; + result += *self.session.str_of(*ident); + }; + return result; + } + + fn import_directive_subclass_to_str(@mut self, + subclass: ImportDirectiveSubclass) + -> @~str { + match subclass { + SingleImport(_target, source) => self.session.str_of(source), + GlobImport => @~"*" + } + } + + fn import_path_to_str(@mut self, + idents: &[ident], + subclass: ImportDirectiveSubclass) + -> @~str { + if idents.is_empty() { + self.import_directive_subclass_to_str(subclass) + } else { + @fmt!("%s::%s", + self.idents_to_str(idents), + *self.import_directive_subclass_to_str(subclass)) + } + } + + /// Attempts to resolve the given import. The return value indicates + /// failure if we're certain the name does not exist, indeterminate if we + /// don't know whether the name exists at the moment due to other + /// currently-unresolved imports, or success if we know the name exists. + /// If successful, the resolved bindings are written into the module. + fn resolve_import_for_module(@mut self, module_: @mut Module, + import_directive: @ImportDirective) + -> ResolveResult<()> { + let mut resolution_result = Failed; + let module_path = &import_directive.module_path; + + debug!("(resolving import for module) resolving import `%s::...` in \ + `%s`", + self.idents_to_str(*module_path), + self.module_to_str(module_)); + + // First, resolve the module path for the directive, if necessary. + let containing_module = if module_path.len() == 0 { + // Use the crate root. + Some(self.graph_root.get_module()) + } else { + match self.resolve_module_path_for_import(module_, + *module_path, + DontUseLexicalScope, + import_directive.span) { + + Failed => None, + Indeterminate => { + resolution_result = Indeterminate; + None + } + Success(containing_module) => Some(containing_module), + } + }; + + match containing_module { + None => {} + Some(containing_module) => { + // We found the module that the target is contained + // within. Attempt to resolve the import within it. + + match *import_directive.subclass { + SingleImport(target, source) => { + resolution_result = + self.resolve_single_import(module_, + containing_module, + target, + source); + } + GlobImport => { + let span = import_directive.span; + let privacy = import_directive.privacy; + resolution_result = + self.resolve_glob_import(privacy, + module_, + containing_module, + span); + } + } + } + } + + // Decrement the count of unresolved imports. + match resolution_result { + Success(()) => { + assert!(self.unresolved_imports >= 1); + self.unresolved_imports -= 1; + } + _ => { + // Nothing to do here; just return the error. + } + } + + // Decrement the count of unresolved globs if necessary. But only if + // the resolution result is indeterminate -- otherwise we'll stop + // processing imports here. (See the loop in + // resolve_imports_for_module.) + + if !resolution_result.indeterminate() { + match *import_directive.subclass { + GlobImport => { + assert!(module_.glob_count >= 1); + module_.glob_count -= 1; + } + SingleImport(*) => { + // Ignore. + } + } + } + + return resolution_result; + } + + fn create_name_bindings_from_module(module: @mut Module) -> NameBindings { + NameBindings { + type_def: Some(TypeNsDef { + privacy: Public, + module_def: Some(module), + type_def: None, + }), + value_def: None, + type_span: None, + value_span: None, + } + } + + fn resolve_single_import(@mut self, + module_: @mut Module, + containing_module: @mut Module, + target: ident, + source: ident) + -> ResolveResult<()> { + debug!("(resolving single import) resolving `%s` = `%s::%s` from \ + `%s`", + *self.session.str_of(target), + self.module_to_str(containing_module), + *self.session.str_of(source), + self.module_to_str(module_)); + + // We need to resolve both namespaces for this to succeed. + // + // FIXME #4949: See if there's some way of handling namespaces in + // a more generic way. We have two of them; it seems worth + // doing... + + let mut value_result = UnknownResult; + let mut type_result = UnknownResult; + + // Search for direct children of the containing module. + match containing_module.children.find(&source) { + None => { + // Continue. + } + Some(child_name_bindings) => { + if child_name_bindings.defined_in_namespace(ValueNS) { + value_result = BoundResult(containing_module, + *child_name_bindings); + } + if child_name_bindings.defined_in_namespace(TypeNS) { + type_result = BoundResult(containing_module, + *child_name_bindings); + } + } + } + + // Unless we managed to find a result in both namespaces (unlikely), + // search imports as well. + match (value_result, type_result) { + (BoundResult(*), BoundResult(*)) => { + // Continue. + } + _ => { + // If there is an unresolved glob at this point in the + // containing module, bail out. We don't know enough to be + // able to resolve this import. + + if containing_module.glob_count > 0 { + debug!("(resolving single import) unresolved glob; \ + bailing out"); + return Indeterminate; + } + + // Now search the exported imports within the containing + // module. + + match containing_module.import_resolutions.find(&source) { + None => { + // The containing module definitely doesn't have an + // exported import with the name in question. We can + // therefore accurately report that the names are + // unbound. + + if value_result.is_unknown() { + value_result = UnboundResult; + } + if type_result.is_unknown() { + type_result = UnboundResult; + } + } + Some(import_resolution) + if import_resolution.outstanding_references + == 0 => { + + fn get_binding(import_resolution: + @mut ImportResolution, + namespace: Namespace) + -> NamespaceResult { + + // Import resolutions must be declared with "pub" + // in order to be exported. + if import_resolution.privacy == Private { + return UnboundResult; + } + + match (*import_resolution). + target_for_namespace(namespace) { + None => { + return UnboundResult; + } + Some(target) => { + import_resolution.state.used = true; + return BoundResult(target.target_module, + target.bindings); + } + } + } + + // The name is an import which has been fully + // resolved. We can, therefore, just follow it. + if value_result.is_unknown() { + value_result = get_binding(*import_resolution, + ValueNS); + } + if type_result.is_unknown() { + type_result = get_binding(*import_resolution, + TypeNS); + } + } + Some(_) => { + // The import is unresolved. Bail out. + debug!("(resolving single import) unresolved import; \ + bailing out"); + return Indeterminate; + } + } + } + } + + // If we didn't find a result in the type namespace, search the + // external modules. + match type_result { + BoundResult(*) => {} + _ => { + match containing_module.external_module_children + .find(&source) { + None => {} // Continue. + Some(module) => { + let name_bindings = + @mut Resolver::create_name_bindings_from_module( + *module); + type_result = BoundResult(containing_module, + name_bindings); + } + } + } + } + + // We've successfully resolved the import. Write the results in. + assert!(module_.import_resolutions.contains_key(&target)); + let import_resolution = module_.import_resolutions.get(&target); + + match value_result { + BoundResult(target_module, name_bindings) => { + import_resolution.value_target = + Some(Target(target_module, name_bindings)); + } + UnboundResult => { /* Continue. */ } + UnknownResult => { + fail!(~"value result should be known at this point"); + } + } + match type_result { + BoundResult(target_module, name_bindings) => { + import_resolution.type_target = + Some(Target(target_module, name_bindings)); + } + UnboundResult => { /* Continue. */ } + UnknownResult => { + fail!(~"type result should be known at this point"); + } + } + + let i = import_resolution; + match (i.value_target, i.type_target) { + // If this name wasn't found in either namespace, it's definitely + // unresolved. + (None, None) => { return Failed; } + // If it's private, it's also unresolved. + (Some(t), None) | (None, Some(t)) => { + let bindings = &mut *t.bindings; + match bindings.type_def { + Some(ref type_def) => { + if type_def.privacy == Private { + return Failed; + } + } + _ => () + } + match bindings.value_def { + Some(ref value_def) => { + if value_def.privacy == Private { + return Failed; + } + } + _ => () + } + } + // It's also an error if there's both a type and a value with this + // name, but both are private + (Some(val), Some(ty)) => { + match (val.bindings.value_def, ty.bindings.value_def) { + (Some(ref value_def), Some(ref type_def)) => + if value_def.privacy == Private + && type_def.privacy == Private { + return Failed; + }, + _ => () + } + } + } + + assert!(import_resolution.outstanding_references >= 1); + import_resolution.outstanding_references -= 1; + + debug!("(resolving single import) successfully resolved import"); + return Success(()); + } + + // Resolves a glob import. Note that this function cannot fail; it either + // succeeds or bails out (as importing * from an empty module or a module + // that exports nothing is valid). + fn resolve_glob_import(@mut self, + privacy: Privacy, + module_: @mut Module, + containing_module: @mut Module, + span: span) + -> ResolveResult<()> { + // This function works in a highly imperative manner; it eagerly adds + // everything it can to the list of import resolutions of the module + // node. + debug!("(resolving glob import) resolving %? glob import", privacy); + let state = @mut ImportState(); + + // We must bail out if the node has unresolved imports of any kind + // (including globs). + if !(*containing_module).all_imports_resolved() { + debug!("(resolving glob import) target module has unresolved \ + imports; bailing out"); + return Indeterminate; + } + + assert!(containing_module.glob_count == 0); + + // Add all resolved imports from the containing module. + for containing_module.import_resolutions.each + |ident, target_import_resolution| { + + debug!("(resolving glob import) writing module resolution \ + %? into `%s`", + target_import_resolution.type_target.is_none(), + self.module_to_str(module_)); + + // Here we merge two import resolutions. + match module_.import_resolutions.find(ident) { + None if target_import_resolution.privacy == Public => { + // Simple: just copy the old import resolution. + let new_import_resolution = + @mut ImportResolution(privacy, + target_import_resolution.span, + state); + new_import_resolution.value_target = + copy target_import_resolution.value_target; + new_import_resolution.type_target = + copy target_import_resolution.type_target; + + module_.import_resolutions.insert + (*ident, new_import_resolution); + } + None => { /* continue ... */ } + Some(&dest_import_resolution) => { + // Merge the two import resolutions at a finer-grained + // level. + + match target_import_resolution.value_target { + None => { + // Continue. + } + Some(copy value_target) => { + dest_import_resolution.value_target = + Some(value_target); + } + } + match target_import_resolution.type_target { + None => { + // Continue. + } + Some(copy type_target) => { + dest_import_resolution.type_target = + Some(type_target); + } + } + } + } + } + + let merge_import_resolution = |ident, + name_bindings: @mut NameBindings| { + let dest_import_resolution; + match module_.import_resolutions.find(ident) { + None => { + // Create a new import resolution from this child. + dest_import_resolution = @mut ImportResolution(privacy, + span, + state); + module_.import_resolutions.insert + (*ident, dest_import_resolution); + } + Some(&existing_import_resolution) => { + dest_import_resolution = existing_import_resolution; + } + } + + debug!("(resolving glob import) writing resolution `%s` in `%s` \ + to `%s`, privacy=%?", + *self.session.str_of(*ident), + self.module_to_str(containing_module), + self.module_to_str(module_), + copy dest_import_resolution.privacy); + + // Merge the child item into the import resolution. + if name_bindings.defined_in_public_namespace(ValueNS) { + debug!("(resolving glob import) ... for value target"); + dest_import_resolution.value_target = + Some(Target(containing_module, name_bindings)); + } + if name_bindings.defined_in_public_namespace(TypeNS) { + debug!("(resolving glob import) ... for type target"); + dest_import_resolution.type_target = + Some(Target(containing_module, name_bindings)); + } + }; + + // Add all children from the containing module. + for containing_module.children.each |ident, name_bindings| { + merge_import_resolution(ident, *name_bindings); + } + + // Add external module children from the containing module. + for containing_module.external_module_children.each + |ident, module| { + let name_bindings = + @mut Resolver::create_name_bindings_from_module(*module); + merge_import_resolution(ident, name_bindings); + } + + debug!("(resolving glob import) successfully resolved import"); + return Success(()); + } + + /// Resolves the given module path from the given root `module_`. + fn resolve_module_path_from_root(@mut self, + module_: @mut Module, + module_path: &[ident], + index: uint, + span: span, + mut name_search_type: NameSearchType) + -> ResolveResult<@mut Module> { + let mut search_module = module_; + let mut index = index; + let module_path_len = module_path.len(); + + // Resolve the module part of the path. This does not involve looking + // upward though scope chains; we simply resolve names directly in + // modules as we go. + + while index < module_path_len { + let name = module_path[index]; + match self.resolve_name_in_module(search_module, + name, + TypeNS, + name_search_type) { + Failed => { + self.session.span_err(span, ~"unresolved name"); + return Failed; + } + Indeterminate => { + debug!("(resolving module path for import) module \ + resolution is indeterminate: %s", + *self.session.str_of(name)); + return Indeterminate; + } + Success(target) => { + // Check to see whether there are type bindings, and, if + // so, whether there is a module within. + match target.bindings.type_def { + Some(copy type_def) => { + match type_def.module_def { + None => { + // Not a module. + self.session.span_err(span, + fmt!("not a \ + module: %s", + *self.session. + str_of( + name))); + return Failed; + } + Some(copy module_def) => { + search_module = module_def; + } + } + } + None => { + // There are no type bindings at all. + self.session.span_err(span, + fmt!("not a module: %s", + *self.session.str_of( + name))); + return Failed; + } + } + } + } + + index += 1; + + // After the first element of the path, allow searching through + // items and imports unconditionally. This allows things like: + // + // pub mod core { + // pub use vec; + // } + // + // pub mod something_else { + // use core::vec; + // } + + name_search_type = SearchItemsAndPublicImports; + } + + return Success(search_module); + } + + /// Attempts to resolve the module part of an import directive or path + /// rooted at the given module. + fn resolve_module_path_for_import(@mut self, + module_: @mut Module, + module_path: &[ident], + use_lexical_scope: UseLexicalScopeFlag, + span: span) + -> ResolveResult<@mut Module> { + let module_path_len = module_path.len(); + assert!(module_path_len > 0); + + debug!("(resolving module path for import) processing `%s` rooted at \ + `%s`", + self.idents_to_str(module_path), + self.module_to_str(module_)); + + // Resolve the module prefix, if any. + let module_prefix_result = self.resolve_module_prefix(module_, + module_path); + + let search_module; + let start_index; + match module_prefix_result { + Failed => { + self.session.span_err(span, ~"unresolved name"); + return Failed; + } + Indeterminate => { + debug!("(resolving module path for import) indeterminate; \ + bailing"); + return Indeterminate; + } + Success(NoPrefixFound) => { + // There was no prefix, so we're considering the first element + // of the path. How we handle this depends on whether we were + // instructed to use lexical scope or not. + match use_lexical_scope { + DontUseLexicalScope => { + // This is a crate-relative path. We will start the + // resolution process at index zero. + search_module = self.graph_root.get_module(); + start_index = 0; + } + UseLexicalScope => { + // This is not a crate-relative path. We resolve the + // first component of the path in the current lexical + // scope and then proceed to resolve below that. + let result = self.resolve_module_in_lexical_scope( + module_, + module_path[0]); + match result { + Failed => { + self.session.span_err(span, + ~"unresolved name"); + return Failed; + } + Indeterminate => { + debug!("(resolving module path for import) \ + indeterminate; bailing"); + return Indeterminate; + } + Success(containing_module) => { + search_module = containing_module; + start_index = 1; + } + } + } + } + } + Success(PrefixFound(containing_module, index)) => { + search_module = containing_module; + start_index = index; + } + } + + self.resolve_module_path_from_root(search_module, + module_path, + start_index, + span, + SearchItemsAndPublicImports) + } + + /// Invariant: This must only be called during main resolution, not during + /// import resolution. + fn resolve_item_in_lexical_scope(@mut self, + module_: @mut Module, + name: ident, + namespace: Namespace, + search_through_modules: + SearchThroughModulesFlag) + -> ResolveResult { + debug!("(resolving item in lexical scope) resolving `%s` in \ + namespace %? in `%s`", + *self.session.str_of(name), + namespace, + self.module_to_str(module_)); + + // The current module node is handled specially. First, check for + // its immediate children. + match module_.children.find(&name) { + Some(name_bindings) + if name_bindings.defined_in_namespace(namespace) => { + return Success(Target(module_, *name_bindings)); + } + Some(_) | None => { /* Not found; continue. */ } + } + + // Now check for its import directives. We don't have to have resolved + // all its imports in the usual way; this is because chains of + // adjacent import statements are processed as though they mutated the + // current scope. + match module_.import_resolutions.find(&name) { + None => { + // Not found; continue. + } + Some(import_resolution) => { + match (*import_resolution).target_for_namespace(namespace) { + None => { + // Not found; continue. + debug!("(resolving item in lexical scope) found \ + import resolution, but not in namespace %?", + namespace); + } + Some(target) => { + debug!("(resolving item in lexical scope) using \ + import resolution"); + import_resolution.state.used = true; + return Success(copy target); + } + } + } + } + + // Search for external modules. + if namespace == TypeNS { + match module_.external_module_children.find(&name) { + None => {} + Some(module) => { + let name_bindings = + @mut Resolver::create_name_bindings_from_module( + *module); + return Success(Target(module_, name_bindings)); + } + } + } + + // Finally, proceed up the scope chain looking for parent modules. + let mut search_module = module_; + loop { + // Go to the next parent. + match search_module.parent_link { + NoParentLink => { + // No more parents. This module was unresolved. + debug!("(resolving item in lexical scope) unresolved \ + module"); + return Failed; + } + ModuleParentLink(parent_module_node, _) => { + match search_through_modules { + DontSearchThroughModules => { + match search_module.kind { + NormalModuleKind => { + // We stop the search here. + debug!("(resolving item in lexical \ + scope) unresolved module: not \ + searching through module \ + parents"); + return Failed; + } + ExternModuleKind | + TraitModuleKind | + AnonymousModuleKind => { + search_module = parent_module_node; + } + } + } + SearchThroughModules => { + search_module = parent_module_node; + } + } + } + BlockParentLink(parent_module_node, _) => { + search_module = parent_module_node; + } + } + + // Resolve the name in the parent module. + match self.resolve_name_in_module(search_module, + name, + namespace, + SearchItemsAndAllImports) { + Failed => { + // Continue up the search chain. + } + Indeterminate => { + // We couldn't see through the higher scope because of an + // unresolved import higher up. Bail. + + debug!("(resolving item in lexical scope) indeterminate \ + higher scope; bailing"); + return Indeterminate; + } + Success(target) => { + // We found the module. + return Success(copy target); + } + } + } + } + + /** Resolves a module name in the current lexical scope. */ + fn resolve_module_in_lexical_scope(@mut self, + module_: @mut Module, + name: ident) + -> ResolveResult<@mut Module> { + // If this module is an anonymous module, resolve the item in the + // lexical scope. Otherwise, resolve the item from the crate root. + let resolve_result = self.resolve_item_in_lexical_scope( + module_, name, TypeNS, DontSearchThroughModules); + match resolve_result { + Success(target) => { + let bindings = &mut *target.bindings; + match bindings.type_def { + Some(ref type_def) => { + match (*type_def).module_def { + None => { + error!("!!! (resolving module in lexical \ + scope) module wasn't actually a \ + module!"); + return Failed; + } + Some(module_def) => { + return Success(module_def); + } + } + } + None => { + error!("!!! (resolving module in lexical scope) module + wasn't actually a module!"); + return Failed; + } + } + } + Indeterminate => { + debug!("(resolving module in lexical scope) indeterminate; \ + bailing"); + return Indeterminate; + } + Failed => { + debug!("(resolving module in lexical scope) failed to \ + resolve"); + return Failed; + } + } + } + + /** + * Returns the nearest normal module parent of the given module. + */ + fn get_nearest_normal_module_parent(@mut self, module_: @mut Module) + -> Option<@mut Module> { + let mut module_ = module_; + loop { + match module_.parent_link { + NoParentLink => return None, + ModuleParentLink(new_module, _) | + BlockParentLink(new_module, _) => { + match new_module.kind { + NormalModuleKind => return Some(new_module), + ExternModuleKind | + TraitModuleKind | + AnonymousModuleKind => module_ = new_module, + } + } + } + } + } + + /** + * Returns the nearest normal module parent of the given module, or the + * module itself if it is a normal module. + */ + fn get_nearest_normal_module_parent_or_self(@mut self, + module_: @mut Module) + -> @mut Module { + match module_.kind { + NormalModuleKind => return module_, + ExternModuleKind | TraitModuleKind | AnonymousModuleKind => { + match self.get_nearest_normal_module_parent(module_) { + None => module_, + Some(new_module) => new_module + } + } + } + } + + /** + * Resolves a "module prefix". A module prefix is one of (a) `self::`; + * (b) some chain of `super::`. + */ + fn resolve_module_prefix(@mut self, + module_: @mut Module, + module_path: &[ident]) + -> ResolveResult { + let interner = self.session.parse_sess.interner; + + // Start at the current module if we see `self` or `super`, or at the + // top of the crate otherwise. + let mut containing_module; + let mut i; + if *interner.get(module_path[0]) == ~"self" { + containing_module = + self.get_nearest_normal_module_parent_or_self(module_); + i = 1; + } else if *interner.get(module_path[0]) == ~"super" { + containing_module = + self.get_nearest_normal_module_parent_or_self(module_); + i = 0; // We'll handle `super` below. + } else { + return Success(NoPrefixFound); + } + + // Now loop through all the `super`s we find. + while i < module_path.len() && + *interner.get(module_path[i]) == ~"super" { + debug!("(resolving module prefix) resolving `super` at %s", + self.module_to_str(containing_module)); + match self.get_nearest_normal_module_parent(containing_module) { + None => return Failed, + Some(new_module) => { + containing_module = new_module; + i += 1; + } + } + } + + debug!("(resolving module prefix) finished resolving prefix at %s", + self.module_to_str(containing_module)); + + return Success(PrefixFound(containing_module, i)); + } + + /// Attempts to resolve the supplied name in the given module for the + /// given namespace. If successful, returns the target corresponding to + /// the name. + fn resolve_name_in_module(@mut self, + module_: @mut Module, + name: ident, + namespace: Namespace, + name_search_type: NameSearchType) + -> ResolveResult { + debug!("(resolving name in module) resolving `%s` in `%s`", + *self.session.str_of(name), + self.module_to_str(module_)); + + // First, check the direct children of the module. + match module_.children.find(&name) { + Some(name_bindings) + if name_bindings.defined_in_namespace(namespace) => { + debug!("(resolving name in module) found node as child"); + return Success(Target(module_, *name_bindings)); + } + Some(_) | None => { + // Continue. + } + } + + // Next, check the module's imports if necessary. + + // If this is a search of all imports, we should be done with glob + // resolution at this point. + if name_search_type == SearchItemsAndAllImports { + assert!(module_.glob_count == 0); + } + + // Check the list of resolved imports. + match module_.import_resolutions.find(&name) { + Some(import_resolution) => { + if import_resolution.privacy == Public && + import_resolution.outstanding_references != 0 { + debug!("(resolving name in module) import \ + unresolved; bailing out"); + return Indeterminate; + } + + match import_resolution.target_for_namespace(namespace) { + None => { + debug!("(resolving name in module) name found, \ + but not in namespace %?", + namespace); + } + Some(target) + if name_search_type == + SearchItemsAndAllImports || + import_resolution.privacy == Public => { + debug!("(resolving name in module) resolved to \ + import"); + import_resolution.state.used = true; + return Success(copy target); + } + Some(_) => { + debug!("(resolving name in module) name found, \ + but not public"); + } + } + } + None => {} // Continue. + } + + // Finally, search through external children. + if namespace == TypeNS { + match module_.external_module_children.find(&name) { + None => {} + Some(module) => { + let name_bindings = + @mut Resolver::create_name_bindings_from_module( + *module); + return Success(Target(module_, name_bindings)); + } + } + } + + // We're out of luck. + debug!("(resolving name in module) failed to resolve %s", + *self.session.str_of(name)); + return Failed; + } + + fn report_unresolved_imports(@mut self, module_: @mut Module) { + let index = module_.resolved_import_count; + let imports: &mut ~[@ImportDirective] = &mut *module_.imports; + let import_count = imports.len(); + if index != import_count { + let sn = self.session.codemap.span_to_snippet(imports[index].span); + if str::contains(sn, "::") { + self.session.span_err(imports[index].span, ~"unresolved import"); + } else { + let err = fmt!("unresolved import (maybe you meant `%s::*`?)", + sn.slice(0, sn.len() - 1)); // -1 to adjust for semicolon + self.session.span_err(imports[index].span, err); + } + } + + // Descend into children and anonymous children. + for module_.children.each_value |&child_node| { + match child_node.get_module_if_available() { + None => { + // Continue. + } + Some(child_module) => { + self.report_unresolved_imports(child_module); + } + } + } + + for module_.anonymous_children.each_value |&module_| { + self.report_unresolved_imports(module_); + } + } + + // Export recording + // + // This pass simply determines what all "export" keywords refer to and + // writes the results into the export map. + // + // FIXME #4953 This pass will be removed once exports change to per-item. + // Then this operation can simply be performed as part of item (or import) + // processing. + + fn record_exports(@mut self) { + let root_module = self.graph_root.get_module(); + self.record_exports_for_module_subtree(root_module); + } + + fn record_exports_for_module_subtree(@mut self, module_: @mut Module) { + // If this isn't a local crate, then bail out. We don't need to record + // exports for nonlocal crates. + + match module_.def_id { + Some(def_id) if def_id.crate == local_crate => { + // OK. Continue. + debug!("(recording exports for module subtree) recording \ + exports for local module"); + } + None => { + // Record exports for the root module. + debug!("(recording exports for module subtree) recording \ + exports for root module"); + } + Some(_) => { + // Bail out. + debug!("(recording exports for module subtree) not recording \ + exports for `%s`", + self.module_to_str(module_)); + return; + } + } + + self.record_exports_for_module(module_); + + for module_.children.each_value |&child_name_bindings| { + match child_name_bindings.get_module_if_available() { + None => { + // Nothing to do. + } + Some(child_module) => { + self.record_exports_for_module_subtree(child_module); + } + } + } + + for module_.anonymous_children.each_value |&child_module| { + self.record_exports_for_module_subtree(child_module); + } + } + + fn record_exports_for_module(@mut self, module_: @mut Module) { + let mut exports2 = ~[]; + + self.add_exports_for_module(&mut exports2, module_); + match /*bad*/copy module_.def_id { + Some(def_id) => { + self.export_map2.insert(def_id.node, exports2); + debug!("(computing exports) writing exports for %d (some)", + def_id.node); + } + None => {} + } + } + + fn add_exports_of_namebindings(@mut self, + exports2: &mut ~[Export2], + ident: ident, + namebindings: @mut NameBindings, + ns: Namespace, + reexport: bool) { + match (namebindings.def_for_namespace(ns), + namebindings.privacy_for_namespace(ns)) { + (Some(d), Some(Public)) => { + debug!("(computing exports) YES: %s '%s' => %?", + if reexport { ~"reexport" } else { ~"export"}, + *self.session.str_of(ident), + def_id_of_def(d)); + exports2.push(Export2 { + reexport: reexport, + name: self.session.str_of(ident), + def_id: def_id_of_def(d) + }); + } + (Some(_), Some(privacy)) => { + debug!("(computing reexports) NO: privacy %?", privacy); + } + (d_opt, p_opt) => { + debug!("(computing reexports) NO: %?, %?", d_opt, p_opt); + } + } + } + + fn add_exports_for_module(@mut self, + exports2: &mut ~[Export2], + module_: @mut Module) { + for module_.children.each |ident, namebindings| { + debug!("(computing exports) maybe export '%s'", + *self.session.str_of(*ident)); + self.add_exports_of_namebindings(&mut *exports2, + *ident, + *namebindings, + TypeNS, + false); + self.add_exports_of_namebindings(&mut *exports2, + *ident, + *namebindings, + ValueNS, + false); + } + + for module_.import_resolutions.each |ident, importresolution| { + if importresolution.privacy != Public { + debug!("(computing exports) not reexporting private `%s`", + *self.session.str_of(*ident)); + loop; + } + for [ TypeNS, ValueNS ].each |ns| { + match importresolution.target_for_namespace(*ns) { + Some(target) => { + debug!("(computing exports) maybe reexport '%s'", + *self.session.str_of(*ident)); + self.add_exports_of_namebindings(&mut *exports2, + *ident, + target.bindings, + *ns, + true) + } + _ => () + } + } + } + } + + // AST resolution + // + // We maintain a list of value ribs and type ribs. + // + // Simultaneously, we keep track of the current position in the module + // graph in the `current_module` pointer. When we go to resolve a name in + // the value or type namespaces, we first look through all the ribs and + // then query the module graph. When we resolve a name in the module + // namespace, we can skip all the ribs (since nested modules are not + // allowed within blocks in Rust) and jump straight to the current module + // graph node. + // + // Named implementations are handled separately. When we find a method + // call, we consult the module node to find all of the implementations in + // scope. This information is lazily cached in the module node. We then + // generate a fake "implementation scope" containing all the + // implementations thus found, for compatibility with old resolve pass. + + fn with_scope(@mut self, name: Option, f: &fn()) { + let orig_module = self.current_module; + + // Move down in the graph. + match name { + None => { + // Nothing to do. + } + Some(name) => { + match orig_module.children.find(&name) { + None => { + debug!("!!! (with scope) didn't find `%s` in `%s`", + *self.session.str_of(name), + self.module_to_str(orig_module)); + } + Some(name_bindings) => { + match (*name_bindings).get_module_if_available() { + None => { + debug!("!!! (with scope) didn't find module \ + for `%s` in `%s`", + *self.session.str_of(name), + self.module_to_str(orig_module)); + } + Some(module_) => { + self.current_module = module_; + } + } + } + } + } + } + + f(); + + self.current_module = orig_module; + } + + // Wraps the given definition in the appropriate number of `def_upvar` + // wrappers. + + fn upvarify(@mut self, + ribs: &mut ~[@Rib], + rib_index: uint, + def_like: def_like, + span: span, + allow_capturing_self: AllowCapturingSelfFlag) + -> Option { + let mut def; + let is_ty_param; + + match def_like { + dl_def(d @ def_local(*)) | dl_def(d @ def_upvar(*)) | + dl_def(d @ def_arg(*)) | dl_def(d @ def_binding(*)) => { + def = d; + is_ty_param = false; + } + dl_def(d @ def_ty_param(*)) => { + def = d; + is_ty_param = true; + } + dl_def(d @ def_self(*)) + if allow_capturing_self == DontAllowCapturingSelf => { + def = d; + is_ty_param = false; + } + _ => { + return Some(def_like); + } + } + + let mut rib_index = rib_index + 1; + while rib_index < ribs.len() { + match ribs[rib_index].kind { + NormalRibKind => { + // Nothing to do. Continue. + } + FunctionRibKind(function_id, body_id) => { + if !is_ty_param { + def = def_upvar(def_id_of_def(def).node, + @def, + function_id, + body_id); + } + } + MethodRibKind(item_id, _) => { + // If the def is a ty param, and came from the parent + // item, it's ok + match def { + def_ty_param(did, _) + if self.def_map.find(&did.node).map_consume(|x| *x) + == Some(def_typaram_binder(item_id)) => { + // ok + } + _ => { + if !is_ty_param { + // This was an attempt to access an upvar inside a + // named function item. This is not allowed, so we + // report an error. + + self.session.span_err( + span, + ~"attempted dynamic environment-capture"); + } else { + // This was an attempt to use a type parameter outside + // its scope. + + self.session.span_err(span, + ~"attempt to use a type \ + argument out of scope"); + } + + return None; + } + } + } + OpaqueFunctionRibKind => { + if !is_ty_param { + // This was an attempt to access an upvar inside a + // named function item. This is not allowed, so we + // report an error. + + self.session.span_err( + span, + ~"attempted dynamic environment-capture"); + } else { + // This was an attempt to use a type parameter outside + // its scope. + + self.session.span_err(span, + ~"attempt to use a type \ + argument out of scope"); + } + + return None; + } + ConstantItemRibKind => { + // Still doesn't deal with upvars + self.session.span_err(span, + ~"attempt to use a non-constant \ + value in a constant"); + + } + } + + rib_index += 1; + } + + return Some(dl_def(def)); + } + + fn search_ribs(@mut self, + ribs: &mut ~[@Rib], + name: ident, + span: span, + allow_capturing_self: AllowCapturingSelfFlag) + -> Option { + // FIXME #4950: This should not use a while loop. + // FIXME #4950: Try caching? + + let mut i = ribs.len(); + while i != 0 { + i -= 1; + match ribs[i].bindings.find(&name) { + Some(&def_like) => { + return self.upvarify(ribs, i, def_like, span, + allow_capturing_self); + } + None => { + // Continue. + } + } + } + + return None; + } + + fn resolve_crate(@mut self) { + debug!("(resolving crate) starting"); + + visit_crate(self.crate, (), mk_vt(@Visitor { + visit_item: |item, _context, visitor| + self.resolve_item(item, visitor), + visit_arm: |arm, _context, visitor| + self.resolve_arm(arm, visitor), + visit_block: |block, _context, visitor| + self.resolve_block(block, visitor), + visit_expr: |expr, _context, visitor| + self.resolve_expr(expr, visitor), + visit_local: |local, _context, visitor| + self.resolve_local(local, visitor), + visit_ty: |ty, _context, visitor| + self.resolve_type(ty, visitor), + .. *default_visitor() + })); + } + + fn resolve_item(@mut self, item: @item, visitor: ResolveVisitor) { + debug!("(resolving item) resolving %s", + *self.session.str_of(item.ident)); + + // Items with the !resolve_unexported attribute are X-ray contexts. + // This is used to allow the test runner to run unexported tests. + let orig_xray_flag = self.xray_context; + if contains_name(attr_metas(item.attrs), + ~"!resolve_unexported") { + self.xray_context = Xray; + } + + match item.node { + + // enum item: resolve all the variants' discrs, + // then resolve the ty params + item_enum(ref enum_def, ref generics) => { + for (*enum_def).variants.each() |variant| { + for variant.node.disr_expr.each |dis_expr| { + // resolve the discriminator expr + // as a constant + self.with_constant_rib(|| { + self.resolve_expr(*dis_expr, visitor); + }); + } + } + + // n.b. the discr expr gets visted twice. + // but maybe it's okay since the first time will signal an + // error if there is one? -- tjc + do self.with_type_parameter_rib( + HasTypeParameters( + generics, item.id, 0, NormalRibKind)) { + visit_item(item, (), visitor); + } + } + + item_ty(_, ref generics) => { + do self.with_type_parameter_rib + (HasTypeParameters(generics, item.id, 0, + NormalRibKind)) + || { + + visit_item(item, (), visitor); + } + } + + item_impl(ref generics, + implemented_traits, + self_type, + ref methods) => { + self.resolve_implementation(item.id, + generics, + implemented_traits, + self_type, + *methods, + visitor); + } + + item_trait(ref generics, ref traits, ref methods) => { + // Create a new rib for the self type. + let self_type_rib = @Rib(NormalRibKind); + self.type_ribs.push(self_type_rib); + self_type_rib.bindings.insert(self.type_self_ident, + dl_def(def_self_ty(item.id))); + + // Create a new rib for the trait-wide type parameters. + do self.with_type_parameter_rib + (HasTypeParameters(generics, item.id, 0, + NormalRibKind)) { + + self.resolve_type_parameters(&generics.ty_params, + visitor); + + // Resolve derived traits. + for traits.each |trt| { + match self.resolve_path(trt.path, TypeNS, true, + visitor) { + None => + self.session.span_err(trt.path.span, + ~"attempt to derive a \ + nonexistent trait"), + Some(def) => { + // Write a mapping from the trait ID to the + // definition of the trait into the definition + // map. + + debug!("(resolving trait) found trait def: \ + %?", def); + + self.record_def(trt.ref_id, def); + } + } + } + + for (*methods).each |method| { + // Create a new rib for the method-specific type + // parameters. + // + // FIXME #4951: Do we need a node ID here? + + match *method { + required(ref ty_m) => { + do self.with_type_parameter_rib + (HasTypeParameters(&ty_m.generics, + item.id, + generics.ty_params.len(), + MethodRibKind(item.id, Required))) { + + // Resolve the method-specific type + // parameters. + self.resolve_type_parameters( + &ty_m.generics.ty_params, + visitor); + + for ty_m.decl.inputs.each |argument| { + self.resolve_type(argument.ty, visitor); + } + + self.resolve_type(ty_m.decl.output, visitor); + } + } + provided(m) => { + self.resolve_method(MethodRibKind(item.id, + Provided(m.id)), + m, + generics.ty_params.len(), + visitor) + } + } + } + } + + self.type_ribs.pop(); + } + + item_struct(ref struct_def, ref generics) => { + self.resolve_struct(item.id, + generics, + struct_def.fields, + &struct_def.dtor, + visitor); + } + + item_mod(ref module_) => { + do self.with_scope(Some(item.ident)) { + self.resolve_module(module_, item.span, item.ident, + item.id, visitor); + } + } + + item_foreign_mod(ref foreign_module) => { + do self.with_scope(Some(item.ident)) { + for foreign_module.items.each |foreign_item| { + match foreign_item.node { + foreign_item_fn(_, _, ref generics) => { + self.with_type_parameter_rib( + HasTypeParameters( + generics, foreign_item.id, 0, + NormalRibKind), + || visit_foreign_item(*foreign_item, (), + visitor)); + } + foreign_item_const(_) => { + visit_foreign_item(*foreign_item, (), + visitor); + } + } + } + } + } + + item_fn(ref fn_decl, _, _, ref generics, ref block) => { + // If this is the main function, we must record it in the + // session. + + // FIXME #4404 android JNI hacks + if !*self.session.building_library || + self.session.targ_cfg.os == session::os_android { + + if self.attr_main_fn.is_none() && + item.ident == special_idents::main { + + self.main_fns.push(Some((item.id, item.span))); + } + + if attrs_contains_name(item.attrs, ~"main") { + if self.attr_main_fn.is_none() { + self.attr_main_fn = Some((item.id, item.span)); + } else { + self.session.span_err( + item.span, + ~"multiple 'main' functions"); + } + } + + if attrs_contains_name(item.attrs, ~"start") { + if self.start_fn.is_none() { + self.start_fn = Some((item.id, item.span)); + } else { + self.session.span_err( + item.span, + ~"multiple 'start' functions"); + } + } + } + + self.resolve_function(OpaqueFunctionRibKind, + Some(fn_decl), + HasTypeParameters + (generics, + item.id, + 0, + OpaqueFunctionRibKind), + block, + NoSelfBinding, + visitor); + } + + item_const(*) => { + self.with_constant_rib(|| { + visit_item(item, (), visitor); + }); + } + + item_mac(*) => { + fail!(~"item macros unimplemented") + } + } + + self.xray_context = orig_xray_flag; + } + + fn with_type_parameter_rib(@mut self, + type_parameters: TypeParameters, + f: &fn()) { + match type_parameters { + HasTypeParameters(generics, node_id, initial_index, + rib_kind) => { + + let function_type_rib = @Rib(rib_kind); + self.type_ribs.push(function_type_rib); + + for generics.ty_params.eachi |index, type_parameter| { + let name = type_parameter.ident; + debug!("with_type_parameter_rib: %d %d", node_id, + type_parameter.id); + let def_like = dl_def(def_ty_param + (local_def(type_parameter.id), + index + initial_index)); + // Associate this type parameter with + // the item that bound it + self.record_def(type_parameter.id, + def_typaram_binder(node_id)); + function_type_rib.bindings.insert(name, def_like); + } + } + + NoTypeParameters => { + // Nothing to do. + } + } + + f(); + + match type_parameters { + HasTypeParameters(*) => { + self.type_ribs.pop(); + } + + NoTypeParameters => { + // Nothing to do. + } + } + } + + fn with_label_rib(@mut self, f: &fn()) { + self.label_ribs.push(@Rib(NormalRibKind)); + f(); + self.label_ribs.pop(); + } + + fn with_constant_rib(@mut self, f: &fn()) { + self.value_ribs.push(@Rib(ConstantItemRibKind)); + f(); + self.value_ribs.pop(); + } + + fn resolve_function(@mut self, + rib_kind: RibKind, + optional_declaration: Option<&fn_decl>, + type_parameters: TypeParameters, + block: &blk, + self_binding: SelfBinding, + visitor: ResolveVisitor) { + // Create a value rib for the function. + let function_value_rib = @Rib(rib_kind); + self.value_ribs.push(function_value_rib); + + // Create a label rib for the function. + let function_label_rib = @Rib(rib_kind); + self.label_ribs.push(function_label_rib); + + // If this function has type parameters, add them now. + do self.with_type_parameter_rib(type_parameters) { + // Resolve the type parameters. + match type_parameters { + NoTypeParameters => { + // Continue. + } + HasTypeParameters(ref generics, _, _, _) => { + self.resolve_type_parameters(&generics.ty_params, + visitor); + } + } + + // Add self to the rib, if necessary. + match self_binding { + NoSelfBinding => { + // Nothing to do. + } + HasSelfBinding(self_node_id, is_implicit) => { + let def_like = dl_def(def_self(self_node_id, + is_implicit)); + (*function_value_rib).bindings.insert(self.self_ident, + def_like); + } + } + + // Add each argument to the rib. + match optional_declaration { + None => { + // Nothing to do. + } + Some(declaration) => { + for declaration.inputs.each |argument| { + let binding_mode = ArgumentIrrefutableMode; + let mutability = + if argument.is_mutbl {Mutable} else {Immutable}; + self.resolve_pattern(argument.pat, + binding_mode, + mutability, + None, + visitor); + + self.resolve_type(argument.ty, visitor); + + debug!("(resolving function) recorded argument"); + } + + self.resolve_type(declaration.output, visitor); + } + } + + // Resolve the function body. + self.resolve_block(block, visitor); + + debug!("(resolving function) leaving function"); + } + + self.label_ribs.pop(); + self.value_ribs.pop(); + } + + fn resolve_type_parameters(@mut self, + type_parameters: &OptVec, + visitor: ResolveVisitor) { + for type_parameters.each |type_parameter| { + for type_parameter.bounds.each |&bound| { + match bound { + TraitTyParamBound(tref) => { + self.resolve_trait_reference(tref, visitor) + } + RegionTyParamBound => {} + } + } + } + } + + fn resolve_trait_reference(@mut self, + trait_reference: &trait_ref, + visitor: ResolveVisitor) { + match self.resolve_path(trait_reference.path, TypeNS, true, visitor) { + None => { + self.session.span_err(trait_reference.path.span, + ~"attempt to implement an \ + unknown trait"); + } + Some(def) => { + self.record_def(trait_reference.ref_id, def); + } + } + } + + fn resolve_struct(@mut self, + id: node_id, + generics: &Generics, + fields: &[@struct_field], + optional_destructor: &Option, + visitor: ResolveVisitor) { + // If applicable, create a rib for the type parameters. + do self.with_type_parameter_rib(HasTypeParameters + (generics, id, 0, + OpaqueFunctionRibKind)) { + + // Resolve the type parameters. + self.resolve_type_parameters(&generics.ty_params, visitor); + + // Resolve fields. + for fields.each |field| { + self.resolve_type(field.node.ty, visitor); + } + + // Resolve the destructor, if applicable. + match *optional_destructor { + None => { + // Nothing to do. + } + Some(ref destructor) => { + self.resolve_function(NormalRibKind, + None, + NoTypeParameters, + &destructor.node.body, + HasSelfBinding + ((*destructor).node.self_id, + true), + visitor); + } + } + } + } + + // Does this really need to take a RibKind or is it always going + // to be NormalRibKind? + fn resolve_method(@mut self, + rib_kind: RibKind, + method: @method, + outer_type_parameter_count: uint, + visitor: ResolveVisitor) { + let method_generics = &method.generics; + let type_parameters = + HasTypeParameters(method_generics, + method.id, + outer_type_parameter_count, + rib_kind); + // we only have self ty if it is a non static method + let self_binding = match method.self_ty.node { + sty_static => { NoSelfBinding } + _ => { HasSelfBinding(method.self_id, false) } + }; + + self.resolve_function(rib_kind, + Some(&method.decl), + type_parameters, + &method.body, + self_binding, + visitor); + } + + fn resolve_implementation(@mut self, + id: node_id, + generics: &Generics, + opt_trait_reference: Option<@trait_ref>, + self_type: @Ty, + methods: &[@method], + visitor: ResolveVisitor) { + // If applicable, create a rib for the type parameters. + let outer_type_parameter_count = generics.ty_params.len(); + do self.with_type_parameter_rib(HasTypeParameters + (generics, id, 0, + NormalRibKind)) { + // Resolve the type parameters. + self.resolve_type_parameters(&generics.ty_params, + visitor); + + // Resolve the trait reference, if necessary. + let original_trait_refs; + match opt_trait_reference { + Some(trait_reference) => { + self.resolve_trait_reference(trait_reference, visitor); + + // Record the current set of trait references. + let mut new_trait_refs = ~[]; + for self.def_map.find(&trait_reference.ref_id).each |&def| { + new_trait_refs.push(def_id_of_def(*def)); + } + original_trait_refs = Some(util::replace( + &mut self.current_trait_refs, + Some(new_trait_refs))); + } + None => { + original_trait_refs = None; + } + } + + // Resolve the self type. + self.resolve_type(self_type, visitor); + + for methods.each |method| { + // We also need a new scope for the method-specific + // type parameters. + self.resolve_method(MethodRibKind( + id, + Provided(method.id)), + *method, + outer_type_parameter_count, + visitor); +/* + let borrowed_type_parameters = &method.tps; + self.resolve_function(MethodRibKind( + id, + Provided(method.id)), + Some(@method.decl), + HasTypeParameters + (borrowed_type_parameters, + method.id, + outer_type_parameter_count, + NormalRibKind), + method.body, + HasSelfBinding(method.self_id), + visitor); +*/ + } + + // Restore the original trait references. + match original_trait_refs { + Some(r) => { self.current_trait_refs = r; } + None => () + } + } + } + + fn resolve_module(@mut self, + module_: &_mod, + span: span, + _name: ident, + id: node_id, + visitor: ResolveVisitor) { + // Write the implementations in scope into the module metadata. + debug!("(resolving module) resolving module ID %d", id); + visit_mod(module_, span, id, (), visitor); + } + + fn resolve_local(@mut self, local: @local, visitor: ResolveVisitor) { + let mutability = if local.node.is_mutbl {Mutable} else {Immutable}; + + // Resolve the type. + self.resolve_type(local.node.ty, visitor); + + // Resolve the initializer, if necessary. + match local.node.init { + None => { + // Nothing to do. + } + Some(initializer) => { + self.resolve_expr(initializer, visitor); + } + } + + // Resolve the pattern. + self.resolve_pattern(local.node.pat, LocalIrrefutableMode, mutability, + None, visitor); + } + + fn binding_mode_map(@mut self, pat: @pat) -> BindingMap { + let mut result = HashMap::new(); + do pat_bindings(self.def_map, pat) |binding_mode, _id, sp, path| { + let ident = path_to_ident(path); + result.insert(ident, + binding_info {span: sp, + binding_mode: binding_mode}); + } + return result; + } + + fn check_consistent_bindings(@mut self, arm: &arm) { + if arm.pats.len() == 0 { return; } + let map_0 = self.binding_mode_map(arm.pats[0]); + for arm.pats.eachi() |i, p| { + let map_i = self.binding_mode_map(*p); + + for map_0.each |&key, &binding_0| { + match map_i.find(&key) { + None => { + self.session.span_err( + p.span, + fmt!("variable `%s` from pattern #1 is \ + not bound in pattern #%u", + *self.session.str_of(key), i + 1)); + } + Some(binding_i) => { + if binding_0.binding_mode != binding_i.binding_mode { + self.session.span_err( + binding_i.span, + fmt!("variable `%s` is bound with different \ + mode in pattern #%u than in pattern #1", + *self.session.str_of(key), i + 1)); + } + } + } + } + + for map_i.each |&key, &binding| { + if !map_0.contains_key(&key) { + self.session.span_err( + binding.span, + fmt!("variable `%s` from pattern #%u is \ + not bound in pattern #1", + *self.session.str_of(key), i + 1)); + } + } + } + } + + fn resolve_arm(@mut self, arm: &arm, visitor: ResolveVisitor) { + self.value_ribs.push(@Rib(NormalRibKind)); + + let bindings_list = @mut HashMap::new(); + for arm.pats.each |pattern| { + self.resolve_pattern(*pattern, RefutableMode, Immutable, + Some(bindings_list), visitor); + } + + // This has to happen *after* we determine which + // pat_idents are variants + self.check_consistent_bindings(arm); + + visit_expr_opt(arm.guard, (), visitor); + self.resolve_block(&arm.body, visitor); + + self.value_ribs.pop(); + } + + fn resolve_block(@mut self, block: &blk, visitor: ResolveVisitor) { + debug!("(resolving block) entering block"); + self.value_ribs.push(@Rib(NormalRibKind)); + + // Move down in the graph, if there's an anonymous module rooted here. + let orig_module = self.current_module; + match self.current_module.anonymous_children.find(&block.node.id) { + None => { /* Nothing to do. */ } + Some(&anonymous_module) => { + debug!("(resolving block) found anonymous module, moving \ + down"); + self.current_module = anonymous_module; + } + } + + // Descend into the block. + visit_block(block, (), visitor); + + // Move back up. + self.current_module = orig_module; + + self.value_ribs.pop(); + debug!("(resolving block) leaving block"); + } + + fn resolve_type(@mut self, ty: @Ty, visitor: ResolveVisitor) { + match ty.node { + // Like path expressions, the interpretation of path types depends + // on whether the path has multiple elements in it or not. + + ty_path(path, path_id) => { + // This is a path in the type namespace. Walk through scopes + // scopes looking for it. + let mut result_def = None; + + // First, check to see whether the name is a primitive type. + if path.idents.len() == 1 { + let name = *path.idents.last(); + + match self.primitive_type_table + .primitive_types + .find(&name) { + + Some(&primitive_type) => { + result_def = + Some(def_prim_ty(primitive_type)); + } + None => { + // Continue. + } + } + } + + match result_def { + None => { + match self.resolve_path(path, TypeNS, true, visitor) { + Some(def) => { + debug!("(resolving type) resolved `%s` to \ + type %?", + *self.session.str_of( + *path.idents.last()), + def); + result_def = Some(def); + } + None => { + result_def = None; + } + } + } + Some(_) => { + // Continue. + } + } + + match result_def { + Some(def) => { + // Write the result into the def map. + debug!("(resolving type) writing resolution for `%s` \ + (id %d)", + self.idents_to_str(path.idents), + path_id); + self.record_def(path_id, def); + } + None => { + self.session.span_err + (ty.span, fmt!("use of undeclared type name `%s`", + self.idents_to_str(path.idents))); + } + } + } + + _ => { + // Just resolve embedded types. + visit_ty(ty, (), visitor); + } + } + } + + fn resolve_pattern(@mut self, + pattern: @pat, + mode: PatternBindingMode, + mutability: Mutability, + // Maps idents to the node ID for the (outermost) + // pattern that binds them + bindings_list: Option<@mut HashMap>, + visitor: ResolveVisitor) { + let pat_id = pattern.id; + do walk_pat(pattern) |pattern| { + match pattern.node { + pat_ident(binding_mode, path, _) + if !path.global && path.idents.len() == 1 => { + + // The meaning of pat_ident with no type parameters + // depends on whether an enum variant or unit-like struct + // with that name is in scope. The probing lookup has to + // be careful not to emit spurious errors. Only matching + // patterns (match) can match nullary variants or + // unit-like structs. For binding patterns (let), matching + // such a value is simply disallowed (since it's rarely + // what you want). + + let ident = path.idents[0]; + + match self.resolve_bare_identifier_pattern(ident) { + FoundStructOrEnumVariant(def) + if mode == RefutableMode => { + debug!("(resolving pattern) resolving `%s` to \ + struct or enum variant", + *self.session.str_of(ident)); + + self.enforce_default_binding_mode( + pattern, + binding_mode, + "an enum variant"); + self.record_def(pattern.id, def); + } + FoundStructOrEnumVariant(_) => { + self.session.span_err(pattern.span, + fmt!("declaration of `%s` \ + shadows an enum \ + variant or unit-like \ + struct in scope", + *self.session + .str_of(ident))); + } + FoundConst(def) if mode == RefutableMode => { + debug!("(resolving pattern) resolving `%s` to \ + constant", + *self.session.str_of(ident)); + + self.enforce_default_binding_mode( + pattern, + binding_mode, + "a constant"); + self.record_def(pattern.id, def); + } + FoundConst(_) => { + self.session.span_err(pattern.span, + ~"only refutable patterns \ + allowed here"); + } + BareIdentifierPatternUnresolved => { + debug!("(resolving pattern) binding `%s`", + *self.session.str_of(ident)); + + let is_mutable = mutability == Mutable; + + let def = match mode { + RefutableMode => { + // For pattern arms, we must use + // `def_binding` definitions. + + def_binding(pattern.id, binding_mode) + } + LocalIrrefutableMode => { + // But for locals, we use `def_local`. + def_local(pattern.id, is_mutable) + } + ArgumentIrrefutableMode => { + // And for function arguments, `def_arg`. + def_arg(pattern.id, is_mutable) + } + }; + + // Record the definition so that later passes + // will be able to distinguish variants from + // locals in patterns. + + self.record_def(pattern.id, def); + + // Add the binding to the local ribs, if it + // doesn't already exist in the bindings list. (We + // must not add it if it's in the bindings list + // because that breaks the assumptions later + // passes make about or-patterns.) + + match bindings_list { + Some(bindings_list) + if !bindings_list.contains_key(&ident) => { + let this = &mut *self; + let last_rib = this.value_ribs[ + this.value_ribs.len() - 1]; + last_rib.bindings.insert(ident, + dl_def(def)); + bindings_list.insert(ident, pat_id); + } + Some(b) => { + if b.find(&ident) == Some(&pat_id) { + // Then this is a duplicate variable + // in the same disjunct, which is an + // error + self.session.span_err(pattern.span, + fmt!("Identifier %s is bound more \ + than once in the same pattern", + path_to_str(path, self.session + .intr()))); + } + // Not bound in the same pattern: do nothing + } + None => { + let this = &mut *self; + let last_rib = this.value_ribs[ + this.value_ribs.len() - 1]; + last_rib.bindings.insert(ident, + dl_def(def)); + } + } + } + } + + // Check the types in the path pattern. + for path.types.each |ty| { + self.resolve_type(*ty, visitor); + } + } + + pat_ident(binding_mode, path, _) => { + // This must be an enum variant, struct, or constant. + match self.resolve_path(path, ValueNS, false, visitor) { + Some(def @ def_variant(*)) | + Some(def @ def_struct(*)) => { + self.record_def(pattern.id, def); + } + Some(def @ def_const(*)) => { + self.enforce_default_binding_mode( + pattern, + binding_mode, + "a constant"); + self.record_def(pattern.id, def); + } + Some(_) => { + self.session.span_err( + path.span, + fmt!("not an enum variant or constant: %s", + *self.session.str_of( + *path.idents.last()))); + } + None => { + self.session.span_err(path.span, + ~"unresolved enum variant"); + } + } + + // Check the types in the path pattern. + for path.types.each |ty| { + self.resolve_type(*ty, visitor); + } + } + + pat_enum(path, _) => { + // This must be an enum variant, struct or const. + match self.resolve_path(path, ValueNS, false, visitor) { + Some(def @ def_fn(*)) | + Some(def @ def_variant(*)) | + Some(def @ def_struct(*)) | + Some(def @ def_const(*)) => { + self.record_def(pattern.id, def); + } + Some(_) => { + self.session.span_err( + path.span, + fmt!("not an enum variant, struct or const: %s", + *self.session.str_of( + *path.idents.last()))); + } + None => { + self.session.span_err(path.span, + ~"unresolved enum variant, \ + struct or const"); + } + } + + // Check the types in the path pattern. + for path.types.each |ty| { + self.resolve_type(*ty, visitor); + } + } + + pat_lit(expr) => { + self.resolve_expr(expr, visitor); + } + + pat_range(first_expr, last_expr) => { + self.resolve_expr(first_expr, visitor); + self.resolve_expr(last_expr, visitor); + } + + pat_struct(path, _, _) => { + let structs: &mut HashSet = &mut self.structs; + match self.resolve_path(path, TypeNS, false, visitor) { + Some(def_ty(class_id)) + if structs.contains(&class_id) => { + let class_def = def_struct(class_id); + self.record_def(pattern.id, class_def); + } + Some(definition @ def_struct(class_id)) + if structs.contains(&class_id) => { + self.record_def(pattern.id, definition); + } + Some(definition @ def_variant(_, variant_id)) + if structs.contains(&variant_id) => { + self.record_def(pattern.id, definition); + } + result => { + debug!("(resolving pattern) didn't find struct \ + def: %?", result); + self.session.span_err( + path.span, + fmt!("`%s` does not name a structure", + self.idents_to_str(path.idents))); + } + } + } + + _ => { + // Nothing to do. + } + } + } + } + + fn resolve_bare_identifier_pattern(@mut self, name: ident) + -> BareIdentifierPatternResolution { + match self.resolve_item_in_lexical_scope(self.current_module, + name, + ValueNS, + SearchThroughModules) { + Success(target) => { + match target.bindings.value_def { + None => { + fail!(~"resolved name in the value namespace to a \ + set of name bindings with no def?!"); + } + Some(def) => { + match def.def { + def @ def_variant(*) | def @ def_struct(*) => { + return FoundStructOrEnumVariant(def); + } + def @ def_const(*) => { + return FoundConst(def); + } + _ => { + return BareIdentifierPatternUnresolved; + } + } + } + } + } + + Indeterminate => { + fail!(~"unexpected indeterminate result"); + } + + Failed => { + return BareIdentifierPatternUnresolved; + } + } + } + + /// If `check_ribs` is true, checks the local definitions first; i.e. + /// doesn't skip straight to the containing module. + fn resolve_path(@mut self, + path: @Path, + namespace: Namespace, + check_ribs: bool, + visitor: ResolveVisitor) + -> Option { + // First, resolve the types. + for path.types.each |ty| { + self.resolve_type(*ty, visitor); + } + + if path.global { + return self.resolve_crate_relative_path(path, + self.xray_context, + namespace); + } + + if path.idents.len() > 1 { + return self.resolve_module_relative_path(path, + self.xray_context, + namespace); + } + + return self.resolve_identifier(*path.idents.last(), + namespace, + check_ribs, + path.span); + } + + fn resolve_identifier(@mut self, + identifier: ident, + namespace: Namespace, + check_ribs: bool, + span: span) + -> Option { + if check_ribs { + match self.resolve_identifier_in_local_ribs(identifier, + namespace, + span) { + Some(def) => { + return Some(def); + } + None => { + // Continue. + } + } + } + + return self.resolve_item_by_identifier_in_lexical_scope(identifier, + namespace); + } + + // FIXME #4952: Merge me with resolve_name_in_module? + fn resolve_definition_of_name_in_module(@mut self, + containing_module: @mut Module, + name: ident, + namespace: Namespace, + xray: XrayFlag) + -> NameDefinition { + // First, search children. + match containing_module.children.find(&name) { + Some(child_name_bindings) => { + match (child_name_bindings.def_for_namespace(namespace), + child_name_bindings.privacy_for_namespace(namespace)) { + (Some(def), Some(Public)) => { + // Found it. Stop the search here. + return ChildNameDefinition(def); + } + (Some(def), _) if xray == Xray => { + // Found it. Stop the search here. + return ChildNameDefinition(def); + } + (Some(_), _) | (None, _) => { + // Continue. + } + } + } + None => { + // Continue. + } + } + + // Next, search import resolutions. + match containing_module.import_resolutions.find(&name) { + Some(import_resolution) if import_resolution.privacy == Public || + xray == Xray => { + match (*import_resolution).target_for_namespace(namespace) { + Some(target) => { + match (target.bindings.def_for_namespace(namespace), + target.bindings.privacy_for_namespace( + namespace)) { + (Some(def), Some(Public)) => { + // Found it. + import_resolution.state.used = true; + return ImportNameDefinition(def); + } + (Some(_), _) | (None, _) => { + // This can happen with external impls, due to + // the imperfect way we read the metadata. + } + } + } + None => {} + } + } + Some(_) | None => {} // Continue. + } + + // Finally, search through external children. + if namespace == TypeNS { + match containing_module.external_module_children.find(&name) { + None => {} + Some(module) => { + match module.def_id { + None => {} // Continue. + Some(def_id) => { + return ChildNameDefinition(def_mod(def_id)); + } + } + } + } + } + + return NoNameDefinition; + } + + fn intern_module_part_of_path(@mut self, path: @Path) -> ~[ident] { + let mut module_path_idents = ~[]; + for path.idents.eachi |index, ident| { + if index == path.idents.len() - 1 { + break; + } + + module_path_idents.push(*ident); + } + + return module_path_idents; + } + + fn resolve_module_relative_path(@mut self, + path: @Path, + xray: XrayFlag, + namespace: Namespace) + -> Option { + let module_path_idents = self.intern_module_part_of_path(path); + + let containing_module; + match self.resolve_module_path_for_import(self.current_module, + module_path_idents, + UseLexicalScope, + path.span) { + Failed => { + self.session.span_err(path.span, + fmt!("use of undeclared module `%s`", + self.idents_to_str( + module_path_idents))); + return None; + } + + Indeterminate => { + fail!(~"indeterminate unexpected"); + } + + Success(resulting_module) => { + containing_module = resulting_module; + } + } + + let name = *path.idents.last(); + match self.resolve_definition_of_name_in_module(containing_module, + name, + namespace, + xray) { + NoNameDefinition => { + // We failed to resolve the name. Report an error. + return None; + } + ChildNameDefinition(def) | ImportNameDefinition(def) => { + return Some(def); + } + } + } + + /// Invariant: This must be called only during main resolution, not during + /// import resolution. + fn resolve_crate_relative_path(@mut self, + path: @Path, + xray: XrayFlag, + namespace: Namespace) + -> Option { + let module_path_idents = self.intern_module_part_of_path(path); + + let root_module = self.graph_root.get_module(); + + let containing_module; + match self.resolve_module_path_from_root(root_module, + module_path_idents, + 0, + path.span, + SearchItemsAndAllImports) { + Failed => { + self.session.span_err(path.span, + fmt!("use of undeclared module `::%s`", + self.idents_to_str( + module_path_idents))); + return None; + } + + Indeterminate => { + fail!(~"indeterminate unexpected"); + } + + Success(resulting_module) => { + containing_module = resulting_module; + } + } + + let name = *path.idents.last(); + match self.resolve_definition_of_name_in_module(containing_module, + name, + namespace, + xray) { + NoNameDefinition => { + // We failed to resolve the name. Report an error. + return None; + } + ChildNameDefinition(def) | ImportNameDefinition(def) => { + return Some(def); + } + } + } + + fn resolve_identifier_in_local_ribs(@mut self, + ident: ident, + namespace: Namespace, + span: span) + -> Option { + // Check the local set of ribs. + let search_result; + match namespace { + ValueNS => { + search_result = self.search_ribs(&mut self.value_ribs, ident, + span, + DontAllowCapturingSelf); + } + TypeNS => { + search_result = self.search_ribs(&mut self.type_ribs, ident, + span, AllowCapturingSelf); + } + } + + match search_result { + Some(dl_def(def)) => { + debug!("(resolving path in local ribs) resolved `%s` to \ + local: %?", + *self.session.str_of(ident), + def); + return Some(def); + } + Some(dl_field) | Some(dl_impl(_)) | None => { + return None; + } + } + } + + fn resolve_item_by_identifier_in_lexical_scope(@mut self, + ident: ident, + namespace: Namespace) + -> Option { + // Check the items. + match self.resolve_item_in_lexical_scope(self.current_module, + ident, + namespace, + DontSearchThroughModules) { + Success(target) => { + match (*target.bindings).def_for_namespace(namespace) { + None => { + // This can happen if we were looking for a type and + // found a module instead. Modules don't have defs. + return None; + } + Some(def) => { + debug!("(resolving item path in lexical scope) \ + resolved `%s` to item", + *self.session.str_of(ident)); + return Some(def); + } + } + } + Indeterminate => { + fail!(~"unexpected indeterminate result"); + } + Failed => { + return None; + } + } + } + + fn find_best_match_for_name(@mut self, name: &str, max_distance: uint) -> Option<~str> { + let this = &mut *self; + + let mut maybes: ~[~str] = ~[]; + let mut values: ~[uint] = ~[]; + + let mut j = this.value_ribs.len(); + while j != 0 { + j -= 1; + for this.value_ribs[j].bindings.each_key |&k| { + vec::push(&mut maybes, copy *this.session.str_of(k)); + vec::push(&mut values, uint::max_value); + } + } + + let mut smallest = 0; + for vec::eachi(maybes) |i, &other| { + + values[i] = str::levdistance(name, other); + + if values[i] <= values[smallest] { + smallest = i; + } + } + + if vec::len(values) > 0 && + values[smallest] != uint::max_value && + values[smallest] < str::len(name) + 2 && + values[smallest] <= max_distance && + maybes[smallest] != name.to_owned() { + + Some(vec::swap_remove(&mut maybes, smallest)) + + } else { + None + } + } + + fn name_exists_in_scope_struct(@mut self, name: &str) -> bool { + let this = &mut *self; + + let mut i = this.type_ribs.len(); + while i != 0 { + i -= 1; + match this.type_ribs[i].kind { + MethodRibKind(node_id, _) => + for this.crate.node.module.items.each |item| { + if item.id == node_id { + match item.node { + item_struct(class_def, _) => { + for vec::each(class_def.fields) |field| { + match field.node.kind { + unnamed_field => {}, + named_field(ident, _, _) => { + if str::eq_slice(*this.session.str_of(ident), + name) { + return true + } + } + } + } + } + _ => {} + } + } + }, + _ => {} + } + } + return false; + } + + fn resolve_expr(@mut self, expr: @expr, visitor: ResolveVisitor) { + // First, record candidate traits for this expression if it could + // result in the invocation of a method call. + + self.record_candidate_traits_for_expr_if_necessary(expr); + + // Next, resolve the node. + match expr.node { + // The interpretation of paths depends on whether the path has + // multiple elements in it or not. + + expr_path(path) => { + // This is a local path in the value namespace. Walk through + // scopes looking for it. + + match self.resolve_path(path, ValueNS, true, visitor) { + Some(def) => { + // Write the result into the def map. + debug!("(resolving expr) resolved `%s`", + self.idents_to_str(path.idents)); + self.record_def(expr.id, def); + } + None => { + let wrong_name = self.idents_to_str( + path.idents); + if self.name_exists_in_scope_struct(wrong_name) { + self.session.span_err(expr.span, + fmt!("unresolved name: `%s`. \ + Did you mean: `self.%s`?", + wrong_name, + wrong_name)); + } + else { + // limit search to 5 to reduce the number + // of stupid suggestions + match self.find_best_match_for_name(wrong_name, 5) { + Some(m) => { + self.session.span_err(expr.span, + fmt!("unresolved name: `%s`. \ + Did you mean: `%s`?", + wrong_name, m)); + } + None => { + self.session.span_err(expr.span, + fmt!("unresolved name: `%s`.", + wrong_name)); + } + } + } + } + } + + visit_expr(expr, (), visitor); + } + + expr_fn_block(ref fn_decl, ref block) => { + self.resolve_function(FunctionRibKind(expr.id, block.node.id), + Some(fn_decl), + NoTypeParameters, + block, + NoSelfBinding, + visitor); + } + + expr_struct(path, _, _) => { + // Resolve the path to the structure it goes to. + let structs: &mut HashSet = &mut self.structs; + match self.resolve_path(path, TypeNS, false, visitor) { + Some(def_ty(class_id)) | Some(def_struct(class_id)) + if structs.contains(&class_id) => { + let class_def = def_struct(class_id); + self.record_def(expr.id, class_def); + } + Some(definition @ def_variant(_, class_id)) + if structs.contains(&class_id) => { + self.record_def(expr.id, definition); + } + _ => { + self.session.span_err( + path.span, + fmt!("`%s` does not name a structure", + self.idents_to_str(path.idents))); + } + } + + visit_expr(expr, (), visitor); + } + + expr_loop(_, Some(label)) => { + do self.with_label_rib { + let this = &mut *self; + let def_like = dl_def(def_label(expr.id)); + let rib = this.label_ribs[this.label_ribs.len() - 1]; + rib.bindings.insert(label, def_like); + + visit_expr(expr, (), visitor); + } + } + + expr_break(Some(label)) | expr_again(Some(label)) => { + match self.search_ribs(&mut self.label_ribs, label, expr.span, + DontAllowCapturingSelf) { + None => + self.session.span_err(expr.span, + fmt!("use of undeclared label \ + `%s`", + *self.session.str_of( + label))), + Some(dl_def(def @ def_label(_))) => + self.record_def(expr.id, def), + Some(_) => + self.session.span_bug(expr.span, + ~"label wasn't mapped to a \ + label def!") + } + } + + _ => { + visit_expr(expr, (), visitor); + } + } + } + + fn record_candidate_traits_for_expr_if_necessary(@mut self, expr: @expr) { + match expr.node { + expr_field(_, ident, _) => { + let traits = self.search_for_traits_containing_method(ident); + self.trait_map.insert(expr.id, @mut traits); + } + expr_method_call(_, ident, _, _, _) => { + let traits = self.search_for_traits_containing_method(ident); + self.trait_map.insert(expr.id, @mut traits); + } + expr_binary(add, _, _) | expr_assign_op(add, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.add_trait()); + } + expr_binary(subtract, _, _) | expr_assign_op(subtract, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.sub_trait()); + } + expr_binary(mul, _, _) | expr_assign_op(mul, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.mul_trait()); + } + expr_binary(quot, _, _) | expr_assign_op(quot, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.quot_trait()); + } + expr_binary(rem, _, _) | expr_assign_op(rem, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.rem_trait()); + } + expr_binary(bitxor, _, _) | expr_assign_op(bitxor, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.bitxor_trait()); + } + expr_binary(bitand, _, _) | expr_assign_op(bitand, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.bitand_trait()); + } + expr_binary(bitor, _, _) | expr_assign_op(bitor, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.bitor_trait()); + } + expr_binary(shl, _, _) | expr_assign_op(shl, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.shl_trait()); + } + expr_binary(shr, _, _) | expr_assign_op(shr, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.shr_trait()); + } + expr_binary(lt, _, _) | expr_binary(le, _, _) | + expr_binary(ge, _, _) | expr_binary(gt, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.ord_trait()); + } + expr_binary(eq, _, _) | expr_binary(ne, _, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.eq_trait()); + } + expr_unary(neg, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.neg_trait()); + } + expr_unary(not, _) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.not_trait()); + } + expr_index(*) => { + self.add_fixed_trait_for_expr(expr.id, + self.lang_items.index_trait()); + } + _ => { + // Nothing to do. + } + } + } + + fn search_for_traits_containing_method(@mut self, + name: ident) + -> ~[def_id] { + debug!("(searching for traits containing method) looking for '%s'", + *self.session.str_of(name)); + + let mut found_traits = ~[]; + let mut search_module = self.current_module; + loop { + // Look for the current trait. + match /*bad*/copy self.current_trait_refs { + Some(trait_def_ids) => { + for trait_def_ids.each |trait_def_id| { + self.add_trait_info_if_containing_method( + &mut found_traits, *trait_def_id, name); + } + } + None => { + // Nothing to do. + } + } + + // Look for trait children. + for search_module.children.each_value |&child_name_bindings| { + match child_name_bindings.def_for_namespace(TypeNS) { + Some(def) => { + match def { + def_trait(trait_def_id) => { + self.add_trait_info_if_containing_method( + &mut found_traits, trait_def_id, name); + } + _ => { + // Continue. + } + } + } + None => { + // Continue. + } + } + } + + // Look for imports. + for search_module.import_resolutions.each_value + |&import_resolution| { + + match import_resolution.target_for_namespace(TypeNS) { + None => { + // Continue. + } + Some(target) => { + match target.bindings.def_for_namespace(TypeNS) { + Some(def) => { + match def { + def_trait(trait_def_id) => { + let added = self. + add_trait_info_if_containing_method( + &mut found_traits, + trait_def_id, name); + if added { + import_resolution.state.used = + true; + } + } + _ => { + // Continue. + } + } + } + None => { + // Continue. + } + } + } + } + } + + // Move to the next parent. + match search_module.parent_link { + NoParentLink => { + // Done. + break; + } + ModuleParentLink(parent_module, _) | + BlockParentLink(parent_module, _) => { + search_module = parent_module; + } + } + } + + return found_traits; + } + + fn add_trait_info_if_containing_method(&self, + found_traits: &mut ~[def_id], + trait_def_id: def_id, + name: ident) + -> bool { + debug!("(adding trait info if containing method) trying trait %d:%d \ + for method '%s'", + trait_def_id.crate, + trait_def_id.node, + *self.session.str_of(name)); + + match self.trait_info.find(&trait_def_id) { + Some(trait_info) if trait_info.contains(&name) => { + debug!("(adding trait info if containing method) found trait \ + %d:%d for method '%s'", + trait_def_id.crate, + trait_def_id.node, + *self.session.str_of(name)); + found_traits.push(trait_def_id); + true + } + Some(_) | None => { + false + } + } + } + + fn add_fixed_trait_for_expr(@mut self, + expr_id: node_id, + trait_id: def_id) { + self.trait_map.insert(expr_id, @mut ~[trait_id]); + } + + fn record_def(@mut self, node_id: node_id, def: def) { + debug!("(recording def) recording %? for %?", def, node_id); + self.def_map.insert(node_id, def); + } + + fn enforce_default_binding_mode(@mut self, + pat: @pat, + pat_binding_mode: binding_mode, + descr: &str) { + match pat_binding_mode { + bind_infer => {} + bind_by_copy => { + self.session.span_err( + pat.span, + fmt!("cannot use `copy` binding mode with %s", + descr)); + } + bind_by_ref(*) => { + self.session.span_err( + pat.span, + fmt!("cannot use `ref` binding mode with %s", + descr)); + } + } + } + + // + // main function checking + // + // be sure that there is only one main function + // + fn check_duplicate_main(@mut self) { + let this = &mut *self; + if this.attr_main_fn.is_none() && this.start_fn.is_none() { + if this.main_fns.len() >= 1u { + let mut i = 1u; + while i < this.main_fns.len() { + let (_, dup_main_span) = this.main_fns[i].unwrap(); + this.session.span_err( + dup_main_span, + ~"multiple 'main' functions"); + i += 1; + } + *this.session.entry_fn = this.main_fns[0]; + *this.session.entry_type = Some(session::EntryMain); + } + } else if !this.start_fn.is_none() { + *this.session.entry_fn = this.start_fn; + *this.session.entry_type = Some(session::EntryStart); + } else { + *this.session.entry_fn = this.attr_main_fn; + *this.session.entry_type = Some(session::EntryMain); + } + } + + // + // Unused import checking + // + // Although this is a lint pass, it lives in here because it depends on + // resolve data structures. + // + + fn unused_import_lint_level(@mut self, m: @mut Module) -> level { + let settings = self.session.lint_settings; + match m.def_id { + Some(def) => get_lint_settings_level(settings, unused_imports, + def.node, def.node), + None => get_lint_level(settings.default_settings, unused_imports) + } + } + + fn check_for_unused_imports_if_necessary(@mut self) { + if self.unused_import_lint_level(self.current_module) == allow { + return; + } + + let root_module = self.graph_root.get_module(); + self.check_for_unused_imports_in_module_subtree(root_module); + } + + fn check_for_unused_imports_in_module_subtree(@mut self, + module_: @mut Module) { + // If this isn't a local crate, then bail out. We don't need to check + // for unused imports in external crates. + + match module_.def_id { + Some(def_id) if def_id.crate == local_crate => { + // OK. Continue. + } + None => { + // Check for unused imports in the root module. + } + Some(_) => { + // Bail out. + debug!("(checking for unused imports in module subtree) not \ + checking for unused imports for `%s`", + self.module_to_str(module_)); + return; + } + } + + self.check_for_unused_imports_in_module(module_); + + for module_.children.each_value |&child_name_bindings| { + match (*child_name_bindings).get_module_if_available() { + None => { + // Nothing to do. + } + Some(child_module) => { + self.check_for_unused_imports_in_module_subtree + (child_module); + } + } + } + + for module_.anonymous_children.each_value |&child_module| { + self.check_for_unused_imports_in_module_subtree(child_module); + } + } + + fn check_for_unused_imports_in_module(@mut self, module_: @mut Module) { + for module_.import_resolutions.each_value |&import_resolution| { + // Ignore dummy spans for things like automatically injected + // imports for the prelude, and also don't warn about the same + // import statement being unused more than once. Furthermore, if + // the import is public, then we can't be sure whether it's unused + // or not so don't warn about it. + if !import_resolution.state.used && + !import_resolution.state.warned && + import_resolution.span != dummy_sp() && + import_resolution.privacy != Public { + import_resolution.state.warned = true; + let span = import_resolution.span; + self.session.span_lint_level( + self.unused_import_lint_level(module_), + span, + ~"unused import"); + } + } + } + + + // + // Diagnostics + // + // Diagnostics are not particularly efficient, because they're rarely + // hit. + // + + /// A somewhat inefficient routine to obtain the name of a module. + fn module_to_str(@mut self, module_: @mut Module) -> ~str { + let mut idents = ~[]; + let mut current_module = module_; + loop { + match current_module.parent_link { + NoParentLink => { + break; + } + ModuleParentLink(module_, name) => { + idents.push(name); + current_module = module_; + } + BlockParentLink(module_, _) => { + idents.push(special_idents::opaque); + current_module = module_; + } + } + } + + if idents.len() == 0 { + return ~"???"; + } + return self.idents_to_str(vec::reversed(idents)); + } + + fn dump_module(@mut self, module_: @mut Module) { + debug!("Dump of module `%s`:", self.module_to_str(module_)); + + debug!("Children:"); + for module_.children.each_key |&name| { + debug!("* %s", *self.session.str_of(name)); + } + + debug!("Import resolutions:"); + for module_.import_resolutions.each |name, import_resolution| { + let value_repr; + match import_resolution.target_for_namespace(ValueNS) { + None => { value_repr = ~""; } + Some(_) => { + value_repr = ~" value:?"; + // FIXME #4954 + } + } + + let type_repr; + match import_resolution.target_for_namespace(TypeNS) { + None => { type_repr = ~""; } + Some(_) => { + type_repr = ~" type:?"; + // FIXME #4954 + } + } + + debug!("* %s:%s%s", *self.session.str_of(*name), + value_repr, type_repr); + } + } +} + +pub struct CrateMap { + def_map: DefMap, + exp_map2: ExportMap2, + trait_map: TraitMap +} + +/// Entry point to crate resolution. +pub fn resolve_crate(session: Session, + lang_items: LanguageItems, + crate: @crate) + -> CrateMap { + let resolver = @mut Resolver(session, lang_items, crate); + resolver.resolve(); + let @Resolver{def_map, export_map2, trait_map, _} = resolver; + CrateMap { + def_map: def_map, + exp_map2: export_map2, + trait_map: trait_map + } +} diff --git a/src/librustc/middle/trans/write_guard.rs b/src/librustc/middle/trans/write_guard.rs new file mode 100644 index 0000000000000..18f21b489b0b8 --- /dev/null +++ b/src/librustc/middle/trans/write_guard.rs @@ -0,0 +1,201 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Logic relating to rooting and write guards for managed values +//! (`@` and `@mut`). This code is primarily for use by datum; +//! it exists in its own module both to keep datum.rs bite-sized +//! and for each in debugging (e.g., so you can use +//! `RUST_LOG=rustc::middle::trans::write_guard`). + +use lib::llvm::ValueRef; +use middle::borrowck::{RootInfo, root_map_key, DynaImm, DynaMut}; +use middle::trans::base::*; +use middle::trans::build::*; +use middle::trans::callee; +use middle::trans::common::*; +use middle::trans::datum::*; +use middle::trans::expr; +use middle::ty; +use driver::session; +use syntax::codemap::span; +use syntax::ast; + +pub fn root_and_write_guard(datum: &Datum, + mut bcx: block, + span: span, + expr_id: ast::node_id, + derefs: uint) -> block { + let key = root_map_key { id: expr_id, derefs: derefs }; + debug!("write_guard::root_and_write_guard(key=%?)", key); + + // root the autoderef'd value, if necessary: + // + // (Note: root'd values are always boxes) + let ccx = bcx.ccx(); + bcx = match ccx.maps.root_map.find(&key) { + None => bcx, + Some(&root_info) => root(datum, bcx, span, key, root_info) + }; + + // Perform the write guard, if necessary. + // + // (Note: write-guarded values are always boxes) + if ccx.maps.write_guard_map.contains(&key) { + perform_write_guard(datum, bcx, span) + } else { + bcx + } +} + +pub fn return_to_mut(mut bcx: block, + root_key: root_map_key, + frozen_val_ref: ValueRef, + bits_val_ref: ValueRef, + filename_val: ValueRef, + line_val: ValueRef) -> block { + debug!("write_guard::return_to_mut(root_key=%?, %s, %s, %s)", + root_key, + bcx.to_str(), + val_str(bcx.ccx().tn, frozen_val_ref), + val_str(bcx.ccx().tn, bits_val_ref)); + + let box_ptr = + Load(bcx, PointerCast(bcx, + frozen_val_ref, + T_ptr(T_ptr(T_i8())))); + + let bits_val = + Load(bcx, bits_val_ref); + + if bcx.tcx().sess.opts.optimize == session::No { + bcx = callee::trans_lang_call( + bcx, + bcx.tcx().lang_items.unrecord_borrow_fn(), + ~[ + box_ptr, + bits_val, + filename_val, + line_val + ], + expr::Ignore); + } + + callee::trans_lang_call( + bcx, + bcx.tcx().lang_items.return_to_mut_fn(), + ~[ + box_ptr, + bits_val, + filename_val, + line_val + ], + expr::Ignore + ) +} + +fn root(datum: &Datum, + mut bcx: block, + span: span, + root_key: root_map_key, + root_info: RootInfo) -> block { + //! In some cases, borrowck will decide that an @T/@[]/@str + //! value must be rooted for the program to be safe. In that + //! case, we will call this function, which will stash a copy + //! away until we exit the scope `scope_id`. + + debug!("write_guard::root(root_key=%?, root_info=%?, datum=%?)", + root_key, root_info, datum.to_str(bcx.ccx())); + + if bcx.sess().trace() { + trans_trace( + bcx, None, + @fmt!("preserving until end of scope %d", + root_info.scope)); + } + + // First, root the datum. Note that we must zero this value, + // because sometimes we root on one path but not another. + // See e.g. #4904. + let scratch = scratch_datum(bcx, datum.ty, true); + datum.copy_to_datum(bcx, INIT, scratch); + let cleanup_bcx = find_bcx_for_scope(bcx, root_info.scope); + add_clean_temp_mem(cleanup_bcx, scratch.val, scratch.ty); + + // Now, consider also freezing it. + match root_info.freeze { + None => {} + Some(freeze_kind) => { + let (filename, line) = filename_and_line_num_from_span(bcx, span); + + // in this case, we don't have to zero, because + // scratch.val will be NULL should the cleanup get + // called without the freezing actually occurring, and + // return_to_mut checks for this condition. + let scratch_bits = scratch_datum(bcx, ty::mk_uint(), false); + + let freeze_did = match freeze_kind { + DynaImm => bcx.tcx().lang_items.borrow_as_imm_fn(), + DynaMut => bcx.tcx().lang_items.borrow_as_mut_fn(), + }; + + let box_ptr = Load(bcx, + PointerCast(bcx, + scratch.val, + T_ptr(T_ptr(T_i8())))); + + bcx = callee::trans_lang_call( + bcx, + freeze_did, + ~[ + box_ptr, + filename, + line + ], + expr::SaveIn(scratch_bits.val)); + + if bcx.tcx().sess.opts.optimize == session::No { + bcx = callee::trans_lang_call( + bcx, + bcx.tcx().lang_items.record_borrow_fn(), + ~[ + box_ptr, + Load(bcx, scratch_bits.val), + filename, + line + ], + expr::Ignore); + } + + add_clean_return_to_mut( + cleanup_bcx, root_key, scratch.val, scratch_bits.val, + filename, line); + } + } + + bcx +} + +fn perform_write_guard(datum: &Datum, + bcx: block, + span: span) -> block { + debug!("perform_write_guard"); + + let llval = datum.to_value_llval(bcx); + let (filename, line) = filename_and_line_num_from_span(bcx, span); + + callee::trans_lang_call( + bcx, + bcx.tcx().lang_items.check_not_borrowed_fn(), + ~[PointerCast(bcx, llval, T_ptr(T_i8())), + filename, + line], + expr::Ignore) +} + From 7ac657116343c599806e733c2caf896681ab3bd1 Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Sat, 4 May 2013 16:00:11 +0900 Subject: [PATCH 189/215] rt: glob, globfree dummy function for android --- src/rt/rust_android_dummy.cpp | 15 +++++++++++++-- src/rt/rust_android_dummy.h | 23 +++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/rt/rust_android_dummy.cpp b/src/rt/rust_android_dummy.cpp index 3c7034a2f9561..0032e9c6e7fea 100644 --- a/src/rt/rust_android_dummy.cpp +++ b/src/rt/rust_android_dummy.cpp @@ -2,12 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#ifdef __ANDROID__ + #include "rust_android_dummy.h" #include #include -#ifdef __ANDROID__ - int backtrace(void **array, int size) { return 0; } char **backtrace_symbols(void *const *array, int size) { return 0; } @@ -59,7 +59,18 @@ extern "C" void srand() extern "C" void atof() { } + extern "C" void tgammaf() { } + +extern "C" int glob(const char *pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *pglob) +{ + return 0; +} + +extern "C" void globfree(glob_t *pglob) +{ +} + #endif diff --git a/src/rt/rust_android_dummy.h b/src/rt/rust_android_dummy.h index 95a1774894bc5..a7c63035c00dc 100644 --- a/src/rt/rust_android_dummy.h +++ b/src/rt/rust_android_dummy.h @@ -11,5 +11,28 @@ char **backtrace_symbols (void *__const *__array, int __size); void backtrace_symbols_fd (void *__const *__array, int __size, int __fd); +#include + +struct stat; +typedef struct { + size_t gl_pathc; /* Count of total paths so far. */ + size_t gl_matchc; /* Count of paths matching pattern. */ + size_t gl_offs; /* Reserved at beginning of gl_pathv. */ + int gl_flags; /* Copy of flags parameter to glob. */ + char **gl_pathv; /* List of paths matching pattern. */ + /* Copy of errfunc parameter to glob. */ + int (*gl_errfunc)(const char *, int); + + /* + * Alternate filesystem access methods for glob; replacement + * versions of closedir(3), readdir(3), opendir(3), stat(2) + * and lstat(2). + */ + void (*gl_closedir)(void *); + struct dirent *(*gl_readdir)(void *); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, struct stat *); +} glob_t; + #endif From 495bceb9b0df3cc98cfd0fc041a9eb87edba5025 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 4 May 2013 10:57:56 +0200 Subject: [PATCH 190/215] Fix syntax: had to use escaped $$ to have an effect after first expansion. --- mk/host.mk | 2 +- mk/target.mk | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mk/host.mk b/mk/host.mk index 54e7e7ca09609..e67aa27e56c56 100644 --- a/mk/host.mk +++ b/mk/host.mk @@ -128,7 +128,7 @@ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)): \ $$(Q)cp $$< $$@ $$(HBIN$(2)_H_$(4))/: - mkdir -p $@ + mkdir -p $$@ endef diff --git a/mk/target.mk b/mk/target.mk index a3e5a5caff107..4bcb1004a08d9 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -84,7 +84,7 @@ endif endif $$(TLIB$(1)_T_$(2)_H_$(3))/: - mkdir -p $@ + mkdir -p $$@ endef From 175a5eea420af5f23c356da7def52d82903bceed Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Sat, 4 May 2013 12:46:11 +0200 Subject: [PATCH 191/215] Fix another goof: consistently use parent directory of target for rule. (I wonder if there's a better way to write this in the rule itself; i.e. something like `$$(dirname $$@)`. But for now this will do.) --- mk/host.mk | 21 ++++++++++++--------- mk/target.mk | 5 ++++- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/mk/host.mk b/mk/host.mk index e67aa27e56c56..0c00a7e1d6469 100644 --- a/mk/host.mk +++ b/mk/host.mk @@ -42,7 +42,7 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBRUSTC_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \ $$(HCORELIB_DEFAULT$(2)_H_$(4)) \ $$(HSTDLIB_DEFAULT$(2)_H_$(4)) \ - | $$(HBIN$(2)_H_$(4))/ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ @@ -56,7 +56,7 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)) \ $$(HCORELIB_DEFAULT$(2)_H_$(4)) \ $$(HSTDLIB_DEFAULT$(2)_H_$(4)) \ - | $$(HBIN$(2)_H_$(4))/ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(LIBSYNTAX_GLOB_$(4)) \ @@ -65,14 +65,14 @@ $$(HLIB$(2)_H_$(4))/$(CFG_LIBSYNTAX_$(4)): \ $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)): \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUNTIME_$(4)) \ - | $$(HBIN$(2)_H_$(4))/ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)): \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_CORELIB_$(4)) \ $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \ - | $$(HBIN$(2)_H_$(4))/ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ # Subtle: We do not let the shell expand $(CORELIB_DSYM_GLOB) directly rather @@ -90,7 +90,7 @@ $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_STDLIB_$(4)) \ $$(HLIB$(2)_H_$(4))/$(CFG_CORELIB_$(4)) \ $$(HLIB$(2)_H_$(4))/$(CFG_RUNTIME_$(4)) \ - | $$(HBIN$(2)_H_$(4))/ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(Q)cp -R $$(TLIB$(1)_T_$(4)_H_$(3))/$(STDLIB_GLOB_$(4)) \ @@ -100,7 +100,7 @@ $$(HLIB$(2)_H_$(4))/$(CFG_STDLIB_$(4)): \ $$(HLIB$(2)_H_$(4))/libcore.rlib: \ $$(TLIB$(1)_T_$(4)_H_$(3))/libcore.rlib \ $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \ - | $$(HBIN$(2)_H_$(4))/ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ @@ -108,7 +108,7 @@ $$(HLIB$(2)_H_$(4))/libstd.rlib: \ $$(TLIB$(1)_T_$(4)_H_$(3))/libstd.rlib \ $$(HLIB$(2)_H_$(4))/libcore.rlib \ $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \ - | $$(HBIN$(2)_H_$(4))/ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ @@ -117,19 +117,22 @@ $$(HLIB$(2)_H_$(4))/librustc.rlib: \ $$(HLIB$(2)_H_$(4))/libcore.rlib \ $$(HLIB$(2)_H_$(4))/libstd.rlib \ $$(HLIB$(2)_H_$(4))/$$(CFG_RUNTIME_$(4)) \ - | $$(HBIN$(2)_H_$(4))/ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(HLIB$(2)_H_$(4))/$(CFG_RUSTLLVM_$(4)): \ $$(TLIB$(1)_T_$(4)_H_$(3))/$(CFG_RUSTLLVM_$(4)) \ - | $$(HBIN$(2)_H_$(4))/ + | $$(HLIB$(2)_H_$(4))/ @$$(call E, cp: $$@) $$(Q)cp $$< $$@ $$(HBIN$(2)_H_$(4))/: mkdir -p $$@ +$$(HLIB$(2)_H_$(4))/: + mkdir -p $$@ + endef $(foreach t,$(CFG_HOST_TRIPLES), \ diff --git a/mk/target.mk b/mk/target.mk index 4bcb1004a08d9..2223531c3ec5e 100644 --- a/mk/target.mk +++ b/mk/target.mk @@ -73,7 +73,7 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)): \ $$(TBIN$(1)_T_$(2)_H_$(3))/rustc$$(X_$(3)): \ $$(DRIVER_CRATE) \ $$(TLIB$(1)_T_$(2)_H_$(3))/$(CFG_LIBRUSTC_$(3)) \ - | $$(TLIB$(1)_T_$(2)_H_$(3))/ + | $$(TBIN$(1)_T_$(2)_H_$(3))/ @$$(call E, compile_and_link: $$@) $$(STAGE$(1)_T_$(2)_H_$(3)) --cfg rustc -o $$@ $$< ifdef CFG_ENABLE_PAX_FLAGS @@ -83,6 +83,9 @@ endif endif +$$(TBIN$(1)_T_$(2)_H_$(3))/: + mkdir -p $$@ + $$(TLIB$(1)_T_$(2)_H_$(3))/: mkdir -p $$@ From e5ca35d567e7d243c81d8c41fa0e7268ae8df58f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Steinbrink?= Date: Sat, 4 May 2013 18:21:27 +0200 Subject: [PATCH 192/215] Reduce code bloat from managed allocations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit d7f5e43 "core::rt: Add the local heap to newsched tasks", local_malloc and local_free have become rather big and their forced inlining causes quite a bit of code bloat. Compile times for crates affected by the bloat (e.g. rustc) improve, while others (e.g. libstd) seem to be unaffected, so I guess the inlining doesn't gain us much. Sizes: | librustc | libsytax ---------------|–-----------|------------ with inlining | 18,547,824 | 7,110,848 w/o inlining | 15,092,040 | 5,518,608 --- src/libcore/unstable/lang.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 7cd218639c0a6..460285bfcfda0 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -98,7 +98,6 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { } #[lang="malloc"] -#[inline(always)] #[cfg(not(stage0))] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { match context() { @@ -129,7 +128,6 @@ pub unsafe fn local_free(ptr: *c_char) { // inside a landing pad may corrupt the state of the exception handler. If a // problem occurs, call exit instead. #[lang="free"] -#[inline(always)] #[cfg(not(stage0))] pub unsafe fn local_free(ptr: *c_char) { match context() { From bf2d3c71e37d3b7aabe57a3d9ea3fada449715c1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 4 May 2013 14:25:15 -0400 Subject: [PATCH 193/215] improve DEBUG_BORROW printouts --- src/libcore/cleanup.rs | 17 +++-- src/libcore/rt/env.rs | 2 + src/libcore/unstable/lang.rs | 139 ++++++++++++++++++++++++----------- src/rt/rust_env.cpp | 2 + src/rt/rust_env.h | 1 + 5 files changed, 109 insertions(+), 52 deletions(-) diff --git a/src/libcore/cleanup.rs b/src/libcore/cleanup.rs index 5e2f4af184dc4..3f7366c6c452b 100644 --- a/src/libcore/cleanup.rs +++ b/src/libcore/cleanup.rs @@ -167,7 +167,8 @@ fn debug_mem() -> bool { #[cfg(notest)] #[lang="annihilate"] pub unsafe fn annihilate() { - use unstable::lang::{local_free, debug_ptr}; + use unstable::lang::{local_free}; + use unstable::lang; use io::WriterUtil; use io; use libc; @@ -191,10 +192,10 @@ pub unsafe fn annihilate() { for each_live_alloc(true) |box, uniq| { stats.n_total_boxes += 1; if uniq { - debug_ptr("Managed-uniq: ", &*box); + lang::debug_mem("Managed-uniq: ", &*box); stats.n_unique_boxes += 1; } else { - debug_ptr("Immortalizing: ", &*box); + lang::debug_mem("Immortalizing: ", &*box); (*box).header.ref_count = managed::raw::RC_IMMORTAL; } } @@ -206,13 +207,13 @@ pub unsafe fn annihilate() { // callback, as the original value may have been freed. for each_live_alloc(false) |box, uniq| { if !uniq { - debug_ptr("Invoking tydesc/glue on: ", &*box); + lang::debug_mem("Invoking tydesc/glue on: ", &*box); let tydesc: *TypeDesc = transmute(copy (*box).header.type_desc); let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0)); - debug_ptr("Box data: ", &(*box).data); - debug_ptr("Type descriptor: ", tydesc); + lang::debug_mem("Box data: ", &(*box).data); + lang::debug_mem("Type descriptor: ", tydesc); drop_glue(to_unsafe_ptr(&tydesc), transmute(&(*box).data)); - debug_ptr("Dropped ", &*box); + lang::debug_mem("Dropped ", &*box); } } @@ -224,7 +225,7 @@ pub unsafe fn annihilate() { // not be valid after. for each_live_alloc(true) |box, uniq| { if !uniq { - debug_ptr("About to free: ", &*box); + lang::debug_mem("About to free: ", &*box); stats.n_bytes_freed += (*((*box).header.type_desc)).size + sys::size_of::(); diff --git a/src/libcore/rt/env.rs b/src/libcore/rt/env.rs index e479375401a3b..1d7ff17314901 100644 --- a/src/libcore/rt/env.rs +++ b/src/libcore/rt/env.rs @@ -33,6 +33,8 @@ pub struct Environment { argv: **c_char, /// Print GC debugging info (true if env var RUST_DEBUG_MEM is set) debug_mem: bool, + /// Print GC debugging info (true if env var RUST_DEBUG_BORROW is set) + debug_borrow: bool, } /// Get the global environment settings diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 01ab2345918b1..5a65a5c24bb57 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -20,6 +20,7 @@ use unstable::exchange_alloc; use cast::transmute; use task::rt::rust_get_task; use option::{Option, Some, None}; +use io; #[allow(non_camel_case_types)] pub type rust_task = c_void; @@ -109,8 +110,8 @@ pub unsafe fn clear_task_borrow_list() { let _ = try_take_task_borrow_list(); } -fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { - debug_ptr("fail_borrowed: ", box); +unsafe fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { + debug_borrow("fail_borrowed: ", box, 0, 0, file, line); match try_take_task_borrow_list() { None => { // not recording borrows @@ -145,42 +146,95 @@ fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { #[inline(always)] pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { let result = transmute(exchange_alloc::malloc(transmute(td), transmute(size))); - debug_ptr("exchange_malloc: ", result); + debug_mem("exchange_malloc: ", result); return result; } /// Because this code is so perf. sensitive, use a static constant so that /// debug printouts are compiled out most of the time. -static ENABLE_DEBUG_PTR: bool = true; +static ENABLE_DEBUG: bool = true; #[inline] -pub fn debug_ptr(tag: &'static str, p: *const T) { +pub fn debug_mem(tag: &'static str, p: *const T) { //! A useful debugging function that prints a pointer + tag + newline //! without allocating memory. - if ENABLE_DEBUG_PTR && ::rt::env::get().debug_mem { - debug_ptr_slow(tag, p); + if ENABLE_DEBUG && ::rt::env::get().debug_mem { + debug_mem_slow(tag, p); } - fn debug_ptr_slow(tag: &'static str, p: *const T) { - use io; + fn debug_mem_slow(tag: &'static str, p: *const T) { let dbg = STDERR_FILENO as io::fd_t; - let letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', - '9', 'a', 'b', 'c', 'd', 'e', 'f']; dbg.write_str(tag); + dbg.write_hex(p as uint); + dbg.write_str("\n"); + } +} + +#[inline] +unsafe fn debug_borrow(tag: &'static str, + p: *const T, + old_bits: uint, + new_bits: uint, + filename: *c_char, + line: size_t) { + //! A useful debugging function that prints a pointer + tag + newline + //! without allocating memory. + + if ENABLE_DEBUG && ::rt::env::get().debug_borrow { + debug_borrow_slow(tag, p, old_bits, new_bits, filename, line); + } + + unsafe fn debug_borrow_slow(tag: &'static str, + p: *const T, + old_bits: uint, + new_bits: uint, + filename: *c_char, + line: size_t) { + let dbg = STDERR_FILENO as io::fd_t; + dbg.write_str(tag); + dbg.write_hex(p as uint); + dbg.write_str(" "); + dbg.write_hex(old_bits); + dbg.write_str(" "); + dbg.write_hex(new_bits); + dbg.write_str(" "); + dbg.write_cstr(filename); + dbg.write_str(":"); + dbg.write_hex(line as uint); + dbg.write_str("\n"); + } +} + +trait DebugPrints { + fn write_hex(&self, val: uint); + unsafe fn write_cstr(&self, str: *c_char); +} +impl DebugPrints for io::fd_t { + fn write_hex(&self, mut i: uint) { + let letters = ['0', '1', '2', '3', '4', '5', '6', '7', '8', + '9', 'a', 'b', 'c', 'd', 'e', 'f']; static uint_nibbles: uint = ::uint::bytes << 1; let mut buffer = [0_u8, ..uint_nibbles+1]; - let mut i = p as uint; let mut c = uint_nibbles; while c > 0 { c -= 1; buffer[c] = letters[i & 0xF] as u8; i >>= 4; } - dbg.write(buffer.slice(0, uint_nibbles)); + self.write(buffer.slice(0, uint_nibbles)); + } - dbg.write_str("\n"); + unsafe fn write_cstr(&self, p: *c_char) { + use libc::strlen; + use vec; + + let len = strlen(p); + let p: *u8 = transmute(p); + do vec::raw::buf_as_slice(p, len as uint) |s| { + self.write(s); + } } } @@ -190,7 +244,7 @@ pub fn debug_ptr(tag: &'static str, p: *const T) { #[lang="exchange_free"] #[inline(always)] pub unsafe fn exchange_free(ptr: *c_char) { - debug_ptr("exchange_free: ", ptr); + debug_mem("exchange_free: ", ptr); exchange_alloc::free(transmute(ptr)) } @@ -198,7 +252,7 @@ pub unsafe fn exchange_free(ptr: *c_char) { #[inline(always)] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { let result = rustrt::rust_upcall_malloc_noswitch(td, size); - debug_ptr("local_malloc: ", result); + debug_mem("local_malloc: ", result); return result; } @@ -208,7 +262,7 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { #[lang="free"] #[inline(always)] pub unsafe fn local_free(ptr: *c_char) { - debug_ptr("local_free: ", ptr); + debug_mem("local_free: ", ptr); rustrt::rust_upcall_free_noswitch(ptr); } @@ -225,19 +279,18 @@ pub unsafe fn borrow_as_imm(a: *u8) { #[inline(always)] pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { let a: *mut BoxRepr = transmute(a); - let ref_count = (*a).header.ref_count; + let old_ref_count = (*a).header.ref_count; + let new_ref_count = old_ref_count | FROZEN_BIT; - debug_ptr("borrow_as_imm (ptr) :", a); - debug_ptr(" (ref) :", ref_count as *()); - debug_ptr(" (line): ", line as *()); + debug_borrow("borrow_as_imm:", a, old_ref_count, new_ref_count, file, line); - if (ref_count & MUT_BIT) != 0 { + if (old_ref_count & MUT_BIT) != 0 { fail_borrowed(a, file, line); } - (*a).header.ref_count = ref_count | FROZEN_BIT; + (*a).header.ref_count = new_ref_count; - ref_count + old_ref_count } #[cfg(not(stage0))] @@ -245,18 +298,18 @@ pub unsafe fn borrow_as_imm(a: *u8, file: *c_char, line: size_t) -> uint { #[inline(always)] pub unsafe fn borrow_as_mut(a: *u8, file: *c_char, line: size_t) -> uint { let a: *mut BoxRepr = transmute(a); + let old_ref_count = (*a).header.ref_count; + let new_ref_count = old_ref_count | MUT_BIT | FROZEN_BIT; - debug_ptr("borrow_as_mut (ptr): ", a); - debug_ptr(" (line): ", line as *()); + debug_borrow("borrow_as_mut:", a, old_ref_count, new_ref_count, file, line); - let ref_count = (*a).header.ref_count; - if (ref_count & (MUT_BIT|FROZEN_BIT)) != 0 { + if (old_ref_count & (MUT_BIT|FROZEN_BIT)) != 0 { fail_borrowed(a, file, line); } - (*a).header.ref_count = ref_count | MUT_BIT | FROZEN_BIT; + (*a).header.ref_count = new_ref_count; - ref_count + old_ref_count } @@ -267,6 +320,7 @@ pub unsafe fn record_borrow(a: *u8, old_ref_count: uint, if (old_ref_count & ALL_BITS) == 0 { // was not borrowed before let a: *mut BoxRepr = transmute(a); + debug_borrow("record_borrow:", a, old_ref_count, 0, file, line); do swap_task_borrow_list |borrow_list| { let mut borrow_list = borrow_list; borrow_list.push(BorrowRecord {box: a, file: file, line: line}); @@ -282,6 +336,7 @@ pub unsafe fn unrecord_borrow(a: *u8, old_ref_count: uint, if (old_ref_count & ALL_BITS) == 0 { // was not borrowed before let a: *mut BoxRepr = transmute(a); + debug_borrow("unrecord_borrow:", a, old_ref_count, 0, file, line); do swap_task_borrow_list |borrow_list| { let mut borrow_list = borrow_list; let br = BorrowRecord {box: a, file: file, line: line}; @@ -317,21 +372,20 @@ pub unsafe fn return_to_mut(a: *u8) { #[cfg(not(stage0))] #[lang="return_to_mut"] #[inline(always)] -pub unsafe fn return_to_mut(a: *u8, old_ref_count: uint, +pub unsafe fn return_to_mut(a: *u8, orig_ref_count: uint, file: *c_char, line: size_t) { // Sometimes the box is null, if it is conditionally frozen. // See e.g. #4904. if !a.is_null() { let a: *mut BoxRepr = transmute(a); - let ref_count = (*a).header.ref_count; - let combined = (ref_count & !ALL_BITS) | (old_ref_count & ALL_BITS); - (*a).header.ref_count = combined; - - debug_ptr("return_to_mut (ptr) : ", a); - debug_ptr(" (line): ", line as *()); - debug_ptr(" (old) : ", old_ref_count as *()); - debug_ptr(" (new) : ", ref_count as *()); - debug_ptr(" (comb): ", combined as *()); + let old_ref_count = (*a).header.ref_count; + let new_ref_count = + (old_ref_count & !ALL_BITS) | (orig_ref_count & ALL_BITS); + + debug_borrow("return_to_mut:", + a, old_ref_count, new_ref_count, file, line); + + (*a).header.ref_count = new_ref_count; } } @@ -355,10 +409,7 @@ pub unsafe fn check_not_borrowed(a: *u8, line: size_t) { let a: *mut BoxRepr = transmute(a); let ref_count = (*a).header.ref_count; - debug_ptr("check_not_borrowed (ptr) : ", a); - debug_ptr(" (line): ", line as *()); - debug_ptr(" (rc) : ", ref_count as *()); - + debug_borrow("check_not_borrowed:", a, ref_count, 0, file, line); if (ref_count & FROZEN_BIT) != 0 { fail_borrowed(a, file, line); } diff --git a/src/rt/rust_env.cpp b/src/rt/rust_env.cpp index 041b4efac52a2..360d611492853 100644 --- a/src/rt/rust_env.cpp +++ b/src/rt/rust_env.cpp @@ -24,6 +24,7 @@ #define RUST_SEED "RUST_SEED" #define RUST_POISON_ON_FREE "RUST_POISON_ON_FREE" #define RUST_DEBUG_MEM "RUST_DEBUG_MEM" +#define RUST_DEBUG_BORROW "RUST_DEBUG_BORROW" #if defined(__WIN32__) static int @@ -130,6 +131,7 @@ load_env(int argc, char **argv) { env->argc = argc; env->argv = argv; env->debug_mem = getenv(RUST_DEBUG_MEM) != NULL; + env->debug_borrow = getenv(RUST_DEBUG_BORROW) != NULL; return env; } diff --git a/src/rt/rust_env.h b/src/rt/rust_env.h index df27f7674f265..b897f0c09a90b 100644 --- a/src/rt/rust_env.h +++ b/src/rt/rust_env.h @@ -28,6 +28,7 @@ struct rust_env { int argc; char **argv; rust_bool debug_mem; + rust_bool debug_borrow; }; rust_env* load_env(int argc, char **argv); From ccf2f7b979ad4e4defd9b856f6d16108c5760829 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 4 May 2013 14:29:08 -0400 Subject: [PATCH 194/215] make asm_comments something that you opt in to --- src/librustc/driver/driver.rs | 5 ----- src/librustc/driver/session.rs | 6 +++--- src/librustc/middle/borrowck/check_loans.rs | 2 +- src/librustc/middle/mem_categorization.rs | 1 - src/librustc/middle/trans/base.rs | 2 +- src/librustc/middle/trans/build.rs | 4 ++-- src/librustc/middle/trans/closure.rs | 2 +- 7 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index e899b1abc2648..6ce62a1382d3d 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -600,11 +600,6 @@ pub fn build_session_options(binary: @~str, let target_opt = getopts::opt_maybe_str(matches, ~"target"); let target_feature_opt = getopts::opt_maybe_str(matches, ~"target-feature"); let save_temps = getopts::opt_present(matches, ~"save-temps"); - match output_type { - // unless we're emitting huamn-readable assembly, omit comments. - link::output_type_llvm_assembly | link::output_type_assembly => (), - _ => debugging_opts |= session::no_asm_comments - } let opt_level = { if (debugging_opts & session::no_opt) != 0 { No diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index fff97d2436af3..15067b785d9ca 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -45,7 +45,7 @@ pub static time_passes: uint = 1 << 1; pub static count_llvm_insns: uint = 1 << 2; pub static time_llvm_passes: uint = 1 << 3; pub static trans_stats: uint = 1 << 4; -pub static no_asm_comments: uint = 1 << 5; +pub static asm_comments: uint = 1 << 5; pub static no_verify: uint = 1 << 6; pub static trace: uint = 1 << 7; pub static coherence: uint = 1 << 8; @@ -72,7 +72,7 @@ pub fn debugging_opts_map() -> ~[(~str, ~str, uint)] { (~"time-llvm-passes", ~"measure time of each LLVM pass", time_llvm_passes), (~"trans-stats", ~"gather trans statistics", trans_stats), - (~"no-asm-comments", ~"omit comments when using -S", no_asm_comments), + (~"asm-comments", ~"generate comments into the assembly (may change behavior)", asm_comments), (~"no-verify", ~"skip LLVM verification", no_verify), (~"trace", ~"emit trace logs", trace), (~"coherence", ~"perform coherence checking", coherence), @@ -267,7 +267,7 @@ pub impl Session_ { } fn trans_stats(@self) -> bool { self.debugging_opt(trans_stats) } fn meta_stats(@self) -> bool { self.debugging_opt(meta_stats) } - fn no_asm_comments(@self) -> bool { self.debugging_opt(no_asm_comments) } + fn asm_comments(@self) -> bool { self.debugging_opt(asm_comments) } fn no_verify(@self) -> bool { self.debugging_opt(no_verify) } fn trace(@self) -> bool { self.debugging_opt(trace) } fn coherence(@self) -> bool { self.debugging_opt(coherence) } diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index c2dc2fb22ab5b..25d57662c6e07 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -374,7 +374,7 @@ pub impl<'self> CheckLoanCtxt<'self> { } } - mc::cat_deref(base, deref_count, mc::gc_ptr(ast::m_mutbl)) => { + mc::cat_deref(_, deref_count, mc::gc_ptr(ast::m_mutbl)) => { // Dynamically check writes to `@mut` let key = root_map_key { diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index f1c337125d704..2e5e53654a455 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -378,7 +378,6 @@ pub impl mem_categorization_ctxt { debug!("cat_expr: id=%d expr=%s", expr.id, pprust::expr_to_str(expr, self.tcx.sess.intr())); - let tcx = self.tcx; let expr_ty = self.expr_ty(expr); match expr.node { ast::expr_unary(ast::deref, e_base) => { diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 8a21d9116f5e6..47363aa9263f2 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -1133,7 +1133,7 @@ pub fn trans_stmt(cx: block, s: &ast::stmt) -> block { let _icx = cx.insn_ctxt("trans_stmt"); debug!("trans_stmt(%s)", stmt_to_str(s, cx.tcx().sess.intr())); - if !cx.sess().no_asm_comments() { + if cx.sess().asm_comments() { add_span_comment(cx, s.span, stmt_to_str(s, cx.ccx().sess.intr())); } diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index f5c496484a037..a9ed80d1eaaf7 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -846,7 +846,7 @@ pub fn _UndefReturn(cx: block, Fn: ValueRef) -> ValueRef { pub fn add_span_comment(bcx: block, sp: span, text: &str) { let ccx = bcx.ccx(); - if !ccx.sess.no_asm_comments() { + if ccx.sess.asm_comments() { let s = fmt!("%s (%s)", text, ccx.sess.codemap.span_to_str(sp)); debug!("%s", copy s); add_comment(bcx, s); @@ -856,7 +856,7 @@ pub fn add_span_comment(bcx: block, sp: span, text: &str) { pub fn add_comment(bcx: block, text: &str) { unsafe { let ccx = bcx.ccx(); - if !ccx.sess.no_asm_comments() { + if ccx.sess.asm_comments() { let sanitized = str::replace(text, ~"$", ~""); let comment_text = ~"# " + str::replace(sanitized, ~"\n", ~"\n\t# "); diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index e35fef6b6f66a..acd52907b9f73 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -224,7 +224,7 @@ pub fn store_environment(bcx: block, for vec::eachi(bound_values) |i, bv| { debug!("Copy %s into closure", bv.to_str(ccx)); - if !ccx.sess.no_asm_comments() { + if ccx.sess.asm_comments() { add_comment(bcx, fmt!("Copy %s into closure", bv.to_str(ccx))); } From 989d008124d62f7c1284633e6619db1a9e8b6598 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 4 May 2013 14:29:32 -0400 Subject: [PATCH 195/215] separate out write_guard code into its own module --- Makefile.in | 3 + src/librustc/middle/trans/_match.rs | 23 +--- src/librustc/middle/trans/common.rs | 58 +++------ src/librustc/middle/trans/controlflow.rs | 8 +- src/librustc/middle/trans/datum.rs | 152 ++--------------------- src/librustc/rustc.rc | 1 + 6 files changed, 41 insertions(+), 204 deletions(-) diff --git a/Makefile.in b/Makefile.in index dd2e6a95861bd..111ad1369deb9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -110,6 +110,9 @@ endif ifdef SAVE_TEMPS CFG_RUSTC_FLAGS += --save-temps endif +ifdef ASM_COMMENTS + CFG_RUSTC_FLAGS += -z asm-comments +endif ifdef TIME_PASSES CFG_RUSTC_FLAGS += -Z time-passes endif diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 3b1cdf0ba47f7..1a81d483dfc3c 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -969,30 +969,17 @@ pub fn pats_require_rooting(bcx: block, }) } -pub fn root_pats_as_necessary(bcx: block, +pub fn root_pats_as_necessary(mut bcx: block, m: &[@Match], col: uint, val: ValueRef) -> block { - let mut bcx = bcx; for vec::each(m) |br| { let pat_id = br.pats[col].id; - - let key = root_map_key {id: pat_id, derefs: 0u }; - match bcx.ccx().maps.root_map.find(&key) { - None => (), - Some(&root_info) => { - // Note: the scope_id will always be the id of the match. See - // the extended comment in rustc::middle::borrowck::preserve() - // for details (look for the case covering cat_discr). - - let datum = Datum {val: val, ty: node_id_type(bcx, pat_id), - mode: ByRef, source: ZeroMem}; - bcx = datum.root(bcx, br.pats[col].span, key, root_info); - // If we kept going, we'd only re-root the same value, so - // return now. - return bcx; - } + if pat_id != 0 { + let datum = Datum {val: val, ty: node_id_type(bcx, pat_id), + mode: ByRef, source: ZeroMem}; + bcx = datum.root_and_write_guard(bcx, br.pats[col].span, pat_id, 0); } } return bcx; diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs index 2a13cf73f8bba..f8b75838b8726 100644 --- a/src/librustc/middle/trans/common.rs +++ b/src/librustc/middle/trans/common.rs @@ -27,18 +27,18 @@ use middle::resolve; use middle::trans::adt; use middle::trans::base; use middle::trans::build; -use middle::trans::callee; use middle::trans::datum; use middle::trans::debuginfo; -use middle::trans::expr; use middle::trans::glue; use middle::trans::reachable; use middle::trans::shape; use middle::trans::type_of; use middle::trans::type_use; +use middle::trans::write_guard; use middle::ty::substs; use middle::ty; use middle::typeck; +use middle::borrowck::root_map_key; use util::ppaux::{Repr}; use core::cast::transmute; @@ -468,6 +468,7 @@ pub fn add_clean_temp_mem(bcx: block, val: ValueRef, t: ty::t) { } } pub fn add_clean_return_to_mut(bcx: block, + root_key: root_map_key, frozen_val_ref: ValueRef, bits_val_ref: ValueRef, filename_val: ValueRef, @@ -488,44 +489,12 @@ pub fn add_clean_return_to_mut(bcx: block, scope_info.cleanups.push( clean_temp( frozen_val_ref, - |bcx| { - let mut bcx = bcx; - - let box_ptr = - build::Load(bcx, - build::PointerCast(bcx, - frozen_val_ref, - T_ptr(T_ptr(T_i8())))); - - let bits_val = - build::Load(bcx, - bits_val_ref); - - if bcx.tcx().sess.opts.optimize == session::No { - bcx = callee::trans_lang_call( - bcx, - bcx.tcx().lang_items.unrecord_borrow_fn(), - ~[ - box_ptr, - bits_val, - filename_val, - line_val - ], - expr::Ignore); - } - - callee::trans_lang_call( - bcx, - bcx.tcx().lang_items.return_to_mut_fn(), - ~[ - box_ptr, - bits_val, - filename_val, - line_val - ], - expr::Ignore - ) - }, + |bcx| write_guard::return_to_mut(bcx, + root_key, + frozen_val_ref, + bits_val_ref, + filename_val, + line_val), normal_exit_only)); scope_clean_changed(scope_info); } @@ -1563,6 +1532,15 @@ pub fn dummy_substs(tps: ~[ty::t]) -> ty::substs { } } +pub fn filename_and_line_num_from_span(bcx: block, + span: span) -> (ValueRef, ValueRef) { + let loc = bcx.sess().parse_sess.cm.lookup_char_pos(span.lo); + let filename_cstr = C_cstr(bcx.ccx(), @/*bad*/copy loc.file.name); + let filename = build::PointerCast(bcx, filename_cstr, T_ptr(T_i8())); + let line = C_int(bcx.ccx(), loc.line as int); + (filename, line) +} + // Casts a Rust bool value to an i1. pub fn bool_to_i1(bcx: block, llval: ValueRef) -> ValueRef { build::ICmp(bcx, lib::llvm::IntNE, llval, C_bool(false)) diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index c8699cc6371bc..e91bec5efed4a 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -385,13 +385,7 @@ fn trans_fail_value(bcx: block, pub fn trans_fail_bounds_check(bcx: block, sp: span, index: ValueRef, len: ValueRef) -> block { let _icx = bcx.insn_ctxt("trans_fail_bounds_check"); - let ccx = bcx.ccx(); - - let loc = bcx.sess().parse_sess.cm.lookup_char_pos(sp.lo); - let line = C_int(ccx, loc.line as int); - let filename_cstr = C_cstr(bcx.ccx(), @/*bad*/copy loc.file.name); - let filename = PointerCast(bcx, filename_cstr, T_ptr(T_i8())); - + let (filename, line) = filename_and_line_num_from_span(bcx, sp); let args = ~[filename, line, index, len]; let bcx = callee::trans_lang_call( bcx, bcx.tcx().lang_items.fail_bounds_check_fn(), args, expr::Ignore); diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 6ffe504b804fb..d4ca0f3c4bed2 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -87,21 +87,19 @@ use lib; use lib::llvm::ValueRef; -use middle::borrowck::{RootInfo, root_map_key, DynaImm, DynaMut}; use middle::trans::adt; use middle::trans::base::*; use middle::trans::build::*; -use middle::trans::callee; use middle::trans::common::*; use middle::trans::common; use middle::trans::expr; use middle::trans::glue; use middle::trans::tvec; use middle::trans::type_of; +use middle::trans::write_guard; use middle::ty; use util::common::indenter; use util::ppaux::ty_to_str; -use driver::session; use core::container::Set; // XXX: this should not be necessary use core::to_bytes; @@ -518,113 +516,6 @@ pub impl Datum { } } - fn root(&self, mut bcx: block, span: span, - root_key: root_map_key, root_info: RootInfo) -> block { - /*! - * - * In some cases, borrowck will decide that an @T/@[]/@str - * value must be rooted for the program to be safe. In that - * case, we will call this function, which will stash a copy - * away until we exit the scope `scope_id`. */ - - debug!("root(root_map_key=%?, root_info=%?, self=%?)", - root_key, root_info, self.to_str(bcx.ccx())); - - if bcx.sess().trace() { - trans_trace( - bcx, None, - @fmt!("preserving until end of scope %d", - root_info.scope)); - } - - // First, root the datum. Note that we must zero this value, - // because sometimes we root on one path but not another. - // See e.g. #4904. - let scratch = scratch_datum(bcx, self.ty, true); - self.copy_to_datum(bcx, INIT, scratch); - let cleanup_bcx = find_bcx_for_scope(bcx, root_info.scope); - add_clean_temp_mem(cleanup_bcx, scratch.val, scratch.ty); - - // Now, consider also freezing it. - match root_info.freeze { - None => {} - Some(freeze_kind) => { - let loc = bcx.sess().parse_sess.cm.lookup_char_pos(span.lo); - let line = C_int(bcx.ccx(), loc.line as int); - let filename_cstr = C_cstr(bcx.ccx(), @/*bad*/copy loc.file.name); - let filename = PointerCast(bcx, filename_cstr, T_ptr(T_i8())); - - // in this case, we don't have to zero, because - // scratch.val will be NULL should the cleanup get - // called without the freezing actually occurring, and - // return_to_mut checks for this condition. - let scratch_bits = scratch_datum(bcx, ty::mk_uint(), false); - - let freeze_did = match freeze_kind { - DynaImm => bcx.tcx().lang_items.borrow_as_imm_fn(), - DynaMut => bcx.tcx().lang_items.borrow_as_mut_fn(), - }; - - let box_ptr = Load(bcx, - PointerCast(bcx, - scratch.val, - T_ptr(T_ptr(T_i8())))); - - bcx = callee::trans_lang_call( - bcx, - freeze_did, - ~[ - box_ptr, - filename, - line - ], - expr::SaveIn(scratch_bits.val)); - - if bcx.tcx().sess.opts.optimize == session::No { - bcx = callee::trans_lang_call( - bcx, - bcx.tcx().lang_items.record_borrow_fn(), - ~[ - box_ptr, - Load(bcx, scratch_bits.val), - filename, - line - ], - expr::Ignore); - } - - add_clean_return_to_mut( - cleanup_bcx, scratch.val, scratch_bits.val, - filename, line); - } - } - - bcx - } - - fn perform_write_guard(&self, bcx: block, span: span) -> block { - debug!("perform_write_guard"); - - // Create scratch space, but do not root it. - let llval = match self.mode { - ByValue => self.val, - ByRef => Load(bcx, self.val), - }; - - let loc = bcx.sess().parse_sess.cm.lookup_char_pos(span.lo); - let line = C_int(bcx.ccx(), loc.line as int); - let filename_cstr = C_cstr(bcx.ccx(), @/*bad*/copy loc.file.name); - let filename = PointerCast(bcx, filename_cstr, T_ptr(T_i8())); - - callee::trans_lang_call( - bcx, - bcx.tcx().lang_items.check_not_borrowed_fn(), - ~[PointerCast(bcx, llval, T_ptr(T_i8())), - filename, - line], - expr::Ignore) - } - fn drop_val(&self, bcx: block) -> block { if !ty::type_needs_drop(bcx.tcx(), self.ty) { return bcx; @@ -687,7 +578,9 @@ pub impl Datum { debug!("try_deref(expr_id=%?, derefs=%?, is_auto=%b, self=%?)", expr_id, derefs, is_auto, self.to_str(bcx.ccx())); - let bcx = self.root_and_write_guard(bcx, span, expr_id, derefs); + let bcx = + write_guard::root_and_write_guard( + self, bcx, span, expr_id, derefs); match ty::get(self.ty).sty { ty::ty_box(_) | ty::ty_uniq(_) => { @@ -841,33 +734,6 @@ pub impl Datum { DatumBlock { bcx: bcx, datum: datum } } - fn root_and_write_guard(&self, - mut bcx: block, - span: span, - expr_id: ast::node_id, - derefs: uint) -> block { - let key = root_map_key { id: expr_id, derefs: derefs }; - debug!("root_and_write_guard(key=%?)", key); - - // root the autoderef'd value, if necessary: - // - // (Note: root'd values are always boxes) - let ccx = bcx.ccx(); - bcx = match ccx.maps.root_map.find(&key) { - None => bcx, - Some(&root_info) => self.root(bcx, span, key, root_info) - }; - - // Perform the write guard, if necessary. - // - // (Note: write-guarded values are always boxes) - if ccx.maps.write_guard_map.contains(&key) { - self.perform_write_guard(bcx, span) - } else { - bcx - } - } - fn get_vec_base_and_len(&self, mut bcx: block, span: span, @@ -877,7 +743,7 @@ pub impl Datum { //! and write guards checks. // only imp't for @[] and @str, but harmless - bcx = self.root_and_write_guard(bcx, span, expr_id, 0); + bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, 0); let (base, len) = self.get_vec_base_and_len_no_root(bcx); (bcx, base, len) } @@ -890,6 +756,14 @@ pub impl Datum { tvec::get_base_and_len(bcx, llval, self.ty) } + fn root_and_write_guard(&self, + bcx: block, + span: span, + expr_id: ast::node_id, + derefs: uint) -> block { + write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs) + } + fn to_result(&self, bcx: block) -> common::Result { rslt(bcx, self.to_appropriate_llval(bcx)) } diff --git a/src/librustc/rustc.rc b/src/librustc/rustc.rc index 1ecb38854c815..7191a98e5dbc6 100644 --- a/src/librustc/rustc.rc +++ b/src/librustc/rustc.rc @@ -47,6 +47,7 @@ pub mod middle { pub mod controlflow; pub mod glue; pub mod datum; + pub mod write_guard; pub mod callee; pub mod expr; pub mod common; From 8081e8debf63726865e869aaacbd040755285a51 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sat, 4 May 2013 14:25:41 -0700 Subject: [PATCH 196/215] Register snapshots --- src/libcore/cast.rs | 46 - src/libcore/container.rs | 36 - src/libcore/core.rc | 3 - src/libcore/hashmap.rs | 168 --- src/libcore/num/f32.rs | 7 +- src/libcore/num/f64.rs | 6 +- src/libcore/num/float.rs | 7 +- src/libcore/num/int-template.rs | 7 +- src/libcore/num/num.rs | 23 +- src/libcore/num/strconv.rs | 7 - src/libcore/num/uint-template.rs | 7 +- src/libcore/ops.rs | 6 - src/libcore/option.rs | 104 -- src/libcore/prelude.rs | 3 - src/libcore/reflect.rs | 33 +- src/libcore/repr.rs | 111 +- src/libcore/result.rs | 7 - src/libcore/rt/io/mod.rs | 3 - src/libcore/rt/mod.rs | 21 - src/libcore/rt/rtio.rs | 5 - src/libcore/rt/uvio.rs | 16 - src/libcore/stackwalk.rs | 3 - src/libcore/sys.rs | 22 - src/libcore/trie.rs | 95 -- src/libcore/tuple.rs | 28 - src/libcore/unstable/intrinsics.rs | 4 - src/libcore/unstable/lang.rs | 47 - src/libcore/vec.rs | 226 ---- src/librustc/metadata/decoder.rs | 8 - src/librustc/metadata/encoder.rs | 1536 +++------------------------- src/librustc/middle/astencode.rs | 774 -------------- src/libstd/arena.rs | 59 -- src/libstd/deque.rs | 122 --- src/libstd/ebml.rs | 539 ---------- src/libstd/flatpipes.rs | 25 - src/libstd/future.rs | 29 - src/libstd/json.rs | 631 ------------ src/libstd/priority_queue.rs | 16 - src/libstd/serialize.rs | 990 +----------------- src/libstd/smallintmap.rs | 77 -- src/libstd/std.rc | 4 - src/libstd/workcache.rs | 45 - src/libsyntax/ast.rs | 31 - src/libsyntax/codemap.rs | 15 - src/libsyntax/ext/base.rs | 11 - src/libsyntax/opt_vec.rs | 9 - src/snapshots.txt | 8 + 47 files changed, 138 insertions(+), 5842 deletions(-) diff --git a/src/libcore/cast.rs b/src/libcore/cast.rs index 22f31d52d2d54..96e1c3bd1249b 100644 --- a/src/libcore/cast.rs +++ b/src/libcore/cast.rs @@ -10,9 +10,7 @@ //! Unsafe casting functions -#[cfg(not(stage0))] use sys; -#[cfg(not(stage0))] use unstable; pub mod rusti { @@ -21,35 +19,11 @@ pub mod rusti { pub extern "rust-intrinsic" { fn forget(+x: T); - #[cfg(stage0)] - fn reinterpret_cast(&&e: T) -> U; - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn transmute(e: T) -> U; } } /// Casts the value at `src` to U. The two types must have the same length. -#[inline(always)] -#[cfg(stage0)] -pub unsafe fn reinterpret_cast(src: &T) -> U { - rusti::reinterpret_cast(*src) -} - -/// Unsafely copies and casts the value at `src` to U, even if the value is -/// noncopyable. The two types must have the same length. -#[inline(always)] -#[cfg(stage0)] -pub unsafe fn transmute_copy(src: &T) -> U { - rusti::reinterpret_cast(*src) -} - -#[inline(always)] -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub unsafe fn transmute_copy(src: &T) -> U { let mut dest: U = unstable::intrinsics::init(); { @@ -90,17 +64,6 @@ pub unsafe fn bump_box_refcount(t: @T) { forget(t); } * assert!(transmute("L") == ~[76u8, 0u8]); */ #[inline(always)] -#[cfg(stage0)] -pub unsafe fn transmute(thing: L) -> G { - let newthing: G = reinterpret_cast(&thing); - forget(thing); - newthing -} - -#[inline(always)] -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub unsafe fn transmute(thing: L) -> G { rusti::transmute(thing) } @@ -161,15 +124,6 @@ mod tests { use cast::{bump_box_refcount, transmute}; #[test] - #[cfg(stage0)] - fn test_reinterpret_cast() { - assert!(1u == unsafe { ::cast::reinterpret_cast(&1) }); - } - - #[test] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn test_transmute_copy() { assert!(1u == unsafe { ::cast::transmute_copy(&1) }); } diff --git a/src/libcore/container.rs b/src/libcore/container.rs index 88c78aebfc5c7..00ea4a9322111 100644 --- a/src/libcore/container.rs +++ b/src/libcore/container.rs @@ -25,42 +25,6 @@ pub trait Mutable: Container { fn clear(&mut self); } -#[cfg(stage0)] -pub trait Map: Mutable { - /// Return true if the map contains a value for the specified key - fn contains_key(&self, key: &K) -> bool; - - // Visits all keys and values - fn each(&self, f: &fn(&K, &V) -> bool); - - /// Visit all keys - fn each_key(&self, f: &fn(&K) -> bool); - - /// Visit all values - fn each_value(&self, f: &fn(&V) -> bool); - - /// Iterate over the map and mutate the contained values - fn mutate_values(&mut self, f: &fn(&K, &mut V) -> bool); - - /// Return a reference to the value corresponding to the key - fn find(&self, key: &K) -> Option<&'self V>; - - /// Return a mutable reference to the value corresponding to the key - fn find_mut(&mut self, key: &K) -> Option<&'self mut V>; - - /// Insert a key-value pair into the map. An existing value for a - /// key is replaced by the new value. Return true if the key did - /// not already exist in the map. - fn insert(&mut self, key: K, value: V) -> bool; - - /// Remove a key-value pair from the map. Return true if the key - /// was present in the map, otherwise false. - fn remove(&mut self, key: &K) -> bool; -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub trait Map: Mutable { /// Return true if the map contains a value for the specified key fn contains_key(&self, key: &K) -> bool; diff --git a/src/libcore/core.rc b/src/libcore/core.rc index 75ef8ee0cbd13..9672bf887caff 100644 --- a/src/libcore/core.rc +++ b/src/libcore/core.rc @@ -74,9 +74,6 @@ they contained the following prologue: pub use kinds::{Const, Copy, Owned, Durable}; pub use ops::{Drop}; -#[cfg(stage0)] -pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not}; -#[cfg(not(stage0))] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Shl, Shr, Index}; diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index 9b82a8dad059e..392ad38e20931 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -184,18 +184,6 @@ priv impl HashMap { } } - #[cfg(stage0)] - #[inline(always)] - fn value_for_bucket(&self, idx: uint) -> &'self V { - match self.buckets[idx] { - Some(ref bkt) => &bkt.value, - None => fail!(~"HashMap::find: internal logic error"), - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn value_for_bucket<'a>(&'a self, idx: uint) -> &'a V { match self.buckets[idx] { @@ -204,18 +192,6 @@ priv impl HashMap { } } - #[cfg(stage0)] - #[inline(always)] - fn mut_value_for_bucket(&mut self, idx: uint) -> &'self mut V { - match self.buckets[idx] { - Some(ref mut bkt) => &mut bkt.value, - None => unreachable() - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn mut_value_for_bucket<'a>(&'a mut self, idx: uint) -> &'a mut V { match self.buckets[idx] { @@ -329,21 +305,6 @@ impl Map for HashMap { } /// Visit all key-value pairs - #[cfg(stage0)] - fn each(&self, blk: &fn(&'self K, &'self V) -> bool) { - for uint::range(0, self.buckets.len()) |i| { - for self.buckets[i].each |bucket| { - if !blk(&bucket.key, &bucket.value) { - return; - } - } - } - } - - /// Visit all key-value pairs - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each<'a>(&'a self, blk: &fn(&'a K, &'a V) -> bool) { for uint::range(0, self.buckets.len()) |i| { for self.buckets[i].each |bucket| { @@ -360,15 +321,6 @@ impl Map for HashMap { } /// Visit all values - #[cfg(stage0)] - fn each_value(&self, blk: &fn(v: &V) -> bool) { - self.each(|_, v| blk(v)) - } - - /// Visit all values - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each_value<'a>(&'a self, blk: &fn(v: &'a V) -> bool) { self.each(|_, v| blk(v)) } @@ -386,18 +338,6 @@ impl Map for HashMap { } /// Return a reference to the value corresponding to the key - #[cfg(stage0)] - fn find(&self, k: &K) -> Option<&'self V> { - match self.bucket_for_key(k) { - FoundEntry(idx) => Some(self.value_for_bucket(idx)), - TableFull | FoundHole(_) => None, - } - } - - /// Return a reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find<'a>(&'a self, k: &K) -> Option<&'a V> { match self.bucket_for_key(k) { FoundEntry(idx) => Some(self.value_for_bucket(idx)), @@ -406,21 +346,6 @@ impl Map for HashMap { } /// Return a mutable reference to the value corresponding to the key - #[cfg(stage0)] - fn find_mut(&mut self, k: &K) -> Option<&'self mut V> { - let idx = match self.bucket_for_key(k) { - FoundEntry(idx) => idx, - TableFull | FoundHole(_) => return None - }; - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker - Some(::cast::transmute_mut_region(self.mut_value_for_bucket(idx))) - } - } - - /// Return a mutable reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find_mut<'a>(&'a mut self, k: &K) -> Option<&'a mut V> { let idx = match self.bucket_for_key(k) { FoundEntry(idx) => idx, @@ -503,40 +428,6 @@ pub impl HashMap { /// Return the value corresponding to the key in the map, or insert /// and return the value if it doesn't exist. - #[cfg(stage0)] - fn find_or_insert(&mut self, k: K, v: V) -> &'self V { - if self.size >= self.resize_at { - // n.b.: We could also do this after searching, so - // that we do not resize if this call to insert is - // simply going to update a key in place. My sense - // though is that it's worse to have to search through - // buckets to find the right spot twice than to just - // resize in this corner case. - self.expand(); - } - - let hash = k.hash_keyed(self.k0, self.k1) as uint; - let idx = match self.bucket_for_key_with_hash(hash, &k) { - TableFull => fail!(~"Internal logic error"), - FoundEntry(idx) => idx, - FoundHole(idx) => { - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); - self.size += 1; - idx - }, - }; - - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker - ::cast::transmute_region(self.value_for_bucket(idx)) - } - } - - /// Return the value corresponding to the key in the map, or insert - /// and return the value if it doesn't exist. - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find_or_insert<'a>(&'a mut self, k: K, v: V) -> &'a V { if self.size >= self.resize_at { // n.b.: We could also do this after searching, so @@ -567,41 +458,6 @@ pub impl HashMap { /// Return the value corresponding to the key in the map, or create, /// insert, and return a new value if it doesn't exist. - #[cfg(stage0)] - fn find_or_insert_with(&mut self, k: K, f: &fn(&K) -> V) -> &'self V { - if self.size >= self.resize_at { - // n.b.: We could also do this after searching, so - // that we do not resize if this call to insert is - // simply going to update a key in place. My sense - // though is that it's worse to have to search through - // buckets to find the right spot twice than to just - // resize in this corner case. - self.expand(); - } - - let hash = k.hash_keyed(self.k0, self.k1) as uint; - let idx = match self.bucket_for_key_with_hash(hash, &k) { - TableFull => fail!(~"Internal logic error"), - FoundEntry(idx) => idx, - FoundHole(idx) => { - let v = f(&k); - self.buckets[idx] = Some(Bucket{hash: hash, key: k, - value: v}); - self.size += 1; - idx - }, - }; - - unsafe { // FIXME(#4903)---requires flow-sensitive borrow checker - ::cast::transmute_region(self.value_for_bucket(idx)) - } - } - - /// Return the value corresponding to the key in the map, or create, - /// insert, and return a new value if it doesn't exist. - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find_or_insert_with<'a>(&'a mut self, k: K, f: &fn(&K) -> V) -> &'a V { if self.size >= self.resize_at { // n.b.: We could also do this after searching, so @@ -647,17 +503,6 @@ pub impl HashMap { } } - #[cfg(stage0)] - fn get(&self, k: &K) -> &'self V { - match self.find(k) { - Some(v) => v, - None => fail!(fmt!("No entry found for key: %?", k)), - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get<'a>(&'a self, k: &K) -> &'a V { match self.find(k) { Some(v) => v, @@ -676,19 +521,6 @@ pub impl HashMap { /// Return the value corresponding to the key in the map, using /// equivalence - #[cfg(stage0)] - fn find_equiv>(&self, k: &Q) -> Option<&'self V> { - match self.bucket_for_key_equiv(k) { - FoundEntry(idx) => Some(self.value_for_bucket(idx)), - TableFull | FoundHole(_) => None, - } - } - - /// Return the value corresponding to the key in the map, using - /// equivalence - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find_equiv<'a, Q:Hash + Equiv>(&'a self, k: &Q) -> Option<&'a V> { match self.bucket_for_key_equiv(k) { FoundEntry(idx) => Some(self.value_for_bucket(idx)), diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 1b4c679ea07b4..416ec2069b521 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -284,12 +284,7 @@ impl Div for f32 { fn div(&self, other: &f32) -> f32 { *self / *other } } -#[cfg(stage0,notest)] -impl Modulo for f32 { - #[inline(always)] - fn modulo(&self, other: &f32) -> f32 { *self % *other } -} -#[cfg(not(stage0),notest)] +#[cfg(notest)] impl Rem for f32 { #[inline(always)] fn rem(&self, other: &f32) -> f32 { *self % *other } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 0f7647fa8680d..6e09ca61a7d4c 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -299,11 +299,7 @@ impl Mul for f64 { impl Div for f64 { fn div(&self, other: &f64) -> f64 { *self / *other } } -#[cfg(stage0,notest)] -impl Modulo for f64 { - fn modulo(&self, other: &f64) -> f64 { *self % *other } -} -#[cfg(not(stage0),notest)] +#[cfg(notest)] impl Rem for f64 { #[inline(always)] fn rem(&self, other: &f64) -> f64 { *self % *other } diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 16bb2aa128651..da9d03f6a7bc3 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -697,12 +697,7 @@ impl Div for float { fn div(&self, other: &float) -> float { *self / *other } } -#[cfg(stage0,notest)] -impl Modulo for float { - #[inline(always)] - fn modulo(&self, other: &float) -> float { *self % *other } -} -#[cfg(not(stage0),notest)] +#[cfg(notest)] impl Rem for float { #[inline(always)] fn rem(&self, other: &float) -> float { *self % *other } diff --git a/src/libcore/num/int-template.rs b/src/libcore/num/int-template.rs index 090e0256abf6e..95c187a7be22e 100644 --- a/src/libcore/num/int-template.rs +++ b/src/libcore/num/int-template.rs @@ -224,12 +224,7 @@ impl Div for T { fn div(&self, other: &T) -> T { *self / *other } } -#[cfg(stage0,notest)] -impl Modulo for T { - #[inline(always)] - fn modulo(&self, other: &T) -> T { *self % *other } -} -#[cfg(not(stage0),notest)] +#[cfg(notest)] impl Rem for T { /// /// Returns the integer remainder after division, satisfying: diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index b8f47db7d128e..1a59a069df7e8 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -10,11 +10,6 @@ //! An interface for numeric types use cmp::{Eq, Ord}; -#[cfg(stage0)] -use ops::{Add, Sub, Mul, Div, Neg}; -#[cfg(stage0)] -use Rem = ops::Modulo; -#[cfg(not(stage0))] use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use option::Option; @@ -391,23 +386,7 @@ pub fn pow_with_uint+Mul>( } /// Helper function for testing numeric operations -#[cfg(stage0,test)] -pub fn test_num(ten: T, two: T) { - assert_eq!(ten.add(&two), cast(12)); - assert_eq!(ten.sub(&two), cast(8)); - assert_eq!(ten.mul(&two), cast(20)); - assert_eq!(ten.div(&two), cast(5)); - assert_eq!(ten.modulo(&two), cast(0)); - - assert_eq!(ten.add(&two), ten + two); - assert_eq!(ten.sub(&two), ten - two); - assert_eq!(ten.mul(&two), ten * two); - assert_eq!(ten.div(&two), ten / two); - assert_eq!(ten.modulo(&two), ten % two); -} -#[cfg(stage1,test)] -#[cfg(stage2,test)] -#[cfg(stage3,test)] +#[cfg(test)] pub fn test_num(ten: T, two: T) { assert_eq!(ten.add(&two), cast(12)); assert_eq!(ten.sub(&two), cast(8)); diff --git a/src/libcore/num/strconv.rs b/src/libcore/num/strconv.rs index 68e3b407a8bc2..c16a29f8295e7 100644 --- a/src/libcore/num/strconv.rs +++ b/src/libcore/num/strconv.rs @@ -9,13 +9,6 @@ // except according to those terms. use core::cmp::{Ord, Eq}; -#[cfg(stage0)] -use ops::{Add, Sub, Mul, Div, Neg}; -#[cfg(stage0)] -use Rem = ops::Modulo; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] use ops::{Add, Sub, Mul, Div, Rem, Neg}; use option::{None, Option, Some}; use char; diff --git a/src/libcore/num/uint-template.rs b/src/libcore/num/uint-template.rs index 379c1834543d2..6d0f1fe1fc72b 100644 --- a/src/libcore/num/uint-template.rs +++ b/src/libcore/num/uint-template.rs @@ -171,12 +171,7 @@ impl Div for T { fn div(&self, other: &T) -> T { *self / *other } } -#[cfg(stage0,notest)] -impl Modulo for T { - #[inline(always)] - fn modulo(&self, other: &T) -> T { *self % *other } -} -#[cfg(not(stage0),notest)] +#[cfg(notest)] impl Rem for T { #[inline(always)] fn rem(&self, other: &T) -> T { *self % *other } diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 5ba860c89c9b9..47ff45be68726 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -35,13 +35,7 @@ pub trait Div { fn div(&self, rhs: &RHS) -> Result; } -#[lang="modulo"] -#[cfg(stage0)] -pub trait Modulo { - fn modulo(&self, rhs: &RHS) -> Result; -} #[lang="rem"] -#[cfg(not(stage0))] pub trait Rem { fn rem(&self, rhs: &RHS) -> Result; } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index 47ec1fabcb822..b7c51147fba78 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -100,16 +100,6 @@ impl> Add, Option> for Option { impl BaseIter for Option { /// Performs an operation on the contained value by reference - #[cfg(stage0)] - #[inline(always)] - fn each(&self, f: &fn(x: &'self T) -> bool) { - match *self { None => (), Some(ref t) => { f(t); } } - } - - /// Performs an operation on the contained value by reference - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn each<'a>(&'a self, f: &fn(x: &'a T) -> bool) { match *self { None => (), Some(ref t) => { f(t); } } @@ -122,15 +112,6 @@ impl BaseIter for Option { } impl MutableIter for Option { - #[cfg(stage0)] - #[inline(always)] - fn each_mut(&mut self, f: &fn(&'self mut T) -> bool) { - match *self { None => (), Some(ref mut t) => { f(t); } } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn each_mut<'a>(&'a mut self, f: &fn(&'a mut T) -> bool) { match *self { None => (), Some(ref mut t) => { f(t); } } @@ -200,35 +181,12 @@ pub impl Option { * Update an optional value by optionally running its content by reference * through a function that returns an option. */ - #[cfg(stage0)] - #[inline(always)] - fn chain_ref(&self, f: &fn(x: &'self T) -> Option) -> Option { - match *self { Some(ref x) => f(x), None => None } - } - - /** - * Update an optional value by optionally running its content by reference - * through a function that returns an option. - */ - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn chain_ref<'a, U>(&'a self, f: &fn(x: &'a T) -> Option) -> Option { match *self { Some(ref x) => f(x), None => None } } /// Maps a `some` value from one type to another by reference - #[cfg(stage0)] - #[inline(always)] - fn map(&self, f: &fn(&'self T) -> U) -> Option { - match *self { Some(ref x) => Some(f(x)), None => None } - } - - /// Maps a `some` value from one type to another by reference - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn map<'a, U>(&self, f: &fn(&'a T) -> U) -> Option { match *self { Some(ref x) => Some(f(x)), None => None } @@ -242,16 +200,6 @@ pub impl Option { } /// Applies a function to the contained value or returns a default - #[cfg(stage0)] - #[inline(always)] - fn map_default(&self, def: U, f: &fn(&'self T) -> U) -> U { - match *self { None => def, Some(ref t) => f(t) } - } - - /// Applies a function to the contained value or returns a default - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn map_default<'a, U>(&'a self, def: U, f: &fn(&'a T) -> U) -> U { match *self { None => def, Some(ref t) => f(t) } @@ -295,32 +243,6 @@ pub impl Option { case explicitly. */ #[inline(always)] - #[cfg(stage0)] - fn get_ref(&self) -> &'self T { - match *self { - Some(ref x) => x, - None => fail!(~"option::get_ref none") - } - } - - /** - Gets an immutable reference to the value inside an option. - - # Failure - - Fails if the value equals `None` - - # Safety note - - In general, because this function may fail, its use is discouraged - (calling `get` on `None` is akin to dereferencing a null pointer). - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get_ref<'a>(&'a self) -> &'a T { match *self { Some(ref x) => x, @@ -343,32 +265,6 @@ pub impl Option { case explicitly. */ #[inline(always)] - #[cfg(stage0)] - fn get_mut_ref(&mut self) -> &'self mut T { - match *self { - Some(ref mut x) => x, - None => fail!(~"option::get_mut_ref none") - } - } - - /** - Gets a mutable reference to the value inside an option. - - # Failure - - Fails if the value equals `None` - - # Safety note - - In general, because this function may fail, its use is discouraged - (calling `get` on `None` is akin to dereferencing a null pointer). - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get_mut_ref<'a>(&'a mut self) -> &'a mut T { match *self { Some(ref mut x) => x, diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 0dad9fc91d4ce..42401ae5a1fcd 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -14,9 +14,6 @@ pub use either::{Either, Left, Right}; pub use kinds::{Const, Copy, Owned, Durable}; -#[cfg(stage0)] -pub use ops::{Add, Sub, Mul, Div, Modulo, Neg, Not}; -#[cfg(not(stage0))] pub use ops::{Add, Sub, Mul, Div, Rem, Neg, Not}; pub use ops::{BitAnd, BitOr, BitXor}; pub use ops::{Drop}; diff --git a/src/libcore/reflect.rs b/src/libcore/reflect.rs index 9a0526b4351ba..47de360f58995 100644 --- a/src/libcore/reflect.rs +++ b/src/libcore/reflect.rs @@ -15,7 +15,7 @@ Runtime type reflection */ use intrinsic::{TyDesc, TyVisitor}; -#[cfg(not(stage0))] use intrinsic::Opaque; +use intrinsic::Opaque; use libc::c_void; use sys; use vec; @@ -394,17 +394,6 @@ impl TyVisitor for MovePtrAdaptor { true } - #[cfg(stage0)] - fn visit_enter_enum(&self, n_variants: uint, sz: uint, align: uint) - -> bool { - self.align(align); - if ! self.inner.visit_enter_enum(n_variants, sz, align) { - return false; - } - true - } - - #[cfg(not(stage0))] fn visit_enter_enum(&self, n_variants: uint, get_disr: extern unsafe fn(ptr: *Opaque) -> int, sz: uint, align: uint) @@ -428,15 +417,6 @@ impl TyVisitor for MovePtrAdaptor { true } - #[cfg(stage0)] - fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { - unsafe { self.align((*inner).align); } - if ! self.inner.visit_enum_variant_field(i, inner) { return false; } - unsafe { self.bump((*inner).size); } - true - } - - #[cfg(not(stage0))] fn visit_enum_variant_field(&self, i: uint, offset: uint, inner: *TyDesc) -> bool { self.inner.push_ptr(); self.bump(offset); @@ -457,17 +437,6 @@ impl TyVisitor for MovePtrAdaptor { true } - #[cfg(stage0)] - fn visit_leave_enum(&self, n_variants: uint, sz: uint, align: uint) - -> bool { - if ! self.inner.visit_leave_enum(n_variants, sz, align) { - return false; - } - self.bump(sz); - true - } - - #[cfg(not(stage0))] fn visit_leave_enum(&self, n_variants: uint, get_disr: extern unsafe fn(ptr: *Opaque) -> int, sz: uint, align: uint) -> bool { diff --git a/src/libcore/repr.rs b/src/libcore/repr.rs index 29b8400706ce0..3d52599325928 100644 --- a/src/libcore/repr.rs +++ b/src/libcore/repr.rs @@ -18,12 +18,11 @@ use cast::transmute; use char; use intrinsic; use intrinsic::{TyDesc, TyVisitor, visit_tydesc}; -#[cfg(not(stage0))] use intrinsic::Opaque; +use intrinsic::Opaque; use io::{Writer, WriterUtil}; use libc::c_void; use managed; use ptr; -#[cfg(stage0)] use sys; use reflect; use reflect::{MovePtr, align}; use to_str::ToStr; @@ -138,14 +137,6 @@ impl Repr for char { // New implementation using reflect::MovePtr -#[cfg(stage0)] -enum VariantState { - Degenerate, - TagMatch, - TagMismatch, -} - -#[cfg(not(stage0))] enum VariantState { SearchingFor(int), Matched, @@ -190,18 +181,6 @@ pub impl ReprVisitor { true } - #[cfg(stage0)] #[inline(always)] - fn bump(&self, sz: uint) { - do self.move_ptr() |p| { - ((p as uint) + sz) as *c_void - }; - } - - #[cfg(stage0)] #[inline(always)] - fn bump_past(&self) { - self.bump(sys::size_of::()); - } - #[inline(always)] fn visit_inner(&self, inner: *TyDesc) -> bool { self.visit_ptr_inner(self.ptr, inner) @@ -467,18 +446,6 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_enter_enum(&self, n_variants: uint, - _sz: uint, _align: uint) -> bool { - if n_variants == 1 { - self.var_stk.push(Degenerate) - } else { - self.var_stk.push(TagMatch) - } - true - } - - #[cfg(not(stage0))] fn visit_enter_enum(&self, _n_variants: uint, get_disr: extern unsafe fn(ptr: *Opaque) -> int, _sz: uint, _align: uint) -> bool { @@ -487,40 +454,6 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_enter_enum_variant(&self, _variant: uint, - disr_val: int, - n_fields: uint, - name: &str) -> bool { - let mut write = false; - match self.var_stk.pop() { - Degenerate => { - write = true; - self.var_stk.push(Degenerate); - } - TagMatch | TagMismatch => { - do self.get::() |t| { - if disr_val == *t { - write = true; - self.var_stk.push(TagMatch); - } else { - self.var_stk.push(TagMismatch); - } - }; - self.bump_past::(); - } - } - - if write { - self.writer.write_str(name); - if n_fields > 0 { - self.writer.write_char('('); - } - } - true - } - - #[cfg(not(stage0))] fn visit_enter_enum_variant(&self, _variant: uint, disr_val: int, n_fields: uint, @@ -549,23 +482,6 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_enum_variant_field(&self, i: uint, inner: *TyDesc) -> bool { - match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { - Degenerate | TagMatch => { - if i != 0 { - self.writer.write_str(", "); - } - if ! self.visit_inner(inner) { - return false; - } - } - TagMismatch => () - } - true - } - - #[cfg(not(stage0))] fn visit_enum_variant_field(&self, i: uint, _offset: uint, inner: *TyDesc) -> bool { match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { Matched => { @@ -581,23 +497,6 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_leave_enum_variant(&self, _variant: uint, - _disr_val: int, - n_fields: uint, - _name: &str) -> bool { - match self.var_stk[vec::uniq_len(&const self.var_stk) - 1] { - Degenerate | TagMatch => { - if n_fields > 0 { - self.writer.write_char(')'); - } - } - TagMismatch => () - } - true - } - - #[cfg(not(stage0))] fn visit_leave_enum_variant(&self, _variant: uint, _disr_val: int, n_fields: uint, @@ -613,14 +512,6 @@ impl TyVisitor for ReprVisitor { true } - #[cfg(stage0)] - fn visit_leave_enum(&self, _n_variants: uint, - _sz: uint, _align: uint) -> bool { - self.var_stk.pop(); - true - } - - #[cfg(not(stage0))] fn visit_leave_enum(&self, _n_variants: uint, _get_disr: extern unsafe fn(ptr: *Opaque) -> int, _sz: uint, _align: uint) -> bool { diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 9171c5167bc7b..17cc07c660d1a 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -226,13 +226,6 @@ pub fn map_err(res: &Result, op: &fn(&E) -> F) } pub impl Result { - #[cfg(stage0)] - #[inline(always)] - fn get_ref(&self) -> &'self T { get_ref(self) } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn get_ref<'a>(&'a self) -> &'a T { get_ref(self) } diff --git a/src/libcore/rt/io/mod.rs b/src/libcore/rt/io/mod.rs index ced4ba0ee2309..97b3ee3e30ef6 100644 --- a/src/libcore/rt/io/mod.rs +++ b/src/libcore/rt/io/mod.rs @@ -275,7 +275,6 @@ pub mod net { } /// Readers and Writers for memory buffers and strings. -#[cfg(not(stage0))] // XXX Using unsnapshotted features pub mod mem; /// Non-blocking access to stdin, stdout, stderr @@ -286,11 +285,9 @@ pub mod stdio; mod option; /// Basic stream compression. XXX: Belongs with other flate code -#[cfg(not(stage0))] // XXX Using unsnapshotted features pub mod flate; /// Interop between byte streams and pipes. Not sure where it belongs -#[cfg(not(stage0))] // XXX " pub mod comm_adapters; /// Extension traits diff --git a/src/libcore/rt/mod.rs b/src/libcore/rt/mod.rs index 56ed7dc95b6df..a072fccd33d6c 100644 --- a/src/libcore/rt/mod.rs +++ b/src/libcore/rt/mod.rs @@ -37,27 +37,6 @@ mod local_heap; #[cfg(test)] pub mod test; -#[cfg(stage0)] -pub fn start(main: *u8, _argc: int, _argv: *c_char, _crate_map: *u8) -> int { - use self::sched::{Scheduler, Task}; - use self::uvio::UvEventLoop; - - let loop_ = ~UvEventLoop::new(); - let mut sched = ~Scheduler::new(loop_); - let main_task = ~do Task::new(&mut sched.stack_pool) { - // XXX: Can't call a C function pointer from Rust yet - unsafe { rust_call_nullary_fn(main) }; - }; - sched.task_queue.push_back(main_task); - sched.run(); - return 0; - - extern { - fn rust_call_nullary_fn(f: *u8); - } -} - -#[cfg(not(stage0))] pub fn start(main: *u8, _argc: int, _argv: **c_char, _crate_map: *u8) -> int { use self::sched::{Scheduler, Task}; use self::uvio::UvEventLoop; diff --git a/src/libcore/rt/rtio.rs b/src/libcore/rt/rtio.rs index 66eb79ba6ae4e..fd64438c61b46 100644 --- a/src/libcore/rt/rtio.rs +++ b/src/libcore/rt/rtio.rs @@ -24,11 +24,6 @@ pub trait EventLoop { fn run(&mut self); fn callback(&mut self, ~fn()); /// The asynchronous I/O services. Not all event loops may provide one - #[cfg(stage0)] - fn io(&mut self) -> Option<&'self mut IoFactoryObject>; - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject>; } diff --git a/src/libcore/rt/uvio.rs b/src/libcore/rt/uvio.rs index 94f8c0bf707dd..ab8aea2b63c4f 100644 --- a/src/libcore/rt/uvio.rs +++ b/src/libcore/rt/uvio.rs @@ -68,14 +68,6 @@ impl EventLoop for UvEventLoop { } } - #[cfg(stage0)] - fn io(&mut self) -> Option<&'self mut IoFactoryObject> { - Some(&mut self.uvio) - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn io<'a>(&'a mut self) -> Option<&'a mut IoFactoryObject> { Some(&mut self.uvio) } @@ -98,14 +90,6 @@ fn test_callback_run_once() { pub struct UvIoFactory(Loop); pub impl UvIoFactory { - #[cfg(stage0)] - fn uv_loop(&mut self) -> &'self mut Loop { - match self { &UvIoFactory(ref mut ptr) => ptr } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn uv_loop<'a>(&'a mut self) -> &'a mut Loop { match self { &UvIoFactory(ref mut ptr) => ptr } } diff --git a/src/libcore/stackwalk.rs b/src/libcore/stackwalk.rs index 272bdca8654f1..987d4064ab9f6 100644 --- a/src/libcore/stackwalk.rs +++ b/src/libcore/stackwalk.rs @@ -93,9 +93,6 @@ pub mod rustrt { pub mod rusti { #[abi = "rust-intrinsic"] pub extern "rust-intrinsic" { - #[cfg(stage0)] - pub fn frame_address(f: &once fn(x: *u8)); - #[cfg(not(stage0))] pub fn frame_address(+f: &once fn(x: *u8)); } } diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs index dd36604883433..4eca7ebbb371e 100644 --- a/src/libcore/sys.rs +++ b/src/libcore/sys.rs @@ -200,21 +200,6 @@ impl FailWithCause for &'static str { } } -// NOTE: remove function after snapshot -#[cfg(stage0)] -pub fn begin_unwind(msg: ~str, file: ~str, line: uint) -> ! { - - do str::as_buf(msg) |msg_buf, _msg_len| { - do str::as_buf(file) |file_buf, _file_len| { - unsafe { - let msg_buf = cast::transmute(msg_buf); - let file_buf = cast::transmute(file_buf); - begin_unwind_(msg_buf, file_buf, line as libc::size_t) - } - } - } -} - // FIXME #4427: Temporary until rt::rt_fail_ goes away pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { use rt::{context, OldTaskContext}; @@ -242,13 +227,6 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! { } } -// NOTE: remove function after snapshot -#[cfg(stage0)] -pub fn fail_assert(msg: &str, file: &str, line: uint) -> ! { - let (msg, file) = (msg.to_owned(), file.to_owned()); - begin_unwind(~"assertion failed: " + msg, file, line) -} - #[cfg(test)] mod tests { use cast; diff --git a/src/libcore/trie.rs b/src/libcore/trie.rs index f4e9ddbdd90a1..f0756be994432 100644 --- a/src/libcore/trie.rs +++ b/src/libcore/trie.rs @@ -56,16 +56,6 @@ impl Map for TrieMap { /// Visit all key-value pairs in order #[inline(always)] - #[cfg(stage0)] - fn each(&self, f: &fn(&uint, &'self T) -> bool) { - self.root.each(f); - } - - /// Visit all key-value pairs in order - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) { self.root.each(f); } @@ -78,16 +68,6 @@ impl Map for TrieMap { /// Visit all values in order #[inline(always)] - #[cfg(stage0)] - fn each_value(&self, f: &fn(&T) -> bool) { - self.each(|_, v| f(v)) - } - - /// Visit all values in order - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each_value<'a>(&'a self, f: &fn(&'a T) -> bool) { self.each(|_, v| f(v)) } @@ -99,31 +79,6 @@ impl Map for TrieMap { } /// Return a reference to the value corresponding to the key - #[cfg(stage0)] - #[inline(hint)] - fn find(&self, key: &uint) -> Option<&'self T> { - let mut node: &'self TrieNode = &self.root; - let mut idx = 0; - loop { - match node.children[chunk(*key, idx)] { - Internal(ref x) => node = &**x, - External(stored, ref value) => { - if stored == *key { - return Some(value) - } else { - return None - } - } - Nothing => return None - } - idx += 1; - } - } - - /// Return a reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(hint)] fn find<'a>(&'a self, key: &uint) -> Option<&'a T> { let mut node: &'a TrieNode = &self.root; @@ -145,16 +100,6 @@ impl Map for TrieMap { } /// Return a mutable reference to the value corresponding to the key - #[cfg(stage0)] - #[inline(always)] - fn find_mut(&mut self, key: &uint) -> Option<&'self mut T> { - find_mut(&mut self.root.children[chunk(*key, 0)], *key, 1) - } - - /// Return a mutable reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] #[inline(always)] fn find_mut<'a>(&'a mut self, key: &uint) -> Option<&'a mut T> { find_mut(&mut self.root.children[chunk(*key, 0)], *key, 1) @@ -193,16 +138,6 @@ pub impl TrieMap { /// Visit all key-value pairs in reverse order #[inline(always)] - #[cfg(stage0)] - fn each_reverse(&self, f: &fn(&uint, &'self T) -> bool) { - self.root.each_reverse(f); - } - - /// Visit all key-value pairs in reverse order - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) { self.root.each_reverse(f); } @@ -298,21 +233,6 @@ impl TrieNode { } impl TrieNode { - #[cfg(stage0)] - fn each(&self, f: &fn(&uint, &'self T) -> bool) -> bool { - for uint::range(0, self.children.len()) |idx| { - match self.children[idx] { - Internal(ref x) => if !x.each(f) { return false }, - External(k, ref v) => if !f(&k, v) { return false }, - Nothing => () - } - } - true - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { for uint::range(0, self.children.len()) |idx| { match self.children[idx] { @@ -324,21 +244,6 @@ impl TrieNode { true } - #[cfg(stage0)] - fn each_reverse(&self, f: &fn(&uint, &'self T) -> bool) -> bool { - for uint::range_rev(self.children.len(), 0) |idx| { - match self.children[idx - 1] { - Internal(ref x) => if !x.each_reverse(f) { return false }, - External(k, ref v) => if !f(&k, v) { return false }, - Nothing => () - } - } - true - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each_reverse<'a>(&'a self, f: &fn(&uint, &'a T) -> bool) -> bool { for uint::range_rev(self.children.len(), 0) |idx| { match self.children[idx - 1] { diff --git a/src/libcore/tuple.rs b/src/libcore/tuple.rs index a2b6f0eb1a714..6da22657906dd 100644 --- a/src/libcore/tuple.rs +++ b/src/libcore/tuple.rs @@ -56,39 +56,11 @@ impl Clone for (T, U) { } } -#[cfg(stage0)] -pub trait ImmutableTuple { - fn first_ref(&self) -> &'self T; - fn second_ref(&self) -> &'self U; -} - -#[cfg(stage0)] -impl ImmutableTuple for (T, U) { - #[inline(always)] - fn first_ref(&self) -> &'self T { - match *self { - (ref t, _) => t, - } - } - #[inline(always)] - fn second_ref(&self) -> &'self U { - match *self { - (_, ref u) => u, - } - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub trait ImmutableTuple { fn first_ref<'a>(&'a self) -> &'a T; fn second_ref<'a>(&'a self) -> &'a U; } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl ImmutableTuple for (T, U) { #[inline(always)] fn first_ref<'a>(&'a self) -> &'a T { diff --git a/src/libcore/unstable/intrinsics.rs b/src/libcore/unstable/intrinsics.rs index b58429a10aad5..65cfc6ec1fe05 100644 --- a/src/libcore/unstable/intrinsics.rs +++ b/src/libcore/unstable/intrinsics.rs @@ -46,10 +46,6 @@ pub extern "rust-intrinsic" { pub fn forget(_: T) -> (); - // XXX: intrinsic uses legacy modes - #[cfg(stage0)] - fn reinterpret_cast(&&src: T) -> U; - pub fn needs_drop() -> bool; // XXX: intrinsic uses legacy modes and has reference to TyDesc diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 460285bfcfda0..7f6faa81012e8 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -17,9 +17,7 @@ use str; use sys; use unstable::exchange_alloc; use cast::transmute; -#[cfg(not(stage0))] use rt::{context, OldTaskContext}; -#[cfg(not(stage0))] use rt::local_services::borrow_local_services; #[allow(non_camel_case_types)] @@ -91,14 +89,6 @@ pub unsafe fn exchange_free(ptr: *c_char) { } #[lang="malloc"] -#[inline(always)] -#[cfg(stage0)] // For some reason this isn't working on windows in stage0 -pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { - return rustrt::rust_upcall_malloc_noswitch(td, size); -} - -#[lang="malloc"] -#[cfg(not(stage0))] pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { match context() { OldTaskContext => { @@ -118,17 +108,6 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char { // inside a landing pad may corrupt the state of the exception handler. If a // problem occurs, call exit instead. #[lang="free"] -#[inline(always)] -#[cfg(stage0)] -pub unsafe fn local_free(ptr: *c_char) { - rustrt::rust_upcall_free_noswitch(ptr); -} - -// NB: Calls to free CANNOT be allowed to fail, as throwing an exception from -// inside a landing pad may corrupt the state of the exception handler. If a -// problem occurs, call exit instead. -#[lang="free"] -#[cfg(not(stage0))] pub unsafe fn local_free(ptr: *c_char) { match context() { OldTaskContext => { @@ -176,32 +155,6 @@ pub unsafe fn strdup_uniq(ptr: *c_uchar, len: uint) -> ~str { } #[lang="start"] -#[cfg(stage0)] -pub fn start(main: *u8, argc: int, argv: *c_char, - crate_map: *u8) -> int { - use libc::getenv; - use rt::start; - - unsafe { - let use_old_rt = do str::as_c_str("RUST_NEWRT") |s| { - getenv(s).is_null() - }; - if use_old_rt { - return rust_start(main as *c_void, argc as c_int, argv, - crate_map as *c_void) as int; - } else { - return start(main, argc, argv, crate_map); - } - } - - extern { - fn rust_start(main: *c_void, argc: c_int, argv: *c_char, - crate_map: *c_void) -> c_int; - } -} - -#[lang="start"] -#[cfg(not(stage0))] pub fn start(main: *u8, argc: int, argv: **c_char, crate_map: *u8) -> int { use libc::getenv; diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index 081efe48e1eb5..6ffb0b30917a3 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -19,9 +19,6 @@ use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater}; use clone::Clone; use old_iter::BaseIter; use old_iter; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] use iterator::Iterator; use kinds::Copy; use libc; @@ -1566,16 +1563,6 @@ pub fn each_permutation(v: &[T], put: &fn(ts: &[T]) -> bool) { } } -// see doc below -#[cfg(stage0)] // XXX: lifetimes! -pub fn windowed(n: uint, v: &[T], it: &fn(&[T]) -> bool) { - assert!(1u <= n); - if n > v.len() { return; } - for uint::range(0, v.len() - n + 1) |i| { - if !it(v.slice(i, i+n)) { return } - } -} - /** * Iterate over all contiguous windows of length `n` of the vector `v`. * @@ -1590,9 +1577,6 @@ pub fn windowed(n: uint, v: &[T], it: &fn(&[T]) -> bool) { * ~~~ * */ -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub fn windowed<'r, T>(n: uint, v: &'r [T], it: &fn(&'r [T]) -> bool) { assert!(1u <= n); if n > v.len() { return; } @@ -1854,150 +1838,6 @@ impl<'self,T:Copy> CopyableVector for &'self const [T] { } } -#[cfg(stage0)] -pub trait ImmutableVector { - fn slice(&self, start: uint, end: uint) -> &'self [T]; - fn head(&self) -> &'self T; - fn head_opt(&self) -> Option<&'self T>; - fn tail(&self) -> &'self [T]; - fn tailn(&self, n: uint) -> &'self [T]; - fn init(&self) -> &'self [T]; - fn initn(&self, n: uint) -> &'self [T]; - fn last(&self) -> &'self T; - fn last_opt(&self) -> Option<&'self T>; - fn each_reverse(&self, blk: &fn(&T) -> bool); - fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool); - fn foldr(&self, z: U, p: &fn(t: &T, u: U) -> U) -> U; - fn map(&self, f: &fn(t: &T) -> U) -> ~[U]; - fn mapi(&self, f: &fn(uint, t: &T) -> U) -> ~[U]; - fn map_r(&self, f: &fn(x: &T) -> U) -> ~[U]; - fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool; - fn flat_map(&self, f: &fn(t: &T) -> ~[U]) -> ~[U]; - fn filter_mapped(&self, f: &fn(t: &T) -> Option) -> ~[U]; - unsafe fn unsafe_ref(&self, index: uint) -> *T; -} - -/// Extension methods for vectors -#[cfg(stage0)] -impl<'self,T> ImmutableVector for &'self [T] { - /// Return a slice that points into another slice. - #[inline] - fn slice(&self, start: uint, end: uint) -> &'self [T] { - slice(*self, start, end) - } - - /// Returns the first element of a vector, failing if the vector is empty. - #[inline] - fn head(&self) -> &'self T { head(*self) } - - /// Returns the first element of a vector - #[inline] - fn head_opt(&self) -> Option<&'self T> { head_opt(*self) } - - /// Returns all but the first element of a vector - #[inline] - fn tail(&self) -> &'self [T] { tail(*self) } - - /// Returns all but the first `n' elements of a vector - #[inline] - fn tailn(&self, n: uint) -> &'self [T] { tailn(*self, n) } - - /// Returns all but the last elemnt of a vector - #[inline] - fn init(&self) -> &'self [T] { init(*self) } - - /// Returns all but the last `n' elemnts of a vector - #[inline] - fn initn(&self, n: uint) -> &'self [T] { initn(*self, n) } - - /// Returns the last element of a `v`, failing if the vector is empty. - #[inline] - fn last(&self) -> &'self T { last(*self) } - - /// Returns the last element of a `v`, failing if the vector is empty. - #[inline] - fn last_opt(&self) -> Option<&'self T> { last_opt(*self) } - - /// Iterates over a vector's elements in reverse. - #[inline] - fn each_reverse(&self, blk: &fn(&T) -> bool) { - each_reverse(*self, blk) - } - - /// Iterates over a vector's elements and indices in reverse. - #[inline] - fn eachi_reverse(&self, blk: &fn(uint, &T) -> bool) { - eachi_reverse(*self, blk) - } - - /// Reduce a vector from right to left - #[inline] - fn foldr(&self, z: U, p: &fn(t: &T, u: U) -> U) -> U { - foldr(*self, z, p) - } - - /// Apply a function to each element of a vector and return the results - #[inline] - fn map(&self, f: &fn(t: &T) -> U) -> ~[U] { map(*self, f) } - - /** - * Apply a function to the index and value of each element in the vector - * and return the results - */ - fn mapi(&self, f: &fn(uint, t: &T) -> U) -> ~[U] { - mapi(*self, f) - } - - #[inline] - fn map_r(&self, f: &fn(x: &T) -> U) -> ~[U] { - let mut r = ~[]; - let mut i = 0; - while i < self.len() { - r.push(f(&self[i])); - i += 1; - } - r - } - - /** - * Returns true if the function returns true for all elements. - * - * If the vector is empty, true is returned. - */ - fn alli(&self, f: &fn(uint, t: &T) -> bool) -> bool { - alli(*self, f) - } - /** - * Apply a function to each element of a vector and return a concatenation - * of each result vector - */ - #[inline] - fn flat_map(&self, f: &fn(t: &T) -> ~[U]) -> ~[U] { - flat_map(*self, f) - } - /** - * Apply a function to each element of a vector and return the results - * - * If function `f` returns `none` then that element is excluded from - * the resulting vector. - */ - #[inline] - fn filter_mapped(&self, f: &fn(t: &T) -> Option) -> ~[U] { - filter_mapped(*self, f) - } - - /// Returns a pointer to the element at the given index, without doing - /// bounds checking. - #[inline(always)] - unsafe fn unsafe_ref(&self, index: uint) -> *T { - let (ptr, _): (*T, uint) = transmute(*self); - ptr.offset(index) - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub trait ImmutableVector<'self, T> { fn slice(&self, start: uint, end: uint) -> &'self [T]; fn iter(self) -> VecIterator<'self, T>; @@ -2022,9 +1862,6 @@ pub trait ImmutableVector<'self, T> { } /// Extension methods for vectors -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl<'self,T> ImmutableVector<'self, T> for &'self [T] { /// Return a slice that points into another slice. #[inline] @@ -2634,17 +2471,6 @@ pub mod bytes { // ___________________________________________________________________________ // ITERATION TRAIT METHODS -#[cfg(stage0)] -impl<'self,A> old_iter::BaseIter for &'self [A] { - #[inline(always)] - fn each(&self, blk: &fn(v: &'self A) -> bool) { each(*self, blk) } - #[inline(always)] - fn size_hint(&self) -> Option { Some(self.len()) } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl<'self,A> old_iter::BaseIter for &'self [A] { #[inline(always)] fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { each(*self, blk) } @@ -2653,18 +2479,6 @@ impl<'self,A> old_iter::BaseIter for &'self [A] { } // FIXME(#4148): This should be redundant -#[cfg(stage0)] -impl old_iter::BaseIter for ~[A] { - #[inline(always)] - fn each(&self, blk: &fn(v: &'self A) -> bool) { each(*self, blk) } - #[inline(always)] - fn size_hint(&self) -> Option { Some(self.len()) } -} - -// FIXME(#4148): This should be redundant -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl old_iter::BaseIter for ~[A] { #[inline(always)] fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { each(*self, blk) } @@ -2673,18 +2487,6 @@ impl old_iter::BaseIter for ~[A] { } // FIXME(#4148): This should be redundant -#[cfg(stage0)] -impl old_iter::BaseIter for @[A] { - #[inline(always)] - fn each(&self, blk: &fn(v: &'self A) -> bool) { each(*self, blk) } - #[inline(always)] - fn size_hint(&self) -> Option { Some(self.len()) } -} - -// FIXME(#4148): This should be redundant -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl old_iter::BaseIter for @[A] { #[inline(always)] fn each<'a>(&'a self, blk: &fn(v: &'a A) -> bool) { each(*self, blk) } @@ -2692,17 +2494,6 @@ impl old_iter::BaseIter for @[A] { fn size_hint(&self) -> Option { Some(self.len()) } } -#[cfg(stage0)] -impl<'self,A> old_iter::MutableIter for &'self mut [A] { - #[inline(always)] - fn each_mut(&mut self, blk: &fn(v: &'self mut A) -> bool) { - each_mut(*self, blk) - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl<'self,A> old_iter::MutableIter for &'self mut [A] { #[inline(always)] fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) { @@ -2711,17 +2502,6 @@ impl<'self,A> old_iter::MutableIter for &'self mut [A] { } // FIXME(#4148): This should be redundant -#[cfg(stage0)] -impl old_iter::MutableIter for ~[A] { - #[inline(always)] - fn each_mut(&mut self, blk: &fn(v: &'self mut A) -> bool) { - each_mut(*self, blk) - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl old_iter::MutableIter for ~[A] { #[inline(always)] fn each_mut<'a>(&'a mut self, blk: &fn(v: &'a mut A) -> bool) { @@ -2927,18 +2707,12 @@ impl Clone for ~[A] { } // could be implemented with &[T] with .slice(), but this avoids bounds checks -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub struct VecIterator<'self, T> { priv ptr: *T, priv end: *T, priv lifetime: &'self T // FIXME: #5922 } -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] impl<'self, T> Iterator<&'self T> for VecIterator<'self, T> { #[inline] fn next(&mut self) -> Option<&'self T> { diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 1be49528b9e79..1347fec5d667a 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -272,14 +272,6 @@ fn item_ty_param_defs(item: ebml::Doc, tcx: ty::ctxt, cdata: cmd, @bounds } -#[cfg(stage0)] -fn item_ty_region_param(item: ebml::Doc) -> Option { - reader::maybe_get_doc(item, tag_region_param).map(|doc| { - Decodable::decode(&reader::Decoder(*doc)) - }) -} - -#[cfg(not(stage0))] fn item_ty_region_param(item: ebml::Doc) -> Option { reader::maybe_get_doc(item, tag_region_param).map(|doc| { let mut decoder = reader::Decoder(*doc); diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 77373076137b9..6a9c564f36828 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -42,13 +42,6 @@ use writer = std::ebml::writer; // used by astencode: type abbrev_map = @mut HashMap; -#[cfg(stage0)] -pub type encode_inlined_item = @fn(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - path: &[ast_map::path_elt], - ii: ast::inlined_item); - -#[cfg(not(stage0))] pub type encode_inlined_item = @fn(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, path: &[ast_map::path_elt], @@ -98,27 +91,12 @@ pub fn reachable(ecx: @EncodeContext, id: node_id) -> bool { ecx.reachable.contains(&id) } -#[cfg(stage0)] -fn encode_name(ecx: @EncodeContext, ebml_w: &writer::Encoder, name: ident) { - ebml_w.wr_tagged_str(tag_paths_data_name, *ecx.tcx.sess.str_of(name)); -} - -#[cfg(not(stage0))] fn encode_name(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, name: ident) { ebml_w.wr_tagged_str(tag_paths_data_name, *ecx.tcx.sess.str_of(name)); } -#[cfg(stage0)] -fn encode_impl_type_basename(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - name: ident) { - ebml_w.wr_tagged_str(tag_item_impl_type_basename, - *ecx.tcx.sess.str_of(name)); -} - -#[cfg(not(stage0))] fn encode_impl_type_basename(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, name: ident) { @@ -126,29 +104,10 @@ fn encode_impl_type_basename(ecx: @EncodeContext, *ecx.tcx.sess.str_of(name)); } -#[cfg(stage0)] -pub fn encode_def_id(ebml_w: &writer::Encoder, id: def_id) { - ebml_w.wr_tagged_str(tag_def_id, def_to_str(id)); -} - -#[cfg(not(stage0))] pub fn encode_def_id(ebml_w: &mut writer::Encoder, id: def_id) { ebml_w.wr_tagged_str(tag_def_id, def_to_str(id)); } -#[cfg(stage0)] -fn encode_region_param(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - it: @ast::item) { - let opt_rp = ecx.tcx.region_paramd_items.find(&it.id); - for opt_rp.each |rp| { - do ebml_w.wr_tag(tag_region_param) { - rp.encode(ebml_w); - } - } -} - -#[cfg(not(stage0))] fn encode_region_param(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, it: @ast::item) { @@ -160,18 +119,6 @@ fn encode_region_param(ecx: @EncodeContext, } } -#[cfg(stage0)] -fn encode_mutability(ebml_w: &writer::Encoder, mt: struct_mutability) { - do ebml_w.wr_tag(tag_struct_mut) { - let val = match mt { - struct_immutable => 'a', - struct_mutable => 'm' - }; - ebml_w.writer.write(&[val as u8]); - } -} - -#[cfg(not(stage0))] fn encode_mutability(ebml_w: &mut writer::Encoder, mt: struct_mutability) { ebml_w.start_tag(tag_struct_mut); let val = match mt { @@ -187,24 +134,6 @@ struct entry { pos: uint } -#[cfg(stage0)] -fn add_to_index(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - path: &[ident], - index: &mut ~[entry<~str>], - name: ident) { - let mut full_path = ~[]; - full_path.push_all(path); - full_path.push(name); - index.push( - entry { - val: ast_util::path_name_i(full_path, - ecx.tcx.sess.parse_sess.interner), - pos: ebml_w.writer.tell() - }); -} - -#[cfg(not(stage0))] fn add_to_index(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, path: &[ident], @@ -221,24 +150,6 @@ fn add_to_index(ecx: @EncodeContext, }); } -#[cfg(stage0)] -fn encode_trait_ref(ebml_w: &writer::Encoder, - ecx: @EncodeContext, - trait_ref: &ty::TraitRef, - tag: uint) { - let ty_str_ctxt = @tyencode::ctxt { - diag: ecx.diag, - ds: def_to_str, - tcx: ecx.tcx, - reachable: |a| reachable(ecx, a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; - - ebml_w.start_tag(tag); - tyencode::enc_trait_ref(ebml_w.writer, ty_str_ctxt, trait_ref); - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_trait_ref(ebml_w: &mut writer::Encoder, ecx: @EncodeContext, trait_ref: &ty::TraitRef, @@ -256,15 +167,6 @@ fn encode_trait_ref(ebml_w: &mut writer::Encoder, } // Item info table encoding -#[cfg(stage0)] -fn encode_family(ebml_w: &writer::Encoder, c: char) { - ebml_w.start_tag(tag_items_data_item_family); - ebml_w.writer.write(&[c as u8]); - ebml_w.end_tag(); -} - -// Item info table encoding -#[cfg(not(stage0))] fn encode_family(ebml_w: &mut writer::Encoder, c: char) { ebml_w.start_tag(tag_items_data_item_family); ebml_w.writer.write(&[c as u8]); @@ -275,25 +177,6 @@ pub fn def_to_str(did: def_id) -> ~str { fmt!("%d:%d", did.crate, did.node) } -#[cfg(stage0)] -fn encode_ty_type_param_defs(ebml_w: &writer::Encoder, - ecx: @EncodeContext, - params: @~[ty::TypeParameterDef], - tag: uint) { - let ty_str_ctxt = @tyencode::ctxt { - diag: ecx.diag, - ds: def_to_str, - tcx: ecx.tcx, - reachable: |a| reachable(ecx, a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; - for params.each |param| { - ebml_w.start_tag(tag); - tyencode::enc_type_param_def(ebml_w.writer, ty_str_ctxt, param); - ebml_w.end_tag(); - } -} - -#[cfg(not(stage0))] fn encode_ty_type_param_defs(ebml_w: &mut writer::Encoder, ecx: @EncodeContext, params: @~[ty::TypeParameterDef], @@ -311,17 +194,6 @@ fn encode_ty_type_param_defs(ebml_w: &mut writer::Encoder, } } -#[cfg(stage0)] -fn encode_type_param_bounds(ebml_w: &writer::Encoder, - ecx: @EncodeContext, - params: &OptVec) { - let ty_param_defs = - @params.map_to_vec(|param| *ecx.tcx.ty_param_defs.get(¶m.id)); - encode_ty_type_param_defs(ebml_w, ecx, ty_param_defs, - tag_items_data_item_ty_param_bounds); -} - -#[cfg(not(stage0))] fn encode_type_param_bounds(ebml_w: &mut writer::Encoder, ecx: @EncodeContext, params: &OptVec) { @@ -331,32 +203,12 @@ fn encode_type_param_bounds(ebml_w: &mut writer::Encoder, tag_items_data_item_ty_param_bounds); } -#[cfg(stage0)] -fn encode_variant_id(ebml_w: &writer::Encoder, vid: def_id) { - ebml_w.start_tag(tag_items_data_item_variant); - ebml_w.writer.write(str::to_bytes(def_to_str(vid))); - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_variant_id(ebml_w: &mut writer::Encoder, vid: def_id) { ebml_w.start_tag(tag_items_data_item_variant); ebml_w.writer.write(str::to_bytes(def_to_str(vid))); ebml_w.end_tag(); } -#[cfg(stage0)] -pub fn write_type(ecx: @EncodeContext, ebml_w: &writer::Encoder, typ: ty::t) { - let ty_str_ctxt = @tyencode::ctxt { - diag: ecx.diag, - ds: def_to_str, - tcx: ecx.tcx, - reachable: |a| reachable(ecx, a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; - tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ); -} - -#[cfg(not(stage0))] pub fn write_type(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, typ: ty::t) { @@ -369,20 +221,6 @@ pub fn write_type(ecx: @EncodeContext, tyencode::enc_ty(ebml_w.writer, ty_str_ctxt, typ); } -#[cfg(stage0)] -pub fn write_vstore(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - vstore: ty::vstore) { - let ty_str_ctxt = @tyencode::ctxt { - diag: ecx.diag, - ds: def_to_str, - tcx: ecx.tcx, - reachable: |a| reachable(ecx, a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; - tyencode::enc_vstore(ebml_w.writer, ty_str_ctxt, vstore); -} - -#[cfg(not(stage0))] pub fn write_vstore(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, vstore: ty::vstore) { @@ -395,14 +233,6 @@ pub fn write_vstore(ecx: @EncodeContext, tyencode::enc_vstore(ebml_w.writer, ty_str_ctxt, vstore); } -#[cfg(stage0)] -fn encode_type(ecx: @EncodeContext, ebml_w: &writer::Encoder, typ: ty::t) { - ebml_w.start_tag(tag_items_data_item_type); - write_type(ecx, ebml_w, typ); - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_type(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, typ: ty::t) { @@ -411,18 +241,6 @@ fn encode_type(ecx: @EncodeContext, ebml_w.end_tag(); } -#[cfg(stage0)] -fn encode_transformed_self_ty(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - opt_typ: Option) { - for opt_typ.each |&typ| { - ebml_w.start_tag(tag_item_method_transformed_self_ty); - write_type(ecx, ebml_w, typ); - ebml_w.end_tag(); - } -} - -#[cfg(not(stage0))] fn encode_transformed_self_ty(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, opt_typ: Option) { @@ -433,24 +251,6 @@ fn encode_transformed_self_ty(ecx: @EncodeContext, } } -#[cfg(stage0)] -fn encode_method_fty(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - typ: &ty::BareFnTy) { - ebml_w.start_tag(tag_item_method_fty); - - let ty_str_ctxt = @tyencode::ctxt { - diag: ecx.diag, - ds: def_to_str, - tcx: ecx.tcx, - reachable: |a| reachable(ecx, a), - abbrevs: tyencode::ac_use_abbrevs(ecx.type_abbrevs)}; - tyencode::enc_bare_fn_ty(ebml_w.writer, ty_str_ctxt, typ); - - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_method_fty(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, typ: &ty::BareFnTy) { @@ -467,23 +267,6 @@ fn encode_method_fty(ecx: @EncodeContext, ebml_w.end_tag(); } -#[cfg(stage0)] -fn encode_symbol(ecx: @EncodeContext, ebml_w: &writer::Encoder, id: node_id) { - ebml_w.start_tag(tag_items_data_item_symbol); - match ecx.item_symbols.find(&id) { - Some(x) => { - debug!("encode_symbol(id=%?, str=%s)", id, *x); - ebml_w.writer.write(str::to_bytes(*x)); - } - None => { - ecx.diag.handler().bug( - fmt!("encode_symbol: id not found %d", id)); - } - } - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_symbol(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, id: node_id) { @@ -501,16 +284,6 @@ fn encode_symbol(ecx: @EncodeContext, ebml_w.end_tag(); } -#[cfg(stage0)] -fn encode_discriminant(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - id: node_id) { - ebml_w.start_tag(tag_items_data_item_symbol); - ebml_w.writer.write(str::to_bytes(**ecx.discrim_symbols.get(&id))); - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_discriminant(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, id: node_id) { @@ -519,16 +292,6 @@ fn encode_discriminant(ecx: @EncodeContext, ebml_w.end_tag(); } -#[cfg(stage0)] -fn encode_disr_val(_: @EncodeContext, - ebml_w: &writer::Encoder, - disr_val: int) { - ebml_w.start_tag(tag_disr_val); - ebml_w.writer.write(str::to_bytes(int::to_str(disr_val))); - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_disr_val(_: @EncodeContext, ebml_w: &mut writer::Encoder, disr_val: int) { @@ -537,65 +300,12 @@ fn encode_disr_val(_: @EncodeContext, ebml_w.end_tag(); } -#[cfg(stage0)] -fn encode_parent_item(ebml_w: &writer::Encoder, id: def_id) { - ebml_w.start_tag(tag_items_data_parent_item); - ebml_w.writer.write(str::to_bytes(def_to_str(id))); - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_parent_item(ebml_w: &mut writer::Encoder, id: def_id) { ebml_w.start_tag(tag_items_data_parent_item); ebml_w.writer.write(str::to_bytes(def_to_str(id))); ebml_w.end_tag(); } -#[cfg(stage0)] -fn encode_enum_variant_info(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - id: node_id, - variants: &[variant], - path: &[ast_map::path_elt], - index: @mut ~[entry], - generics: &ast::Generics) { - debug!("encode_enum_variant_info(id=%?)", id); - - let mut disr_val = 0; - let mut i = 0; - let vi = ty::enum_variants(ecx.tcx, - ast::def_id { crate: local_crate, node: id }); - for variants.each |variant| { - index.push(entry {val: variant.node.id, pos: ebml_w.writer.tell()}); - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(variant.node.id)); - encode_family(ebml_w, 'v'); - encode_name(ecx, ebml_w, variant.node.name); - encode_parent_item(ebml_w, local_def(id)); - encode_type(ecx, ebml_w, - node_id_to_type(ecx.tcx, variant.node.id)); - match variant.node.kind { - ast::tuple_variant_kind(ref args) - if args.len() > 0 && generics.ty_params.len() == 0 => { - encode_symbol(ecx, ebml_w, variant.node.id); - } - ast::tuple_variant_kind(_) | ast::struct_variant_kind(_) => {} - } - encode_discriminant(ecx, ebml_w, variant.node.id); - if vi[i].disr_val != disr_val { - encode_disr_val(ecx, ebml_w, vi[i].disr_val); - disr_val = vi[i].disr_val; - } - encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); - encode_path(ecx, ebml_w, path, - ast_map::path_name(variant.node.name)); - ebml_w.end_tag(); - disr_val += 1; - i += 1; - } -} - -#[cfg(not(stage0))] fn encode_enum_variant_info(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, id: node_id, @@ -639,31 +349,6 @@ fn encode_enum_variant_info(ecx: @EncodeContext, } } -#[cfg(stage0)] -fn encode_path(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - path: &[ast_map::path_elt], - name: ast_map::path_elt) { - fn encode_path_elt(ecx: @EncodeContext, ebml_w: &writer::Encoder, - elt: ast_map::path_elt) { - let (tag, name) = match elt { - ast_map::path_mod(name) => (tag_path_elt_mod, name), - ast_map::path_name(name) => (tag_path_elt_name, name) - }; - - ebml_w.wr_tagged_str(tag, *ecx.tcx.sess.str_of(name)); - } - - do ebml_w.wr_tag(tag_path) { - ebml_w.wr_tagged_u32(tag_path_len, (path.len() + 1) as u32); - for path.each |pe| { - encode_path_elt(ecx, ebml_w, *pe); - } - encode_path_elt(ecx, ebml_w, name); - } -} - -#[cfg(not(stage0))] fn encode_path(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, path: &[ast_map::path_elt], @@ -688,9 +373,8 @@ fn encode_path(ecx: @EncodeContext, ebml_w.end_tag(); } -#[cfg(stage0)] fn encode_info_for_mod(ecx: @EncodeContext, - ebml_w: &writer::Encoder, + ebml_w: &mut writer::Encoder, md: &_mod, id: node_id, path: &[ast_map::path_elt], @@ -750,101 +434,15 @@ fn encode_info_for_mod(ecx: @EncodeContext, ebml_w.end_tag(); } -#[cfg(not(stage0))] -fn encode_info_for_mod(ecx: @EncodeContext, - ebml_w: &mut writer::Encoder, - md: &_mod, - id: node_id, - path: &[ast_map::path_elt], - name: ident) { - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(id)); - encode_family(ebml_w, 'm'); - encode_name(ecx, ebml_w, name); - debug!("(encoding info for module) encoding info for module ID %d", id); +fn encode_struct_field_family(ebml_w: &mut writer::Encoder, + visibility: visibility) { + encode_family(ebml_w, match visibility { + public => 'g', + private => 'j', + inherited => 'N' + }); +} - // Encode info about all the module children. - for md.items.each |item| { - match item.node { - item_impl(*) => { - let (ident, did) = (item.ident, item.id); - debug!("(encoding info for module) ... encoding impl %s \ - (%?/%?)", - *ecx.tcx.sess.str_of(ident), - did, - ast_map::node_id_to_str(ecx.tcx.items, did, ecx.tcx - .sess.parse_sess.interner)); - - ebml_w.start_tag(tag_mod_impl); - ebml_w.wr_str(def_to_str(local_def(did))); - ebml_w.end_tag(); - } - _ => {} // FIXME #4573: Encode these too. - } - } - - encode_path(ecx, ebml_w, path, ast_map::path_mod(name)); - - // Encode the reexports of this module. - debug!("(encoding info for module) encoding reexports for %d", id); - match ecx.reexports2.find(&id) { - Some(ref exports) => { - debug!("(encoding info for module) found reexports for %d", id); - for exports.each |exp| { - debug!("(encoding info for module) reexport '%s' for %d", - *exp.name, id); - ebml_w.start_tag(tag_items_data_item_reexport); - ebml_w.start_tag(tag_items_data_item_reexport_def_id); - ebml_w.wr_str(def_to_str(exp.def_id)); - ebml_w.end_tag(); - ebml_w.start_tag(tag_items_data_item_reexport_name); - ebml_w.wr_str(*exp.name); - ebml_w.end_tag(); - ebml_w.end_tag(); - } - } - None => { - debug!("(encoding info for module) found no reexports for %d", - id); - } - } - - ebml_w.end_tag(); -} - -#[cfg(stage0)] -fn encode_struct_field_family(ebml_w: &writer::Encoder, - visibility: visibility) { - encode_family(ebml_w, match visibility { - public => 'g', - private => 'j', - inherited => 'N' - }); -} - -#[cfg(not(stage0))] -fn encode_struct_field_family(ebml_w: &mut writer::Encoder, - visibility: visibility) { - encode_family(ebml_w, match visibility { - public => 'g', - private => 'j', - inherited => 'N' - }); -} - -#[cfg(stage0)] -fn encode_visibility(ebml_w: &writer::Encoder, visibility: visibility) { - ebml_w.start_tag(tag_items_data_item_visibility); - let ch = match visibility { - public => 'y', - private => 'n', - inherited => 'i', - }; - ebml_w.wr_str(str::from_char(ch)); - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_visibility(ebml_w: &mut writer::Encoder, visibility: visibility) { ebml_w.start_tag(tag_items_data_item_visibility); let ch = match visibility { @@ -856,52 +454,6 @@ fn encode_visibility(ebml_w: &mut writer::Encoder, visibility: visibility) { ebml_w.end_tag(); } -#[cfg(stage0)] -fn encode_self_type(ebml_w: &writer::Encoder, self_type: ast::self_ty_) { - ebml_w.start_tag(tag_item_trait_method_self_ty); - - // Encode the base self type. - match self_type { - sty_static => { - ebml_w.writer.write(&[ 's' as u8 ]); - } - sty_value => { - ebml_w.writer.write(&[ 'v' as u8 ]); - } - sty_region(_, m) => { - // FIXME(#4846) encode custom lifetime - ebml_w.writer.write(&[ '&' as u8 ]); - encode_mutability(ebml_w, m); - } - sty_box(m) => { - ebml_w.writer.write(&[ '@' as u8 ]); - encode_mutability(ebml_w, m); - } - sty_uniq(m) => { - ebml_w.writer.write(&[ '~' as u8 ]); - encode_mutability(ebml_w, m); - } - } - - ebml_w.end_tag(); - - fn encode_mutability(ebml_w: &writer::Encoder, - m: ast::mutability) { - match m { - m_imm => { - ebml_w.writer.write(&[ 'i' as u8 ]); - } - m_mutbl => { - ebml_w.writer.write(&[ 'm' as u8 ]); - } - m_const => { - ebml_w.writer.write(&[ 'c' as u8 ]); - } - } - } -} - -#[cfg(not(stage0))] fn encode_self_type(ebml_w: &mut writer::Encoder, self_type: ast::self_ty_) { ebml_w.start_tag(tag_item_trait_method_self_ty); @@ -946,14 +498,6 @@ fn encode_self_type(ebml_w: &mut writer::Encoder, self_type: ast::self_ty_) { } } -#[cfg(stage0)] -fn encode_method_sort(ebml_w: &writer::Encoder, sort: char) { - ebml_w.start_tag(tag_item_trait_method_sort); - ebml_w.writer.write(&[ sort as u8 ]); - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_method_sort(ebml_w: &mut writer::Encoder, sort: char) { ebml_w.start_tag(tag_item_trait_method_sort); ebml_w.writer.write(&[ sort as u8 ]); @@ -961,47 +505,6 @@ fn encode_method_sort(ebml_w: &mut writer::Encoder, sort: char) { } /* Returns an index of items in this class */ -#[cfg(stage0)] -fn encode_info_for_struct(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - path: &[ast_map::path_elt], - fields: &[@struct_field], - global_index: @mut~[entry]) - -> ~[entry] { - /* Each class has its own index, since different classes - may have fields with the same name */ - let index = @mut ~[]; - let tcx = ecx.tcx; - /* We encode both private and public fields -- need to include - private fields to get the offsets right */ - for fields.each |field| { - let (nm, mt, vis) = match field.node.kind { - named_field(nm, mt, vis) => (nm, mt, vis), - unnamed_field => ( - special_idents::unnamed_field, - struct_immutable, - inherited - ) - }; - - let id = field.node.id; - index.push(entry {val: id, pos: ebml_w.writer.tell()}); - global_index.push(entry {val: id, pos: ebml_w.writer.tell()}); - ebml_w.start_tag(tag_items_data_item); - debug!("encode_info_for_struct: doing %s %d", - *tcx.sess.str_of(nm), id); - encode_struct_field_family(ebml_w, vis); - encode_name(ecx, ebml_w, nm); - encode_path(ecx, ebml_w, path, ast_map::path_name(nm)); - encode_type(ecx, ebml_w, node_id_to_type(tcx, id)); - encode_mutability(ebml_w, mt); - encode_def_id(ebml_w, local_def(id)); - ebml_w.end_tag(); - } - /*bad*/copy *index -} - -#[cfg(not(stage0))] fn encode_info_for_struct(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, path: &[ast_map::path_elt], @@ -1042,37 +545,6 @@ fn encode_info_for_struct(ecx: @EncodeContext, } // This is for encoding info for ctors and dtors -#[cfg(stage0)] -fn encode_info_for_ctor(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - id: node_id, - ident: ident, - path: &[ast_map::path_elt], - item: Option, - generics: &ast::Generics) { - ebml_w.start_tag(tag_items_data_item); - encode_name(ecx, ebml_w, ident); - encode_def_id(ebml_w, local_def(id)); - encode_family(ebml_w, purity_fn_family(ast::impure_fn)); - encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); - let its_ty = node_id_to_type(ecx.tcx, id); - debug!("fn name = %s ty = %s its node id = %d", - *ecx.tcx.sess.str_of(ident), - ty_to_str(ecx.tcx, its_ty), id); - encode_type(ecx, ebml_w, its_ty); - encode_path(ecx, ebml_w, path, ast_map::path_name(ident)); - match item { - Some(it) => { - (ecx.encode_inlined_item)(ecx, ebml_w, path, it); - } - None => { - encode_symbol(ecx, ebml_w, id); - } - } - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_info_for_ctor(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, id: node_id, @@ -1094,512 +566,121 @@ fn encode_info_for_ctor(ecx: @EncodeContext, match item { Some(it) => { (ecx.encode_inlined_item)(ecx, ebml_w, path, it); - } - None => { - encode_symbol(ecx, ebml_w, id); - } - } - ebml_w.end_tag(); -} - -#[cfg(stage0)] -fn encode_info_for_struct_ctor(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - path: &[ast_map::path_elt], - name: ast::ident, - ctor_id: node_id, - index: @mut ~[entry]) { - index.push(entry { val: ctor_id, pos: ebml_w.writer.tell() }); - - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(ctor_id)); - encode_family(ebml_w, 'f'); - encode_name(ecx, ebml_w, name); - encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, ctor_id)); - encode_path(ecx, ebml_w, path, ast_map::path_name(name)); - - if ecx.item_symbols.contains_key(&ctor_id) { - encode_symbol(ecx, ebml_w, ctor_id); - } - - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] -fn encode_info_for_struct_ctor(ecx: @EncodeContext, - ebml_w: &mut writer::Encoder, - path: &[ast_map::path_elt], - name: ast::ident, - ctor_id: node_id, - index: @mut ~[entry]) { - index.push(entry { val: ctor_id, pos: ebml_w.writer.tell() }); - - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(ctor_id)); - encode_family(ebml_w, 'f'); - encode_name(ecx, ebml_w, name); - encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, ctor_id)); - encode_path(ecx, ebml_w, path, ast_map::path_name(name)); - - if ecx.item_symbols.contains_key(&ctor_id) { - encode_symbol(ecx, ebml_w, ctor_id); - } - - ebml_w.end_tag(); -} - -#[cfg(stage0)] -fn encode_method_ty_fields(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - method_ty: &ty::method) { - encode_def_id(ebml_w, method_ty.def_id); - encode_name(ecx, ebml_w, method_ty.ident); - encode_ty_type_param_defs(ebml_w, ecx, - method_ty.generics.type_param_defs, - tag_item_method_tps); - encode_transformed_self_ty(ecx, ebml_w, method_ty.transformed_self_ty); - encode_method_fty(ecx, ebml_w, &method_ty.fty); - encode_visibility(ebml_w, method_ty.vis); - encode_self_type(ebml_w, method_ty.self_ty); -} - -#[cfg(not(stage0))] -fn encode_method_ty_fields(ecx: @EncodeContext, - ebml_w: &mut writer::Encoder, - method_ty: &ty::method) { - encode_def_id(ebml_w, method_ty.def_id); - encode_name(ecx, ebml_w, method_ty.ident); - encode_ty_type_param_defs(ebml_w, ecx, - method_ty.generics.type_param_defs, - tag_item_method_tps); - encode_transformed_self_ty(ecx, ebml_w, method_ty.transformed_self_ty); - encode_method_fty(ecx, ebml_w, &method_ty.fty); - encode_visibility(ebml_w, method_ty.vis); - encode_self_type(ebml_w, method_ty.self_ty); -} - -#[cfg(stage0)] -fn encode_info_for_method(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - impl_path: &[ast_map::path_elt], - should_inline: bool, - parent_id: node_id, - m: @method, - owner_generics: &ast::Generics, - method_generics: &ast::Generics) { - debug!("encode_info_for_method: %d %s %u %u", m.id, - *ecx.tcx.sess.str_of(m.ident), - owner_generics.ty_params.len(), - method_generics.ty_params.len()); - ebml_w.start_tag(tag_items_data_item); - - let method_def_id = local_def(m.id); - let method_ty: @ty::method = ty::method(ecx.tcx, method_def_id); - encode_method_ty_fields(ecx, ebml_w, method_ty); - - match m.self_ty.node { - ast::sty_static => { - encode_family(ebml_w, purity_static_method_family(m.purity)); - } - _ => encode_family(ebml_w, purity_fn_family(m.purity)) - } - - let mut combined_ty_params = opt_vec::Empty; - combined_ty_params.push_all(&owner_generics.ty_params); - combined_ty_params.push_all(&method_generics.ty_params); - let len = combined_ty_params.len(); - encode_type_param_bounds(ebml_w, ecx, &combined_ty_params); - - encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id)); - encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident)); - - if len > 0u || should_inline { - (ecx.encode_inlined_item)( - ecx, ebml_w, impl_path, - ii_method(local_def(parent_id), m)); - } else { - encode_symbol(ecx, ebml_w, m.id); - } - - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] -fn encode_info_for_method(ecx: @EncodeContext, - ebml_w: &mut writer::Encoder, - impl_path: &[ast_map::path_elt], - should_inline: bool, - parent_id: node_id, - m: @method, - owner_generics: &ast::Generics, - method_generics: &ast::Generics) { - debug!("encode_info_for_method: %d %s %u %u", m.id, - *ecx.tcx.sess.str_of(m.ident), - owner_generics.ty_params.len(), - method_generics.ty_params.len()); - ebml_w.start_tag(tag_items_data_item); - - let method_def_id = local_def(m.id); - let method_ty: @ty::method = ty::method(ecx.tcx, method_def_id); - encode_method_ty_fields(ecx, ebml_w, method_ty); - - match m.self_ty.node { - ast::sty_static => { - encode_family(ebml_w, purity_static_method_family(m.purity)); - } - _ => encode_family(ebml_w, purity_fn_family(m.purity)) - } - - let mut combined_ty_params = opt_vec::Empty; - combined_ty_params.push_all(&owner_generics.ty_params); - combined_ty_params.push_all(&method_generics.ty_params); - let len = combined_ty_params.len(); - encode_type_param_bounds(ebml_w, ecx, &combined_ty_params); - - encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id)); - encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident)); - - if len > 0u || should_inline { - (ecx.encode_inlined_item)( - ecx, ebml_w, impl_path, - ii_method(local_def(parent_id), m)); - } else { - encode_symbol(ecx, ebml_w, m.id); - } - - ebml_w.end_tag(); -} - -fn purity_fn_family(p: purity) -> char { - match p { - unsafe_fn => 'u', - pure_fn => 'p', - impure_fn => 'f', - extern_fn => 'e' - } -} - -fn purity_static_method_family(p: purity) -> char { - match p { - unsafe_fn => 'U', - pure_fn => 'P', - impure_fn => 'F', - _ => fail!(~"extern fn can't be static") - } -} - - -fn should_inline(attrs: &[attribute]) -> bool { - match attr::find_inline_attr(attrs) { - attr::ia_none | attr::ia_never => false, - attr::ia_hint | attr::ia_always => true - } -} - -#[cfg(stage0)] -fn encode_info_for_item(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - item: @item, - index: @mut ~[entry], - path: &[ast_map::path_elt]) { - let tcx = ecx.tcx; - let must_write = - match item.node { - item_enum(_, _) | item_impl(*) | item_trait(*) | item_struct(*) | - item_mod(*) | item_foreign_mod(*) | item_const(*) => true, - _ => false - }; - if !must_write && !reachable(ecx, item.id) { return; } - - fn add_to_index_(item: @item, ebml_w: &writer::Encoder, - index: @mut ~[entry]) { - index.push(entry { val: item.id, pos: ebml_w.writer.tell() }); - } - let add_to_index: &fn() = || add_to_index_(item, ebml_w, index); - - debug!("encoding info for item at %s", - ecx.tcx.sess.codemap.span_to_str(item.span)); - - match item.node { - item_const(_, _) => { - add_to_index(); - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'c'); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - encode_symbol(ecx, ebml_w, item.id); - encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); - ebml_w.end_tag(); - } - item_fn(_, purity, _, ref generics, _) => { - add_to_index(); - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, purity_fn_family(purity)); - let tps_len = generics.ty_params.len(); - encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - encode_attributes(ebml_w, item.attrs); - if tps_len > 0u || should_inline(item.attrs) { - (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); - } else { - encode_symbol(ecx, ebml_w, item.id); - } - ebml_w.end_tag(); - } - item_mod(ref m) => { - add_to_index(); - encode_info_for_mod(ecx, ebml_w, m, item.id, path, item.ident); - } - item_foreign_mod(_) => { - add_to_index(); - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'n'); - encode_name(ecx, ebml_w, item.ident); - encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - ebml_w.end_tag(); - } - item_ty(_, ref generics) => { - add_to_index(); - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'y'); - encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - encode_name(ecx, ebml_w, item.ident); - encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - encode_region_param(ecx, ebml_w, item); - ebml_w.end_tag(); - } - item_enum(ref enum_definition, ref generics) => { - add_to_index(); - do ebml_w.wr_tag(tag_items_data_item) { - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 't'); - encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - encode_name(ecx, ebml_w, item.ident); - for (*enum_definition).variants.each |v| { - encode_variant_id(ebml_w, local_def(v.node.id)); - } - (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); - encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - encode_region_param(ecx, ebml_w, item); - } - encode_enum_variant_info(ecx, - ebml_w, - item.id, - (*enum_definition).variants, - path, - index, - generics); - } - item_struct(struct_def, ref generics) => { - /* First, encode the fields - These come first because we need to write them to make - the index, and the index needs to be in the item for the - class itself */ - let idx = encode_info_for_struct(ecx, ebml_w, path, - struct_def.fields, index); - - /* Index the class*/ - add_to_index(); - - /* Now, make an item for the class itself */ - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'S'); - encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - - // If this is a tuple- or enum-like struct, encode the type of the - // constructor. - if struct_def.fields.len() > 0 && - struct_def.fields[0].node.kind == ast::unnamed_field { - let ctor_id = match struct_def.ctor_id { - Some(ctor_id) => ctor_id, - None => ecx.tcx.sess.bug(~"struct def didn't have ctor id"), - }; - - encode_info_for_struct_ctor(ecx, - ebml_w, - path, - item.ident, - ctor_id, - index); - } - - encode_name(ecx, ebml_w, item.ident); - encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - encode_region_param(ecx, ebml_w, item); - - /* Encode def_ids for each field and method - for methods, write all the stuff get_trait_method - needs to know*/ - for struct_def.fields.each |f| { - match f.node.kind { - named_field(ident, _, vis) => { - ebml_w.start_tag(tag_item_field); - encode_struct_field_family(ebml_w, vis); - encode_name(ecx, ebml_w, ident); - encode_def_id(ebml_w, local_def(f.node.id)); - ebml_w.end_tag(); - } - unnamed_field => { - ebml_w.start_tag(tag_item_unnamed_field); - encode_def_id(ebml_w, local_def(f.node.id)); - ebml_w.end_tag(); - } - } - } - - /* Each class has its own index -- encode it */ - let bkts = create_index(idx); - encode_index(ebml_w, bkts, write_int); - ebml_w.end_tag(); - } - item_impl(ref generics, opt_trait, ty, ref methods) => { - add_to_index(); - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'i'); - encode_region_param(ecx, ebml_w, item); - encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); - encode_type(ecx, ebml_w, node_id_to_type(tcx, item.id)); - encode_name(ecx, ebml_w, item.ident); - encode_attributes(ebml_w, item.attrs); - match ty.node { - ast::ty_path(path, _) if path.idents.len() == 1 => { - encode_impl_type_basename(ecx, ebml_w, - ast_util::path_to_ident(path)); - } - _ => {} - } - for methods.each |m| { - ebml_w.start_tag(tag_item_impl_method); - let method_def_id = local_def(m.id); - ebml_w.writer.write(str::to_bytes(def_to_str(method_def_id))); - ebml_w.end_tag(); - } - for opt_trait.each |ast_trait_ref| { - let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id); - encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_trait_ref); - } - encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - ebml_w.end_tag(); - - // >:-< - let mut impl_path = vec::append(~[], path); - impl_path += ~[ast_map::path_name(item.ident)]; - - for methods.each |m| { - index.push(entry {val: m.id, pos: ebml_w.writer.tell()}); - encode_info_for_method(ecx, - ebml_w, - impl_path, - should_inline(m.attrs), - item.id, - *m, - generics, - &m.generics); - } - } - item_trait(ref generics, ref super_traits, ref ms) => { - add_to_index(); - ebml_w.start_tag(tag_items_data_item); - encode_def_id(ebml_w, local_def(item.id)); - encode_family(ebml_w, 'I'); - encode_region_param(ecx, ebml_w, item); - encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); - let trait_def = ty::lookup_trait_def(tcx, local_def(item.id)); - encode_trait_ref(ebml_w, ecx, trait_def.trait_ref, tag_item_trait_ref); - encode_name(ecx, ebml_w, item.ident); - encode_attributes(ebml_w, item.attrs); - for ty::trait_method_def_ids(tcx, local_def(item.id)).each |&method_def_id| { - ebml_w.start_tag(tag_item_trait_method); - encode_def_id(ebml_w, method_def_id); - ebml_w.end_tag(); - } - encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); - for super_traits.each |ast_trait_ref| { - let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id); - encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_super_trait_ref); + } + None => { + encode_symbol(ecx, ebml_w, id); + } } ebml_w.end_tag(); +} - // Now output the method info for each method. - for ty::trait_method_def_ids(tcx, local_def(item.id)).eachi |i, &method_def_id| { - assert!(method_def_id.crate == ast::local_crate); +fn encode_info_for_struct_ctor(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + path: &[ast_map::path_elt], + name: ast::ident, + ctor_id: node_id, + index: @mut ~[entry]) { + index.push(entry { val: ctor_id, pos: ebml_w.writer.tell() }); - let method_ty: @ty::method = ty::method(tcx, method_def_id); + ebml_w.start_tag(tag_items_data_item); + encode_def_id(ebml_w, local_def(ctor_id)); + encode_family(ebml_w, 'f'); + encode_name(ecx, ebml_w, name); + encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, ctor_id)); + encode_path(ecx, ebml_w, path, ast_map::path_name(name)); - index.push(entry {val: method_def_id.node, pos: ebml_w.writer.tell()}); + if ecx.item_symbols.contains_key(&ctor_id) { + encode_symbol(ecx, ebml_w, ctor_id); + } - ebml_w.start_tag(tag_items_data_item); + ebml_w.end_tag(); +} - encode_method_ty_fields(ecx, ebml_w, method_ty); +fn encode_method_ty_fields(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + method_ty: &ty::method) { + encode_def_id(ebml_w, method_ty.def_id); + encode_name(ecx, ebml_w, method_ty.ident); + encode_ty_type_param_defs(ebml_w, ecx, + method_ty.generics.type_param_defs, + tag_item_method_tps); + encode_transformed_self_ty(ecx, ebml_w, method_ty.transformed_self_ty); + encode_method_fty(ecx, ebml_w, &method_ty.fty); + encode_visibility(ebml_w, method_ty.vis); + encode_self_type(ebml_w, method_ty.self_ty); +} - encode_parent_item(ebml_w, local_def(item.id)); +fn encode_info_for_method(ecx: @EncodeContext, + ebml_w: &mut writer::Encoder, + impl_path: &[ast_map::path_elt], + should_inline: bool, + parent_id: node_id, + m: @method, + owner_generics: &ast::Generics, + method_generics: &ast::Generics) { + debug!("encode_info_for_method: %d %s %u %u", m.id, + *ecx.tcx.sess.str_of(m.ident), + owner_generics.ty_params.len(), + method_generics.ty_params.len()); + ebml_w.start_tag(tag_items_data_item); - let mut trait_path = vec::append(~[], path); - trait_path.push(ast_map::path_name(item.ident)); - encode_path(ecx, ebml_w, trait_path, ast_map::path_name(method_ty.ident)); + let method_def_id = local_def(m.id); + let method_ty: @ty::method = ty::method(ecx.tcx, method_def_id); + encode_method_ty_fields(ecx, ebml_w, method_ty); - match method_ty.self_ty { - sty_static => { - encode_family(ebml_w, - purity_static_method_family( - method_ty.fty.purity)); + match m.self_ty.node { + ast::sty_static => { + encode_family(ebml_w, purity_static_method_family(m.purity)); + } + _ => encode_family(ebml_w, purity_fn_family(m.purity)) + } - let tpt = ty::lookup_item_type(tcx, method_def_id); - encode_ty_type_param_defs(ebml_w, ecx, - tpt.generics.type_param_defs, - tag_items_data_item_ty_param_bounds); - encode_type(ecx, ebml_w, tpt.ty); - } + let mut combined_ty_params = opt_vec::Empty; + combined_ty_params.push_all(&owner_generics.ty_params); + combined_ty_params.push_all(&method_generics.ty_params); + let len = combined_ty_params.len(); + encode_type_param_bounds(ebml_w, ecx, &combined_ty_params); - _ => { - encode_family(ebml_w, - purity_fn_family( - method_ty.fty.purity)); - } - } + encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, m.id)); + encode_path(ecx, ebml_w, impl_path, ast_map::path_name(m.ident)); - match ms[i] { - required(_) => { - encode_method_sort(ebml_w, 'r'); - } + if len > 0u || should_inline { + (ecx.encode_inlined_item)( + ecx, ebml_w, impl_path, + ii_method(local_def(parent_id), m)); + } else { + encode_symbol(ecx, ebml_w, m.id); + } - provided(m) => { - // This is obviously a bogus assert but I don't think this - // ever worked before anyhow...near as I can tell, before - // we would emit two items. - if method_ty.self_ty == sty_static { - tcx.sess.span_unimpl( - item.span, - fmt!("Method %s is both provided and static", - *tcx.sess.intr().get(method_ty.ident))); - } - encode_type_param_bounds(ebml_w, ecx, - &m.generics.ty_params); - encode_method_sort(ebml_w, 'p'); - (ecx.encode_inlined_item)( - ecx, ebml_w, path, - ii_method(local_def(item.id), m)); - } - } + ebml_w.end_tag(); +} - ebml_w.end_tag(); - } - } - item_mac(*) => fail!(~"item macros unimplemented") +fn purity_fn_family(p: purity) -> char { + match p { + unsafe_fn => 'u', + pure_fn => 'p', + impure_fn => 'f', + extern_fn => 'e' + } +} + +fn purity_static_method_family(p: purity) -> char { + match p { + unsafe_fn => 'U', + pure_fn => 'P', + impure_fn => 'F', + _ => fail!(~"extern fn can't be static") + } +} + + +fn should_inline(attrs: &[attribute]) -> bool { + match attr::find_inline_attr(attrs) { + attr::ia_none | attr::ia_never => false, + attr::ia_hint | attr::ia_always => true } } -#[cfg(not(stage0))] fn encode_info_for_item(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, item: @item, @@ -1904,42 +985,6 @@ fn encode_info_for_item(ecx: @EncodeContext, } } -#[cfg(stage0)] -fn encode_info_for_foreign_item(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - nitem: @foreign_item, - index: @mut ~[entry], - path: ast_map::path, - abi: AbiSet) { - if !reachable(ecx, nitem.id) { return; } - index.push(entry { val: nitem.id, pos: ebml_w.writer.tell() }); - - ebml_w.start_tag(tag_items_data_item); - match nitem.node { - foreign_item_fn(_, purity, ref generics) => { - encode_def_id(ebml_w, local_def(nitem.id)); - encode_family(ebml_w, purity_fn_family(purity)); - encode_type_param_bounds(ebml_w, ecx, &generics.ty_params); - encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); - if abi.is_intrinsic() { - (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_foreign(nitem)); - } else { - encode_symbol(ecx, ebml_w, nitem.id); - } - encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident)); - } - foreign_item_const(*) => { - encode_def_id(ebml_w, local_def(nitem.id)); - encode_family(ebml_w, 'c'); - encode_type(ecx, ebml_w, node_id_to_type(ecx.tcx, nitem.id)); - encode_symbol(ecx, ebml_w, nitem.id); - encode_path(ecx, ebml_w, path, ast_map::path_name(nitem.ident)); - } - } - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_info_for_foreign_item(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, nitem: @foreign_item, @@ -1974,54 +1019,6 @@ fn encode_info_for_foreign_item(ecx: @EncodeContext, ebml_w.end_tag(); } -#[cfg(stage0)] -fn encode_info_for_items(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - crate: &crate) - -> ~[entry] { - let index = @mut ~[]; - ebml_w.start_tag(tag_items_data); - index.push(entry { val: crate_node_id, pos: ebml_w.writer.tell() }); - encode_info_for_mod(ecx, ebml_w, &crate.node.module, - crate_node_id, ~[], - syntax::parse::token::special_idents::invalid); - visit::visit_crate(crate, (), visit::mk_vt(@visit::Visitor { - visit_expr: |_e, _cx, _v| { }, - visit_item: { - let ebml_w = copy *ebml_w; - |i, cx, v| { - visit::visit_item(i, cx, v); - match *ecx.tcx.items.get(&i.id) { - ast_map::node_item(_, pt) => { - encode_info_for_item(ecx, &ebml_w, i, - index, *pt); - } - _ => fail!(~"bad item") - } - } - }, - visit_foreign_item: { - let ebml_w = copy *ebml_w; - |ni, cx, v| { - visit::visit_foreign_item(ni, cx, v); - match *ecx.tcx.items.get(&ni.id) { - ast_map::node_foreign_item(_, abi, _, pt) => { - encode_info_for_foreign_item(ecx, &ebml_w, ni, - index, /*bad*/copy *pt, - abi); - } - // case for separate item and foreign-item tables - _ => fail!(~"bad foreign item") - } - } - }, - ..*visit::default_visitor() - })); - ebml_w.end_tag(); - return /*bad*/copy *index; -} - -#[cfg(not(stage0))] fn encode_info_for_items(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, crate: &crate) @@ -2077,51 +1074,20 @@ fn encode_info_for_items(ecx: @EncodeContext, fn create_index(index: ~[entry]) -> ~[@~[entry]] { - let mut buckets: ~[@mut ~[entry]] = ~[]; - for uint::range(0u, 256u) |_i| { buckets.push(@mut ~[]); }; - for index.each |elt| { - let h = elt.val.hash() as uint; - buckets[h % 256].push(*elt); - } - - let mut buckets_frozen = ~[]; - for buckets.each |bucket| { - buckets_frozen.push(@/*bad*/copy **bucket); - } - return buckets_frozen; -} - -#[cfg(stage0)] -fn encode_index(ebml_w: &writer::Encoder, - buckets: ~[@~[entry]], - write_fn: &fn(@io::Writer, &T)) { - let writer = ebml_w.writer; - ebml_w.start_tag(tag_index); - let mut bucket_locs: ~[uint] = ~[]; - ebml_w.start_tag(tag_index_buckets); - for buckets.each |bucket| { - bucket_locs.push(ebml_w.writer.tell()); - ebml_w.start_tag(tag_index_buckets_bucket); - for vec::each(**bucket) |elt| { - ebml_w.start_tag(tag_index_buckets_bucket_elt); - assert!(elt.pos < 0xffff_ffff); - writer.write_be_u32(elt.pos as u32); - write_fn(writer, &elt.val); - ebml_w.end_tag(); - } - ebml_w.end_tag(); + let mut buckets: ~[@mut ~[entry]] = ~[]; + for uint::range(0u, 256u) |_i| { buckets.push(@mut ~[]); }; + for index.each |elt| { + let h = elt.val.hash() as uint; + buckets[h % 256].push(*elt); } - ebml_w.end_tag(); - ebml_w.start_tag(tag_index_table); - for bucket_locs.each |pos| { - assert!(*pos < 0xffff_ffff); - writer.write_be_u32(*pos as u32); + + let mut buckets_frozen = ~[]; + for buckets.each |bucket| { + buckets_frozen.push(@/*bad*/copy **bucket); } - ebml_w.end_tag(); - ebml_w.end_tag(); + return buckets_frozen; } -#[cfg(not(stage0))] fn encode_index(ebml_w: &mut writer::Encoder, buckets: ~[@~[entry]], write_fn: &fn(@io::Writer, &T)) { @@ -2160,45 +1126,6 @@ fn write_int(writer: @io::Writer, &n: &int) { writer.write_be_u32(n as u32); } -#[cfg(stage0)] -fn encode_meta_item(ebml_w: &writer::Encoder, mi: @meta_item) { - match mi.node { - meta_word(name) => { - ebml_w.start_tag(tag_meta_item_word); - ebml_w.start_tag(tag_meta_item_name); - ebml_w.writer.write(str::to_bytes(*name)); - ebml_w.end_tag(); - ebml_w.end_tag(); - } - meta_name_value(name, value) => { - match value.node { - lit_str(value) => { - ebml_w.start_tag(tag_meta_item_name_value); - ebml_w.start_tag(tag_meta_item_name); - ebml_w.writer.write(str::to_bytes(*name)); - ebml_w.end_tag(); - ebml_w.start_tag(tag_meta_item_value); - ebml_w.writer.write(str::to_bytes(*value)); - ebml_w.end_tag(); - ebml_w.end_tag(); - } - _ => {/* FIXME (#623): encode other variants */ } - } - } - meta_list(name, ref items) => { - ebml_w.start_tag(tag_meta_item_list); - ebml_w.start_tag(tag_meta_item_name); - ebml_w.writer.write(str::to_bytes(*name)); - ebml_w.end_tag(); - for items.each |inner_item| { - encode_meta_item(ebml_w, *inner_item); - } - ebml_w.end_tag(); - } - } -} - -#[cfg(not(stage0))] fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @meta_item) { match mi.node { meta_word(name) => { @@ -2236,18 +1163,6 @@ fn encode_meta_item(ebml_w: &mut writer::Encoder, mi: @meta_item) { } } -#[cfg(stage0)] -fn encode_attributes(ebml_w: &writer::Encoder, attrs: &[attribute]) { - ebml_w.start_tag(tag_attributes); - for attrs.each |attr| { - ebml_w.start_tag(tag_attribute); - encode_meta_item(ebml_w, attr.node.value); - ebml_w.end_tag(); - } - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_attributes(ebml_w: &mut writer::Encoder, attrs: &[attribute]) { ebml_w.start_tag(tag_attributes); for attrs.each |attr| { @@ -2312,50 +1227,6 @@ fn synthesize_crate_attrs(ecx: @EncodeContext, return attrs; } -#[cfg(stage0)] -fn encode_crate_deps(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - cstore: @mut cstore::CStore) { - fn get_ordered_deps(ecx: @EncodeContext, cstore: @mut cstore::CStore) - -> ~[decoder::crate_dep] { - type numdep = decoder::crate_dep; - - // Pull the cnums and name,vers,hash out of cstore - let mut deps = ~[]; - do cstore::iter_crate_data(cstore) |key, val| { - let dep = decoder::crate_dep {cnum: key, - name: ecx.tcx.sess.ident_of(/*bad*/ copy *val.name), - vers: decoder::get_crate_vers(val.data), - hash: decoder::get_crate_hash(val.data)}; - deps.push(dep); - }; - - // Sort by cnum - std::sort::quick_sort(deps, |kv1, kv2| kv1.cnum <= kv2.cnum); - - // Sanity-check the crate numbers - let mut expected_cnum = 1; - for deps.each |n| { - assert!((n.cnum == expected_cnum)); - expected_cnum += 1; - } - - // mut -> immutable hack for vec::map - deps.slice(0, deps.len()).to_owned() - } - - // We're just going to write a list of crate 'name-hash-version's, with - // the assumption that they are numbered 1 to n. - // FIXME (#2166): This is not nearly enough to support correct versioning - // but is enough to get transitive crate dependencies working. - ebml_w.start_tag(tag_crate_deps); - for get_ordered_deps(ecx, cstore).each |dep| { - encode_crate_dep(ecx, ebml_w, *dep); - } - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_crate_deps(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, cstore: @mut cstore::CStore) { @@ -2398,32 +1269,6 @@ fn encode_crate_deps(ecx: @EncodeContext, ebml_w.end_tag(); } -#[cfg(stage0)] -fn encode_lang_items(ecx: @EncodeContext, ebml_w: &writer::Encoder) { - ebml_w.start_tag(tag_lang_items); - - for ecx.tcx.lang_items.each_item |def_id, i| { - if def_id.crate != local_crate { - loop; - } - - ebml_w.start_tag(tag_lang_items_item); - - ebml_w.start_tag(tag_lang_items_item_id); - ebml_w.writer.write_be_u32(i as u32); - ebml_w.end_tag(); // tag_lang_items_item_id - - ebml_w.start_tag(tag_lang_items_item_node_id); - ebml_w.writer.write_be_u32(def_id.node as u32); - ebml_w.end_tag(); // tag_lang_items_item_node_id - - ebml_w.end_tag(); // tag_lang_items_item - } - - ebml_w.end_tag(); // tag_lang_items -} - -#[cfg(not(stage0))] fn encode_lang_items(ecx: @EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.start_tag(tag_lang_items); @@ -2448,21 +1293,6 @@ fn encode_lang_items(ecx: @EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.end_tag(); // tag_lang_items } -#[cfg(stage0)] -fn encode_link_args(ecx: @EncodeContext, ebml_w: &writer::Encoder) { - ebml_w.start_tag(tag_link_args); - - let link_args = cstore::get_used_link_args(ecx.cstore); - for link_args.each |link_arg| { - ebml_w.start_tag(tag_link_args_arg); - ebml_w.writer.write_str(link_arg.to_str()); - ebml_w.end_tag(); - } - - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_link_args(ecx: @EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.start_tag(tag_link_args); @@ -2476,24 +1306,6 @@ fn encode_link_args(ecx: @EncodeContext, ebml_w: &mut writer::Encoder) { ebml_w.end_tag(); } -#[cfg(stage0)] -fn encode_crate_dep(ecx: @EncodeContext, - ebml_w: &writer::Encoder, - dep: decoder::crate_dep) { - ebml_w.start_tag(tag_crate_dep); - ebml_w.start_tag(tag_crate_dep_name); - ebml_w.writer.write(str::to_bytes(*ecx.tcx.sess.str_of(dep.name))); - ebml_w.end_tag(); - ebml_w.start_tag(tag_crate_dep_vers); - ebml_w.writer.write(str::to_bytes(*dep.vers)); - ebml_w.end_tag(); - ebml_w.start_tag(tag_crate_dep_hash); - ebml_w.writer.write(str::to_bytes(*dep.hash)); - ebml_w.end_tag(); - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_crate_dep(ecx: @EncodeContext, ebml_w: &mut writer::Encoder, dep: decoder::crate_dep) { @@ -2510,14 +1322,6 @@ fn encode_crate_dep(ecx: @EncodeContext, ebml_w.end_tag(); } -#[cfg(stage0)] -fn encode_hash(ebml_w: &writer::Encoder, hash: &str) { - ebml_w.start_tag(tag_crate_hash); - ebml_w.writer.write(str::to_bytes(hash)); - ebml_w.end_tag(); -} - -#[cfg(not(stage0))] fn encode_hash(ebml_w: &mut writer::Encoder, hash: &str) { ebml_w.start_tag(tag_crate_hash); ebml_w.writer.write(str::to_bytes(hash)); @@ -2532,114 +1336,6 @@ pub static metadata_encoding_version : &'static [u8] = 0x74, //'t' as u8, 0, 0, 0, 1 ]; -#[cfg(stage0)] -pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { - let wr = @io::BytesWriter(); - let stats = Stats { - inline_bytes: 0, - attr_bytes: 0, - dep_bytes: 0, - lang_item_bytes: 0, - link_args_bytes: 0, - item_bytes: 0, - index_bytes: 0, - zero_bytes: 0, - total_bytes: 0, - n_inlines: 0 - }; - let EncodeParams{item_symbols, diag, tcx, reachable, reexports2, - discrim_symbols, cstore, encode_inlined_item, - link_meta, _} = parms; - let ecx = @EncodeContext { - diag: diag, - tcx: tcx, - stats: @mut stats, - reachable: reachable, - reexports2: reexports2, - item_symbols: item_symbols, - discrim_symbols: discrim_symbols, - link_meta: link_meta, - cstore: cstore, - encode_inlined_item: encode_inlined_item, - type_abbrevs: @mut HashMap::new() - }; - - let ebml_w = writer::Encoder(wr as @io::Writer); - - encode_hash(&ebml_w, ecx.link_meta.extras_hash); - - let mut i = wr.pos; - let crate_attrs = synthesize_crate_attrs(ecx, crate); - encode_attributes(&ebml_w, crate_attrs); - ecx.stats.attr_bytes = wr.pos - i; - - i = wr.pos; - encode_crate_deps(ecx, &ebml_w, ecx.cstore); - ecx.stats.dep_bytes = wr.pos - i; - - // Encode the language items. - i = wr.pos; - encode_lang_items(ecx, &ebml_w); - ecx.stats.lang_item_bytes = wr.pos - i; - - // Encode the link args. - i = wr.pos; - encode_link_args(ecx, &ebml_w); - ecx.stats.link_args_bytes = wr.pos - i; - - // Encode and index the items. - ebml_w.start_tag(tag_items); - i = wr.pos; - let items_index = encode_info_for_items(ecx, &ebml_w, crate); - ecx.stats.item_bytes = wr.pos - i; - - i = wr.pos; - let items_buckets = create_index(items_index); - encode_index(&ebml_w, items_buckets, write_int); - ecx.stats.index_bytes = wr.pos - i; - ebml_w.end_tag(); - - ecx.stats.total_bytes = wr.pos; - - if (tcx.sess.meta_stats()) { - - do wr.bytes.each |e| { - if *e == 0 { - ecx.stats.zero_bytes += 1; - } - true - } - - io::println("metadata stats:"); - io::println(fmt!(" inline bytes: %u", ecx.stats.inline_bytes)); - io::println(fmt!(" attribute bytes: %u", ecx.stats.attr_bytes)); - io::println(fmt!(" dep bytes: %u", ecx.stats.dep_bytes)); - io::println(fmt!(" lang item bytes: %u", ecx.stats.lang_item_bytes)); - io::println(fmt!(" link args bytes: %u", ecx.stats.link_args_bytes)); - io::println(fmt!(" item bytes: %u", ecx.stats.item_bytes)); - io::println(fmt!(" index bytes: %u", ecx.stats.index_bytes)); - io::println(fmt!(" zero bytes: %u", ecx.stats.zero_bytes)); - io::println(fmt!(" total bytes: %u", ecx.stats.total_bytes)); - } - - // Pad this, since something (LLVM, presumably) is cutting off the - // remaining % 4 bytes. - wr.write(&[0u8, 0u8, 0u8, 0u8]); - - // FIXME #3396: weird bug here, for reasons unclear this emits random - // looking bytes (mostly 0x1) if we use the version byte-array constant - // above; so we use a string constant inline instead. - // - // Should be: - // - // vec::from_slice(metadata_encoding_version) + - - (do str::as_bytes(&~"rust\x00\x00\x00\x01") |bytes| { - vec::slice(*bytes, 0, 8).to_vec() - }) + flate::deflate_bytes(wr.bytes) -} - -#[cfg(not(stage0))] pub fn encode_metadata(parms: EncodeParams, crate: &crate) -> ~[u8] { let wr = @io::BytesWriter(); let stats = Stats { diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 2a9f19fc84695..c6f01153a906e 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -77,31 +77,6 @@ trait tr_intern { // ______________________________________________________________________ // Top-level methods. -#[cfg(stage0)] -pub fn encode_inlined_item(ecx: @e::EncodeContext, - ebml_w: &writer::Encoder, - path: &[ast_map::path_elt], - ii: ast::inlined_item, - maps: Maps) { - debug!("> Encoding inlined item: %s::%s (%u)", - ast_map::path_to_str(path, ecx.tcx.sess.parse_sess.interner), - *ecx.tcx.sess.str_of(ii.ident()), - ebml_w.writer.tell()); - - let id_range = ast_util::compute_id_range_for_inlined_item(&ii); - do ebml_w.wr_tag(c::tag_ast as uint) { - id_range.encode(ebml_w); - encode_ast(ebml_w, simplify_ast(&ii)); - encode_side_tables_for_ii(ecx, maps, ebml_w, &ii); - } - - debug!("< Encoded inlined fn: %s::%s (%u)", - ast_map::path_to_str(path, ecx.tcx.sess.parse_sess.interner), - *ecx.tcx.sess.str_of(ii.ident()), - ebml_w.writer.tell()); -} - -#[cfg(not(stage0))] pub fn encode_inlined_item(ecx: @e::EncodeContext, ebml_w: &mut writer::Encoder, path: &[ast_map::path_elt], @@ -126,53 +101,6 @@ pub fn encode_inlined_item(ecx: @e::EncodeContext, ebml_w.writer.tell()); } -#[cfg(stage0)] -pub fn decode_inlined_item(cdata: @cstore::crate_metadata, - tcx: ty::ctxt, - maps: Maps, - path: ast_map::path, - par_doc: ebml::Doc) - -> Option { - let dcx = @DecodeContext { - cdata: cdata, - tcx: tcx, - maps: maps - }; - match par_doc.opt_child(c::tag_ast) { - None => None, - Some(ast_doc) => { - debug!("> Decoding inlined fn: %s::?", - ast_map::path_to_str(path, tcx.sess.parse_sess.interner)); - let ast_dsr = &reader::Decoder(ast_doc); - let from_id_range = Decodable::decode(ast_dsr); - let to_id_range = reserve_id_range(dcx.tcx.sess, from_id_range); - let xcx = @ExtendedDecodeContext { - dcx: dcx, - from_id_range: from_id_range, - to_id_range: to_id_range - }; - let raw_ii = decode_ast(ast_doc); - let ii = renumber_ast(xcx, raw_ii); - debug!("Fn named: %s", *tcx.sess.str_of(ii.ident())); - debug!("< Decoded inlined fn: %s::%s", - ast_map::path_to_str(path, tcx.sess.parse_sess.interner), - *tcx.sess.str_of(ii.ident())); - ast_map::map_decoded_item(tcx.sess.diagnostic(), - dcx.tcx.items, path, &ii); - decode_side_tables(xcx, ast_doc); - match ii { - ast::ii_item(i) => { - debug!(">>> DECODED ITEM >>>\n%s\n<<< DECODED ITEM <<<", - syntax::print::pprust::item_to_str(i, tcx.sess.intr())); - } - _ => { } - } - Some(ii) - } - } -} - -#[cfg(not(stage0))] pub fn decode_inlined_item(cdata: @cstore::crate_metadata, tcx: ty::ctxt, maps: Maps, @@ -309,49 +237,20 @@ impl tr for span { } } -#[cfg(stage0)] -trait def_id_encoder_helpers { - fn emit_def_id(&self, did: ast::def_id); -} - -#[cfg(not(stage0))] trait def_id_encoder_helpers { fn emit_def_id(&mut self, did: ast::def_id); } -#[cfg(stage0)] -impl def_id_encoder_helpers for S { - fn emit_def_id(&self, did: ast::def_id) { - did.encode(self) - } -} - -#[cfg(not(stage0))] impl def_id_encoder_helpers for S { fn emit_def_id(&mut self, did: ast::def_id) { did.encode(self) } } -#[cfg(stage0)] -trait def_id_decoder_helpers { - fn read_def_id(&self, xcx: @ExtendedDecodeContext) -> ast::def_id; -} - -#[cfg(not(stage0))] trait def_id_decoder_helpers { fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id; } -#[cfg(stage0)] -impl def_id_decoder_helpers for D { - fn read_def_id(&self, xcx: @ExtendedDecodeContext) -> ast::def_id { - let did: ast::def_id = Decodable::decode(self); - did.tr(xcx) - } -} - -#[cfg(not(stage0))] impl def_id_decoder_helpers for D { fn read_def_id(&mut self, xcx: @ExtendedDecodeContext) -> ast::def_id { let did: ast::def_id = Decodable::decode(self); @@ -374,14 +273,6 @@ impl def_id_decoder_helpers for D { // We also have to adjust the spans: for now we just insert a dummy span, // but eventually we should add entries to the local codemap as required. -#[cfg(stage0)] -fn encode_ast(ebml_w: &writer::Encoder, item: ast::inlined_item) { - do ebml_w.wr_tag(c::tag_tree as uint) { - item.encode(ebml_w) - } -} - -#[cfg(not(stage0))] fn encode_ast(ebml_w: &mut writer::Encoder, item: ast::inlined_item) { ebml_w.start_tag(c::tag_tree as uint); item.encode(ebml_w); @@ -439,14 +330,6 @@ fn simplify_ast(ii: &ast::inlined_item) -> ast::inlined_item { } } -#[cfg(stage0)] -fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item { - let chi_doc = par_doc.get(c::tag_tree as uint); - let d = &reader::Decoder(chi_doc); - Decodable::decode(d) -} - -#[cfg(not(stage0))] fn decode_ast(par_doc: ebml::Doc) -> ast::inlined_item { let chi_doc = par_doc.get(c::tag_tree as uint); let mut d = reader::Decoder(chi_doc); @@ -477,24 +360,10 @@ fn renumber_ast(xcx: @ExtendedDecodeContext, ii: ast::inlined_item) // ______________________________________________________________________ // Encoding and decoding of ast::def -#[cfg(stage0)] -fn encode_def(ebml_w: &writer::Encoder, def: ast::def) { - def.encode(ebml_w) -} - -#[cfg(not(stage0))] fn encode_def(ebml_w: &mut writer::Encoder, def: ast::def) { def.encode(ebml_w) } -#[cfg(stage0)] -fn decode_def(xcx: @ExtendedDecodeContext, doc: ebml::Doc) -> ast::def { - let dsr = &reader::Decoder(doc); - let def: ast::def = Decodable::decode(dsr); - def.tr(xcx) -} - -#[cfg(not(stage0))] fn decode_def(xcx: @ExtendedDecodeContext, doc: ebml::Doc) -> ast::def { let mut dsr = reader::Decoder(doc); let def: ast::def = Decodable::decode(&mut dsr); @@ -602,38 +471,15 @@ impl tr for ty::bound_region { // ______________________________________________________________________ // Encoding and decoding of freevar information -#[cfg(stage0)] -fn encode_freevar_entry(ebml_w: &writer::Encoder, fv: @freevar_entry) { - (*fv).encode(ebml_w) -} - -#[cfg(not(stage0))] fn encode_freevar_entry(ebml_w: &mut writer::Encoder, fv: @freevar_entry) { (*fv).encode(ebml_w) } -#[cfg(stage0)] -trait ebml_decoder_helper { - fn read_freevar_entry(&self, xcx: @ExtendedDecodeContext) - -> freevar_entry; -} - -#[cfg(not(stage0))] trait ebml_decoder_helper { fn read_freevar_entry(&mut self, xcx: @ExtendedDecodeContext) -> freevar_entry; } -#[cfg(stage0)] -impl ebml_decoder_helper for reader::Decoder { - fn read_freevar_entry(&self, xcx: @ExtendedDecodeContext) - -> freevar_entry { - let fv: freevar_entry = Decodable::decode(self); - fv.tr(xcx) - } -} - -#[cfg(not(stage0))] impl ebml_decoder_helper for reader::Decoder { fn read_freevar_entry(&mut self, xcx: @ExtendedDecodeContext) -> freevar_entry { @@ -654,28 +500,11 @@ impl tr for freevar_entry { // ______________________________________________________________________ // Encoding and decoding of CaptureVar information -#[cfg(stage0)] -trait capture_var_helper { - fn read_capture_var(&self, xcx: @ExtendedDecodeContext) - -> moves::CaptureVar; -} - -#[cfg(not(stage0))] trait capture_var_helper { fn read_capture_var(&mut self, xcx: @ExtendedDecodeContext) -> moves::CaptureVar; } -#[cfg(stage0)] -impl capture_var_helper for reader::Decoder { - fn read_capture_var(&self, xcx: @ExtendedDecodeContext) - -> moves::CaptureVar { - let cvar: moves::CaptureVar = Decodable::decode(self); - cvar.tr(xcx) - } -} - -#[cfg(not(stage0))] impl capture_var_helper for reader::Decoder { fn read_capture_var(&mut self, xcx: @ExtendedDecodeContext) -> moves::CaptureVar { @@ -698,35 +527,10 @@ impl tr for moves::CaptureVar { // Encoding and decoding of method_map_entry trait read_method_map_entry_helper { - #[cfg(stage0)] - fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) - -> method_map_entry; - #[cfg(not(stage0))] fn read_method_map_entry(&mut self, xcx: @ExtendedDecodeContext) -> method_map_entry; } -#[cfg(stage0)] -fn encode_method_map_entry(ecx: @e::EncodeContext, - ebml_w: &writer::Encoder, - mme: method_map_entry) { - do ebml_w.emit_struct("method_map_entry", 3) { - do ebml_w.emit_field(~"self_arg", 0u) { - ebml_w.emit_arg(ecx, mme.self_arg); - } - do ebml_w.emit_field(~"explicit_self", 2u) { - mme.explicit_self.encode(ebml_w); - } - do ebml_w.emit_field(~"origin", 1u) { - mme.origin.encode(ebml_w); - } - do ebml_w.emit_field(~"self_mode", 3) { - mme.self_mode.encode(ebml_w); - } - } -} - -#[cfg(not(stage0))] fn encode_method_map_entry(ecx: @e::EncodeContext, ebml_w: &mut writer::Encoder, mme: method_map_entry) { @@ -747,32 +551,6 @@ fn encode_method_map_entry(ecx: @e::EncodeContext, } impl read_method_map_entry_helper for reader::Decoder { - #[cfg(stage0)] - fn read_method_map_entry(&self, xcx: @ExtendedDecodeContext) - -> method_map_entry { - do self.read_struct("method_map_entry", 3) { - method_map_entry { - self_arg: self.read_field(~"self_arg", 0u, || { - self.read_arg(xcx) - }), - explicit_self: self.read_field(~"explicit_self", 2u, || { - let self_type: ast::self_ty_ = Decodable::decode(self); - self_type - }), - origin: self.read_field(~"origin", 1u, || { - let method_origin: method_origin = - Decodable::decode(self); - method_origin.tr(xcx) - }), - self_mode: self.read_field(~"self_mode", 3, || { - let self_mode: ty::SelfMode = Decodable::decode(self); - self_mode - }), - } - } - } - - #[cfg(not(stage0))] fn read_method_map_entry(&mut self, xcx: @ExtendedDecodeContext) -> method_map_entry { do self.read_struct("method_map_entry", 3) |this| { @@ -830,20 +608,6 @@ impl tr for method_origin { // ______________________________________________________________________ // Encoding and decoding vtable_res -#[cfg(stage0)] -fn encode_vtable_res(ecx: @e::EncodeContext, - ebml_w: &writer::Encoder, - dr: typeck::vtable_res) { - // can't autogenerate this code because automatic code of - // ty::t doesn't work, and there is no way (atm) to have - // hand-written encoding routines combine with auto-generated - // ones. perhaps we should fix this. - do ebml_w.emit_from_vec(*dr) |vtable_origin| { - encode_vtable_origin(ecx, ebml_w, vtable_origin) - } -} - -#[cfg(not(stage0))] fn encode_vtable_res(ecx: @e::EncodeContext, ebml_w: &mut writer::Encoder, dr: typeck::vtable_res) { @@ -856,40 +620,6 @@ fn encode_vtable_res(ecx: @e::EncodeContext, } } -#[cfg(stage0)] -fn encode_vtable_origin(ecx: @e::EncodeContext, - ebml_w: &writer::Encoder, - vtable_origin: &typeck::vtable_origin) { - do ebml_w.emit_enum(~"vtable_origin") { - match *vtable_origin { - typeck::vtable_static(def_id, ref tys, vtable_res) => { - do ebml_w.emit_enum_variant(~"vtable_static", 0u, 3u) { - do ebml_w.emit_enum_variant_arg(0u) { - ebml_w.emit_def_id(def_id) - } - do ebml_w.emit_enum_variant_arg(1u) { - ebml_w.emit_tys(ecx, /*bad*/copy *tys); - } - do ebml_w.emit_enum_variant_arg(2u) { - encode_vtable_res(ecx, ebml_w, vtable_res); - } - } - } - typeck::vtable_param(pn, bn) => { - do ebml_w.emit_enum_variant(~"vtable_param", 1u, 2u) { - do ebml_w.emit_enum_variant_arg(0u) { - ebml_w.emit_uint(pn); - } - do ebml_w.emit_enum_variant_arg(1u) { - ebml_w.emit_uint(bn); - } - } - } - } - } -} - -#[cfg(not(stage0))] fn encode_vtable_origin(ecx: @e::EncodeContext, ebml_w: &mut writer::Encoder, vtable_origin: &typeck::vtable_origin) { @@ -923,70 +653,18 @@ fn encode_vtable_origin(ecx: @e::EncodeContext, } trait vtable_decoder_helpers { - #[cfg(stage0)] - fn read_vtable_res(&self, xcx: @ExtendedDecodeContext) - -> typeck::vtable_res; - #[cfg(not(stage0))] fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_res; - #[cfg(stage0)] - fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext) - -> typeck::vtable_origin; - #[cfg(not(stage0))] fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_origin; } impl vtable_decoder_helpers for reader::Decoder { - #[cfg(stage0)] - fn read_vtable_res(&self, xcx: @ExtendedDecodeContext) - -> typeck::vtable_res { - @self.read_to_vec(|| self.read_vtable_origin(xcx)) - } - - #[cfg(not(stage0))] fn read_vtable_res(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_res { @self.read_to_vec(|this| this.read_vtable_origin(xcx)) } - #[cfg(stage0)] - fn read_vtable_origin(&self, xcx: @ExtendedDecodeContext) - -> typeck::vtable_origin { - do self.read_enum("vtable_origin") { - do self.read_enum_variant(["vtable_static", "vtable_param"]) |i| { - match i { - 0 => { - typeck::vtable_static( - do self.read_enum_variant_arg(0u) { - self.read_def_id(xcx) - }, - do self.read_enum_variant_arg(1u) { - self.read_tys(xcx) - }, - do self.read_enum_variant_arg(2u) { - self.read_vtable_res(xcx) - } - ) - } - 1 => { - typeck::vtable_param( - do self.read_enum_variant_arg(0u) { - self.read_uint() - }, - do self.read_enum_variant_arg(1u) { - self.read_uint() - } - ) - } - // hard to avoid - user input - _ => fail!(~"bad enum variant") - } - } - } - } - - #[cfg(not(stage0))] fn read_vtable_origin(&mut self, xcx: @ExtendedDecodeContext) -> typeck::vtable_origin { do self.read_enum("vtable_origin") |this| { @@ -1042,20 +720,6 @@ impl get_ty_str_ctxt for e::EncodeContext { } } -#[cfg(stage0)] -trait ebml_writer_helpers { - fn emit_arg(&self, ecx: @e::EncodeContext, arg: ty::arg); - fn emit_ty(&self, ecx: @e::EncodeContext, ty: ty::t); - fn emit_vstore(&self, ecx: @e::EncodeContext, vstore: ty::vstore); - fn emit_tys(&self, ecx: @e::EncodeContext, tys: ~[ty::t]); - fn emit_type_param_def(&self, - ecx: @e::EncodeContext, - type_param_def: &ty::TypeParameterDef); - fn emit_tpbt(&self, ecx: @e::EncodeContext, - tpbt: ty::ty_param_bounds_and_ty); -} - -#[cfg(not(stage0))] trait ebml_writer_helpers { fn emit_arg(&mut self, ecx: @e::EncodeContext, arg: ty::arg); fn emit_ty(&mut self, ecx: @e::EncodeContext, ty: ty::t); @@ -1070,73 +734,30 @@ trait ebml_writer_helpers { } impl ebml_writer_helpers for writer::Encoder { - #[cfg(stage0)] - fn emit_ty(&self, ecx: @e::EncodeContext, ty: ty::t) { - do self.emit_opaque { - e::write_type(ecx, self, ty) - } - } - - #[cfg(not(stage0))] fn emit_ty(&mut self, ecx: @e::EncodeContext, ty: ty::t) { do self.emit_opaque |this| { e::write_type(ecx, this, ty) } } - #[cfg(stage0)] - fn emit_vstore(&self, ecx: @e::EncodeContext, vstore: ty::vstore) { - do self.emit_opaque { - e::write_vstore(ecx, self, vstore) - } - } - - #[cfg(not(stage0))] fn emit_vstore(&mut self, ecx: @e::EncodeContext, vstore: ty::vstore) { do self.emit_opaque |this| { e::write_vstore(ecx, this, vstore) } } - #[cfg(stage0)] - fn emit_arg(&self, ecx: @e::EncodeContext, arg: ty::arg) { - do self.emit_opaque { - tyencode::enc_arg(self.writer, ecx.ty_str_ctxt(), arg); - } - } - - #[cfg(not(stage0))] fn emit_arg(&mut self, ecx: @e::EncodeContext, arg: ty::arg) { do self.emit_opaque |this| { tyencode::enc_arg(this.writer, ecx.ty_str_ctxt(), arg); } } - #[cfg(stage0)] - fn emit_tys(&self, ecx: @e::EncodeContext, tys: ~[ty::t]) { - do self.emit_from_vec(tys) |ty| { - self.emit_ty(ecx, *ty) - } - } - - #[cfg(not(stage0))] fn emit_tys(&mut self, ecx: @e::EncodeContext, tys: ~[ty::t]) { do self.emit_from_vec(tys) |this, ty| { this.emit_ty(ecx, *ty) } } - #[cfg(stage0)] - fn emit_type_param_def(&self, - ecx: @e::EncodeContext, - type_param_def: &ty::TypeParameterDef) { - do self.emit_opaque { - tyencode::enc_type_param_def(self.writer, ecx.ty_str_ctxt(), - type_param_def) - } - } - - #[cfg(not(stage0))] fn emit_type_param_def(&mut self, ecx: @e::EncodeContext, type_param_def: &ty::TypeParameterDef) { @@ -1147,31 +768,6 @@ impl ebml_writer_helpers for writer::Encoder { } } - #[cfg(stage0)] - fn emit_tpbt(&self, - ecx: @e::EncodeContext, - tpbt: ty::ty_param_bounds_and_ty) { - do self.emit_struct("ty_param_bounds_and_ty", 2) { - do self.emit_field(~"generics", 0) { - do self.emit_struct("Generics", 2) { - do self.emit_field(~"type_param_defs", 0) { - do self.emit_from_vec(*tpbt.generics.type_param_defs) - |type_param_def| { - self.emit_type_param_def(ecx, type_param_def); - } - } - do self.emit_field(~"region_param", 1) { - tpbt.generics.region_param.encode(self); - } - } - } - do self.emit_field(~"ty", 1) { - self.emit_ty(ecx, tpbt.ty); - } - } - } - - #[cfg(not(stage0))] fn emit_tpbt(&mut self, ecx: @e::EncodeContext, tpbt: ty::ty_param_bounds_and_ty) { @@ -1196,30 +792,11 @@ impl ebml_writer_helpers for writer::Encoder { } } -#[cfg(stage0)] -trait write_tag_and_id { - fn tag(&self, tag_id: c::astencode_tag, f: &fn()); - fn id(&self, id: ast::node_id); -} - -#[cfg(not(stage0))] trait write_tag_and_id { fn tag(&mut self, tag_id: c::astencode_tag, f: &fn(&mut Self)); fn id(&mut self, id: ast::node_id); } -#[cfg(stage0)] -impl write_tag_and_id for writer::Encoder { - fn tag(&self, tag_id: c::astencode_tag, f: &fn()) { - do self.wr_tag(tag_id as uint) { f() } - } - - fn id(&self, id: ast::node_id) { - self.wr_tagged_u64(c::tag_table_id as uint, id as u64) - } -} - -#[cfg(not(stage0))] impl write_tag_and_id for writer::Encoder { fn tag(&mut self, tag_id: c::astencode_tag, @@ -1234,26 +811,6 @@ impl write_tag_and_id for writer::Encoder { } } -#[cfg(stage0)] -fn encode_side_tables_for_ii(ecx: @e::EncodeContext, - maps: Maps, - ebml_w: &writer::Encoder, - ii: &ast::inlined_item) { - do ebml_w.wr_tag(c::tag_table as uint) { - let ebml_w = copy *ebml_w; - ast_util::visit_ids_for_inlined_item( - ii, - |id: ast::node_id| { - // Note: this will cause a copy of ebml_w, which is bad as - // it has mut fields. But I believe it's harmless since - // we generate balanced EBML. - /*let ebml_w = copy ebml_w;*/ - encode_side_tables_for_id(ecx, maps, &ebml_w, id) - }); - } -} - -#[cfg(not(stage0))] fn encode_side_tables_for_ii(ecx: @e::EncodeContext, maps: Maps, ebml_w: &mut writer::Encoder, @@ -1272,137 +829,6 @@ fn encode_side_tables_for_ii(ecx: @e::EncodeContext, ebml_w.end_tag(); } -#[cfg(stage0)] -fn encode_side_tables_for_id(ecx: @e::EncodeContext, - maps: Maps, - ebml_w: &writer::Encoder, - id: ast::node_id) { - let tcx = ecx.tcx; - - debug!("Encoding side tables for id %d", id); - - for tcx.def_map.find(&id).each |def| { - do ebml_w.tag(c::tag_table_def) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - (*def).encode(ebml_w) - } - } - } - - for tcx.node_types.find(&(id as uint)).each |&ty| { - do ebml_w.tag(c::tag_table_node_type) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - ebml_w.emit_ty(ecx, *ty); - } - } - } - - for tcx.node_type_substs.find(&id).each |tys| { - do ebml_w.tag(c::tag_table_node_type_subst) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - // FIXME(#5562): removing this copy causes a segfault - // before stage2 - ebml_w.emit_tys(ecx, /*bad*/copy **tys) - } - } - } - - for tcx.freevars.find(&id).each |&fv| { - do ebml_w.tag(c::tag_table_freevars) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - do ebml_w.emit_from_vec(**fv) |fv_entry| { - encode_freevar_entry(ebml_w, *fv_entry) - } - } - } - } - - let lid = ast::def_id { crate: ast::local_crate, node: id }; - for tcx.tcache.find(&lid).each |&tpbt| { - do ebml_w.tag(c::tag_table_tcache) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - ebml_w.emit_tpbt(ecx, *tpbt); - } - } - } - - for tcx.ty_param_defs.find(&id).each |&type_param_def| { - do ebml_w.tag(c::tag_table_param_defs) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - ebml_w.emit_type_param_def(ecx, type_param_def) - } - } - } - - if maps.mutbl_map.contains(&id) { - do ebml_w.tag(c::tag_table_mutbl) { - ebml_w.id(id); - } - } - - for maps.last_use_map.find(&id).each |&m| { - do ebml_w.tag(c::tag_table_last_use) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - do ebml_w.emit_from_vec(/*bad*/ copy **m) |id| { - id.encode(ebml_w); - } - } - } - } - - for maps.method_map.find(&id).each |&mme| { - do ebml_w.tag(c::tag_table_method_map) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - encode_method_map_entry(ecx, ebml_w, *mme) - } - } - } - - for maps.vtable_map.find(&id).each |&dr| { - do ebml_w.tag(c::tag_table_vtable_map) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - encode_vtable_res(ecx, ebml_w, *dr); - } - } - } - - for tcx.adjustments.find(&id).each |adj| { - do ebml_w.tag(c::tag_table_adjustments) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - (**adj).encode(ebml_w) - } - } - } - - if maps.moves_map.contains(&id) { - do ebml_w.tag(c::tag_table_moves_map) { - ebml_w.id(id); - } - } - - for maps.capture_map.find(&id).each |&cap_vars| { - do ebml_w.tag(c::tag_table_capture_map) { - ebml_w.id(id); - do ebml_w.tag(c::tag_table_val) { - do ebml_w.emit_from_vec(*cap_vars) |cap_var| { - cap_var.encode(ebml_w); - } - } - } - } -} - -#[cfg(not(stage0))] fn encode_side_tables_for_id(ecx: @e::EncodeContext, maps: Maps, ebml_w: &mut writer::Encoder, @@ -1544,20 +970,6 @@ impl doc_decoder_helpers for ebml::Doc { } } -#[cfg(stage0)] -trait ebml_decoder_decoder_helpers { - fn read_arg(&self, xcx: @ExtendedDecodeContext) -> ty::arg; - fn read_ty(&self, xcx: @ExtendedDecodeContext) -> ty::t; - fn read_tys(&self, xcx: @ExtendedDecodeContext) -> ~[ty::t]; - fn read_type_param_def(&self, xcx: @ExtendedDecodeContext) -> ty::TypeParameterDef; - fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) - -> ty::ty_param_bounds_and_ty; - fn convert_def_id(&self, xcx: @ExtendedDecodeContext, - source: DefIdSource, - did: ast::def_id) -> ast::def_id; -} - -#[cfg(not(stage0))] trait ebml_decoder_decoder_helpers { fn read_arg(&mut self, xcx: @ExtendedDecodeContext) -> ty::arg; fn read_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::t; @@ -1574,16 +986,6 @@ trait ebml_decoder_decoder_helpers { } impl ebml_decoder_decoder_helpers for reader::Decoder { - #[cfg(stage0)] - fn read_arg(&self, xcx: @ExtendedDecodeContext) -> ty::arg { - do self.read_opaque |doc| { - tydecode::parse_arg_data( - doc.data, xcx.dcx.cdata.cnum, doc.start, xcx.dcx.tcx, - |s, a| self.convert_def_id(xcx, s, a)) - } - } - - #[cfg(not(stage0))] fn read_arg(&mut self, xcx: @ExtendedDecodeContext) -> ty::arg { do self.read_opaque |this, doc| { tydecode::parse_arg_data( @@ -1595,35 +997,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } - #[cfg(stage0)] - fn read_ty(&self, xcx: @ExtendedDecodeContext) -> ty::t { - // Note: regions types embed local node ids. In principle, we - // should translate these node ids into the new decode - // context. However, we do not bother, because region types - // are not used during trans. - - return do self.read_opaque |doc| { - - let ty = tydecode::parse_ty_data( - doc.data, xcx.dcx.cdata.cnum, doc.start, xcx.dcx.tcx, - |s, a| self.convert_def_id(xcx, s, a)); - - debug!("read_ty(%s) = %s", - type_string(doc), ty_to_str(xcx.dcx.tcx, ty)); - - ty - }; - - fn type_string(doc: ebml::Doc) -> ~str { - let mut str = ~""; - for uint::range(doc.start, doc.end) |i| { - str::push_char(&mut str, doc.data[i] as char); - } - str - } - } - - #[cfg(not(stage0))] fn read_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::t { // Note: regions types embed local node ids. In principle, we // should translate these node ids into the new decode @@ -1654,27 +1027,10 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } - #[cfg(stage0)] - fn read_tys(&self, xcx: @ExtendedDecodeContext) -> ~[ty::t] { - self.read_to_vec(|| self.read_ty(xcx) ) - } - - #[cfg(not(stage0))] fn read_tys(&mut self, xcx: @ExtendedDecodeContext) -> ~[ty::t] { self.read_to_vec(|this| this.read_ty(xcx) ) } - #[cfg(stage0)] - fn read_type_param_def(&self, xcx: @ExtendedDecodeContext) - -> ty::TypeParameterDef { - do self.read_opaque |doc| { - tydecode::parse_type_param_def_data( - doc.data, doc.start, xcx.dcx.cdata.cnum, xcx.dcx.tcx, - |s, a| self.convert_def_id(xcx, s, a)) - } - } - - #[cfg(not(stage0))] fn read_type_param_def(&mut self, xcx: @ExtendedDecodeContext) -> ty::TypeParameterDef { do self.read_opaque |this, doc| { @@ -1687,31 +1043,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } - #[cfg(stage0)] - fn read_ty_param_bounds_and_ty(&self, xcx: @ExtendedDecodeContext) - -> ty::ty_param_bounds_and_ty { - do self.read_struct("ty_param_bounds_and_ty", 2) { - ty::ty_param_bounds_and_ty { - generics: do self.read_field("generics", 0) { - do self.read_struct("Generics", 2) { - ty::Generics { - type_param_defs: self.read_field("type_param_defs", 0, || { - @self.read_to_vec(|| self.read_type_param_def(xcx)) - }), - region_param: self.read_field(~"region_param", 1, || { - Decodable::decode(self) - }) - } - } - }, - ty: self.read_field(~"ty", 1, || { - self.read_ty(xcx) - }) - } - } - } - - #[cfg(not(stage0))] fn read_ty_param_bounds_and_ty(&mut self, xcx: @ExtendedDecodeContext) -> ty::ty_param_bounds_and_ty { do self.read_struct("ty_param_bounds_and_ty", 2) |this| { @@ -1742,35 +1073,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } - #[cfg(stage0)] - fn convert_def_id(&self, - xcx: @ExtendedDecodeContext, - source: tydecode::DefIdSource, - did: ast::def_id) - -> ast::def_id { - /*! - * - * Converts a def-id that appears in a type. The correct - * translation will depend on what kind of def-id this is. - * This is a subtle point: type definitions are not - * inlined into the current crate, so if the def-id names - * a nominal type or type alias, then it should be - * translated to refer to the source crate. - * - * However, *type parameters* are cloned along with the function - * they are attached to. So we should translate those def-ids - * to refer to the new, cloned copy of the type parameter. - */ - - let r = match source { - NominalType | TypeWithId => xcx.tr_def_id(did), - TypeParameter => xcx.tr_intern_def_id(did) - }; - debug!("convert_def_id(source=%?, did=%?)=%?", source, did, r); - return r; - } - - #[cfg(not(stage0))] fn convert_def_id(&mut self, xcx: @ExtendedDecodeContext, source: tydecode::DefIdSource, @@ -1799,82 +1101,6 @@ impl ebml_decoder_decoder_helpers for reader::Decoder { } } -#[cfg(stage0)] -fn decode_side_tables(xcx: @ExtendedDecodeContext, - ast_doc: ebml::Doc) { - let dcx = xcx.dcx; - let tbl_doc = ast_doc.get(c::tag_table as uint); - for reader::docs(tbl_doc) |tag, entry_doc| { - let id0 = entry_doc.get(c::tag_table_id as uint).as_int(); - let id = xcx.tr_id(id0); - - debug!(">> Side table document with tag 0x%x \ - found for id %d (orig %d)", - tag, id, id0); - - if tag == (c::tag_table_mutbl as uint) { - dcx.maps.mutbl_map.insert(id); - } else if tag == (c::tag_table_moves_map as uint) { - dcx.maps.moves_map.insert(id); - } else { - let val_doc = entry_doc.get(c::tag_table_val as uint); - let val_dsr = &reader::Decoder(val_doc); - if tag == (c::tag_table_def as uint) { - let def = decode_def(xcx, val_doc); - dcx.tcx.def_map.insert(id, def); - } else if tag == (c::tag_table_node_type as uint) { - let ty = val_dsr.read_ty(xcx); - debug!("inserting ty for node %?: %s", - id, ty_to_str(dcx.tcx, ty)); - dcx.tcx.node_types.insert(id as uint, ty); - } else if tag == (c::tag_table_node_type_subst as uint) { - let tys = val_dsr.read_tys(xcx); - dcx.tcx.node_type_substs.insert(id, tys); - } else if tag == (c::tag_table_freevars as uint) { - let fv_info = @val_dsr.read_to_vec(|| { - @val_dsr.read_freevar_entry(xcx) - }); - dcx.tcx.freevars.insert(id, fv_info); - } else if tag == (c::tag_table_tcache as uint) { - let tpbt = val_dsr.read_ty_param_bounds_and_ty(xcx); - let lid = ast::def_id { crate: ast::local_crate, node: id }; - dcx.tcx.tcache.insert(lid, tpbt); - } else if tag == (c::tag_table_param_defs as uint) { - let bounds = val_dsr.read_type_param_def(xcx); - dcx.tcx.ty_param_defs.insert(id, bounds); - } else if tag == (c::tag_table_last_use as uint) { - let ids = val_dsr.read_to_vec(|| { - xcx.tr_id(val_dsr.read_int()) - }); - dcx.maps.last_use_map.insert(id, @mut ids); - } else if tag == (c::tag_table_method_map as uint) { - dcx.maps.method_map.insert( - id, - val_dsr.read_method_map_entry(xcx)); - } else if tag == (c::tag_table_vtable_map as uint) { - dcx.maps.vtable_map.insert(id, - val_dsr.read_vtable_res(xcx)); - } else if tag == (c::tag_table_adjustments as uint) { - let adj: @ty::AutoAdjustment = @Decodable::decode(val_dsr); - adj.tr(xcx); - dcx.tcx.adjustments.insert(id, adj); - } else if tag == (c::tag_table_capture_map as uint) { - let cvars = - at_vec::from_owned( - val_dsr.read_to_vec( - || val_dsr.read_capture_var(xcx))); - dcx.maps.capture_map.insert(id, cvars); - } else { - xcx.dcx.tcx.sess.bug( - fmt!("unknown tag found in side tables: %x", tag)); - } - } - - debug!(">< Side table doc loaded"); - } -} - -#[cfg(not(stage0))] fn decode_side_tables(xcx: @ExtendedDecodeContext, ast_doc: ebml::Doc) { let dcx = xcx.dcx; diff --git a/src/libstd/arena.rs b/src/libstd/arena.rs index 67b5e5e654ad0..b9a09323f81d0 100644 --- a/src/libstd/arena.rs +++ b/src/libstd/arena.rs @@ -203,21 +203,6 @@ pub impl Arena { } #[inline(always)] - #[cfg(stage0)] - priv fn alloc_pod(&mut self, op: &fn() -> T) -> &'self T { - unsafe { - let tydesc = sys::get_type_desc::(); - let ptr = self.alloc_pod_inner((*tydesc).size, (*tydesc).align); - let ptr: *mut T = transmute(ptr); - rusti::move_val_init(&mut (*ptr), op()); - return transmute(ptr); - } - } - - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] priv fn alloc_pod<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T { unsafe { let tydesc = sys::get_type_desc::(); @@ -265,31 +250,6 @@ pub impl Arena { } #[inline(always)] - #[cfg(stage0)] - priv fn alloc_nonpod(&mut self, op: &fn() -> T) -> &'self T { - unsafe { - let tydesc = sys::get_type_desc::(); - let (ty_ptr, ptr) = - self.alloc_nonpod_inner((*tydesc).size, (*tydesc).align); - let ty_ptr: *mut uint = transmute(ty_ptr); - let ptr: *mut T = transmute(ptr); - // Write in our tydesc along with a bit indicating that it - // has *not* been initialized yet. - *ty_ptr = transmute(tydesc); - // Actually initialize it - rusti::move_val_init(&mut(*ptr), op()); - // Now that we are done, update the tydesc to indicate that - // the object is there. - *ty_ptr = bitpack_tydesc_ptr(tydesc, true); - - return transmute(ptr); - } - } - - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] priv fn alloc_nonpod<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T { unsafe { let tydesc = sys::get_type_desc::(); @@ -312,25 +272,6 @@ pub impl Arena { // The external interface #[inline(always)] - #[cfg(stage0)] - fn alloc(&mut self, op: &fn() -> T) -> &'self T { - unsafe { - // XXX: Borrow check - let this = transmute_mut_region(self); - if !rusti::needs_drop::() { - return this.alloc_pod(op); - } - // XXX: Borrow check - let this = transmute_mut_region(self); - this.alloc_nonpod(op) - } - } - - // The external interface - #[inline(always)] - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn alloc<'a, T>(&'a mut self, op: &fn() -> T) -> &'a T { unsafe { // XXX: Borrow check diff --git a/src/libstd/deque.rs b/src/libstd/deque.rs index 8a310a9f52b5e..65e71869a1f0f 100644 --- a/src/libstd/deque.rs +++ b/src/libstd/deque.rs @@ -37,128 +37,6 @@ impl Mutable for Deque { } } -#[cfg(stage0)] -pub impl Deque { - /// Create an empty Deque - fn new() -> Deque { - Deque{nelts: 0, lo: 0, hi: 0, - elts: vec::from_fn(initial_capacity, |_| None)} - } - - /// Return a reference to the first element in the deque - /// - /// Fails if the deque is empty - #[cfg(stage0)] - fn peek_front(&self) -> &'self T { get(self.elts, self.lo) } - - /// Return a reference to the first element in the deque - /// - /// Fails if the deque is empty - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn peek_front<'a>(&'a self) -> &'a T { get(self.elts, self.lo) } - - /// Return a reference to the last element in the deque - /// - /// Fails if the deque is empty - #[cfg(stage0)] - fn peek_back(&self) -> &'self T { get(self.elts, self.hi - 1u) } - - /// Return a reference to the last element in the deque - /// - /// Fails if the deque is empty - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn peek_back<'a>(&'a self) -> &'a T { get(self.elts, self.hi - 1u) } - - /// Retrieve an element in the deque by index - /// - /// Fails if there is no element with the given index - #[cfg(stage0)] - fn get(&self, i: int) -> &'self T { - let idx = (self.lo + (i as uint)) % self.elts.len(); - get(self.elts, idx) - } - - /// Retrieve an element in the deque by index - /// - /// Fails if there is no element with the given index - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn get<'a>(&'a self, i: int) -> &'a T { - let idx = (self.lo + (i as uint)) % self.elts.len(); - get(self.elts, idx) - } - - /// Iterate over the elements in the deque - fn each(&self, f: &fn(&T) -> bool) { - self.eachi(|_i, e| f(e)) - } - - /// Iterate over the elements in the deque by index - fn eachi(&self, f: &fn(uint, &T) -> bool) { - for uint::range(0, self.nelts) |i| { - if !f(i, self.get(i as int)) { return; } - } - } - - /// Remove and return the first element in the deque - /// - /// Fails if the deque is empty - fn pop_front(&mut self) -> T { - let result = self.elts[self.lo].swap_unwrap(); - self.lo = (self.lo + 1u) % self.elts.len(); - self.nelts -= 1u; - result - } - - /// Remove and return the last element in the deque - /// - /// Fails if the deque is empty - fn pop_back(&mut self) -> T { - if self.hi == 0u { - self.hi = self.elts.len() - 1u; - } else { self.hi -= 1u; } - let result = self.elts[self.hi].swap_unwrap(); - self.elts[self.hi] = None; - self.nelts -= 1u; - result - } - - /// Prepend an element to the deque - fn add_front(&mut self, t: T) { - let oldlo = self.lo; - if self.lo == 0u { - self.lo = self.elts.len() - 1u; - } else { self.lo -= 1u; } - if self.lo == self.hi { - self.elts = grow(self.nelts, oldlo, self.elts); - self.lo = self.elts.len() - 1u; - self.hi = self.nelts; - } - self.elts[self.lo] = Some(t); - self.nelts += 1u; - } - - /// Append an element to the deque - fn add_back(&mut self, t: T) { - if self.lo == self.hi && self.nelts != 0u { - self.elts = grow(self.nelts, self.lo, self.elts); - self.lo = 0u; - self.hi = self.nelts; - } - self.elts[self.hi] = Some(t); - self.hi = (self.hi + 1u) % self.elts.len(); - self.nelts += 1u; - } -} - -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] pub impl Deque { /// Create an empty Deque fn new() -> Deque { diff --git a/src/libstd/ebml.rs b/src/libstd/ebml.rs index 41c5a0f7690cb..8a4bc823fd881 100644 --- a/src/libstd/ebml.rs +++ b/src/libstd/ebml.rs @@ -263,13 +263,6 @@ pub mod reader { pub fn doc_as_i32(d: Doc) -> i32 { doc_as_u32(d) as i32 } pub fn doc_as_i64(d: Doc) -> i64 { doc_as_u64(d) as i64 } - #[cfg(stage0)] - pub struct Decoder { - priv mut parent: Doc, - priv mut pos: uint, - } - - #[cfg(not(stage0))] pub struct Decoder { priv parent: Doc, priv pos: uint, @@ -283,25 +276,6 @@ pub mod reader { } priv impl Decoder { - #[cfg(stage0)] - fn _check_label(&self, lbl: &str) { - if self.pos < self.parent.end { - let TaggedDoc { tag: r_tag, doc: r_doc } = - doc_at(self.parent.data, self.pos); - - if r_tag == (EsLabel as uint) { - self.pos = r_doc.end; - let str = doc_as_str(r_doc); - if lbl != str { - fail!(fmt!("Expected label %s but found %s", - lbl, - str)); - } - } - } - } - - #[cfg(not(stage0))] fn _check_label(&mut self, lbl: &str) { if self.pos < self.parent.end { let TaggedDoc { tag: r_tag, doc: r_doc } = @@ -319,30 +293,6 @@ pub mod reader { } } - #[cfg(stage0)] - fn next_doc(&self, exp_tag: EbmlEncoderTag) -> Doc { - debug!(". next_doc(exp_tag=%?)", exp_tag); - if self.pos >= self.parent.end { - fail!(~"no more documents in current node!"); - } - let TaggedDoc { tag: r_tag, doc: r_doc } = - doc_at(self.parent.data, self.pos); - debug!("self.parent=%?-%? self.pos=%? r_tag=%? r_doc=%?-%?", - copy self.parent.start, copy self.parent.end, - copy self.pos, r_tag, r_doc.start, r_doc.end); - if r_tag != (exp_tag as uint) { - fail!(fmt!("expected EBML doc with tag %? but found tag %?", - exp_tag, r_tag)); - } - if r_doc.end > self.parent.end { - fail!(fmt!("invalid EBML, child extends to 0x%x, \ - parent to 0x%x", r_doc.end, self.parent.end)); - } - self.pos = r_doc.end; - r_doc - } - - #[cfg(not(stage0))] fn next_doc(&mut self, exp_tag: EbmlEncoderTag) -> Doc { debug!(". next_doc(exp_tag=%?)", exp_tag); if self.pos >= self.parent.end { @@ -365,19 +315,6 @@ pub mod reader { r_doc } - #[cfg(stage0)] - fn push_doc(&self, d: Doc, f: &fn() -> T) -> T { - let old_parent = self.parent; - let old_pos = self.pos; - self.parent = d; - self.pos = d.start; - let r = f(); - self.parent = old_parent; - self.pos = old_pos; - r - } - - #[cfg(not(stage0))] fn push_doc(&mut self, d: Doc, f: &fn() -> T) -> T { let old_parent = self.parent; let old_pos = self.pos; @@ -389,14 +326,6 @@ pub mod reader { r } - #[cfg(stage0)] - fn _next_uint(&self, exp_tag: EbmlEncoderTag) -> uint { - let r = doc_as_u32(self.next_doc(exp_tag)); - debug!("_next_uint exp_tag=%? result=%?", exp_tag, r); - r as uint - } - - #[cfg(not(stage0))] fn _next_uint(&mut self, exp_tag: EbmlEncoderTag) -> uint { let r = doc_as_u32(self.next_doc(exp_tag)); debug!("_next_uint exp_tag=%? result=%?", exp_tag, r); @@ -405,14 +334,6 @@ pub mod reader { } pub impl Decoder { - #[cfg(stage0)] - fn read_opaque(&self, op: &fn(Doc) -> R) -> R { - do self.push_doc(self.next_doc(EsOpaque)) { - op(copy self.parent) - } - } - - #[cfg(not(stage0))] fn read_opaque(&mut self, op: &fn(&mut Decoder, Doc) -> R) -> R { let doc = self.next_doc(EsOpaque); @@ -428,188 +349,6 @@ pub mod reader { } } - #[cfg(stage0)] - impl serialize::Decoder for Decoder { - fn read_nil(&self) -> () { () } - - fn read_u64(&self) -> u64 { doc_as_u64(self.next_doc(EsU64)) } - fn read_u32(&self) -> u32 { doc_as_u32(self.next_doc(EsU32)) } - fn read_u16(&self) -> u16 { doc_as_u16(self.next_doc(EsU16)) } - fn read_u8 (&self) -> u8 { doc_as_u8 (self.next_doc(EsU8 )) } - fn read_uint(&self) -> uint { - let v = doc_as_u64(self.next_doc(EsUint)); - if v > (::core::uint::max_value as u64) { - fail!(fmt!("uint %? too large for this architecture", v)); - } - v as uint - } - - fn read_i64(&self) -> i64 { - doc_as_u64(self.next_doc(EsI64)) as i64 - } - fn read_i32(&self) -> i32 { - doc_as_u32(self.next_doc(EsI32)) as i32 - } - fn read_i16(&self) -> i16 { - doc_as_u16(self.next_doc(EsI16)) as i16 - } - fn read_i8 (&self) -> i8 { - doc_as_u8(self.next_doc(EsI8 )) as i8 - } - fn read_int(&self) -> int { - let v = doc_as_u64(self.next_doc(EsInt)) as i64; - if v > (int::max_value as i64) || v < (int::min_value as i64) { - fail!(fmt!("int %? out of range for this architecture", v)); - } - v as int - } - - fn read_bool(&self) -> bool { - doc_as_u8(self.next_doc(EsBool)) as bool - } - - fn read_f64(&self) -> f64 { fail!(~"read_f64()"); } - fn read_f32(&self) -> f32 { fail!(~"read_f32()"); } - fn read_float(&self) -> float { fail!(~"read_float()"); } - fn read_char(&self) -> char { fail!(~"read_char()"); } - fn read_str(&self) -> ~str { doc_as_str(self.next_doc(EsStr)) } - - // Compound types: - fn read_enum(&self, name: &str, f: &fn() -> T) -> T { - debug!("read_enum(%s)", name); - self._check_label(name); - self.push_doc(self.next_doc(EsEnum), f) - } - - fn read_enum_variant(&self, - _: &[&str], - f: &fn(uint) -> T) - -> T { - debug!("read_enum_variant()"); - let idx = self._next_uint(EsEnumVid); - debug!(" idx=%u", idx); - do self.push_doc(self.next_doc(EsEnumBody)) { - f(idx) - } - } - - fn read_enum_variant_arg(&self, - idx: uint, - f: &fn() -> T) -> T { - debug!("read_enum_variant_arg(idx=%u)", idx); - f() - } - - fn read_enum_struct_variant(&self, - _: &[&str], - f: &fn(uint) -> T) - -> T { - debug!("read_enum_struct_variant()"); - let idx = self._next_uint(EsEnumVid); - debug!(" idx=%u", idx); - do self.push_doc(self.next_doc(EsEnumBody)) { - f(idx) - } - } - - fn read_enum_struct_variant_field(&self, - name: &str, - idx: uint, - f: &fn() -> T) - -> T { - debug!("read_enum_struct_variant_arg(name=%?, idx=%u)", name, idx); - f() - } - - fn read_struct(&self, - name: &str, - _: uint, - f: &fn() -> T) - -> T { - debug!("read_struct(name=%s)", name); - f() - } - - fn read_field(&self, - name: &str, - idx: uint, - f: &fn() -> T) - -> T { - debug!("read_field(name=%?, idx=%u)", name, idx); - self._check_label(name); - f() - } - - fn read_tuple(&self, f: &fn(uint) -> T) -> T { - debug!("read_tuple()"); - self.read_seq(f) - } - - fn read_tuple_arg(&self, idx: uint, f: &fn() -> T) -> T { - debug!("read_tuple_arg(idx=%u)", idx); - self.read_seq_elt(idx, f) - } - - fn read_tuple_struct(&self, - name: &str, - f: &fn(uint) -> T) - -> T { - debug!("read_tuple_struct(name=%?)", name); - self.read_tuple(f) - } - - fn read_tuple_struct_arg(&self, - idx: uint, - f: &fn() -> T) - -> T { - debug!("read_tuple_struct_arg(idx=%u)", idx); - self.read_tuple_arg(idx, f) - } - - fn read_option(&self, f: &fn(bool) -> T) -> T { - debug!("read_option()"); - do self.read_enum("Option") || { - do self.read_enum_variant(["None", "Some"]) |idx| { - match idx { - 0 => f(false), - 1 => f(true), - _ => fail!(), - } - } - } - } - - fn read_seq(&self, f: &fn(uint) -> T) -> T { - debug!("read_seq()"); - do self.push_doc(self.next_doc(EsVec)) { - let len = self._next_uint(EsVecLen); - debug!(" len=%u", len); - f(len) - } - } - - fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T { - debug!("read_seq_elt(idx=%u)", idx); - self.push_doc(self.next_doc(EsVecElt), f) - } - - fn read_map(&self, _f: &fn(uint) -> T) -> T { - debug!("read_map()"); - fail!(~"read_map is unimplemented"); - } - - fn read_map_elt_key(&self, idx: uint, _f: &fn() -> T) -> T { - debug!("read_map_elt_key(idx=%u)", idx); - fail!(~"read_map_elt_val is unimplemented"); - } - - fn read_map_elt_val(&self, idx: uint, _f: &fn() -> T) -> T { - debug!("read_map_elt_val(idx=%u)", idx); - fail!(~"read_map_elt_val is unimplemented"); - } - } - - #[cfg(not(stage0))] impl serialize::Decoder for Decoder { fn read_nil(&mut self) -> () { () } @@ -891,104 +630,6 @@ pub mod writer { } // FIXME (#2741): Provide a function to write the standard ebml header. - #[cfg(stage0)] - pub impl Encoder { - fn start_tag(&self, tag_id: uint) { - debug!("Start tag %u", tag_id); - - // Write the enum ID: - write_vuint(self.writer, tag_id); - - // Write a placeholder four-byte size. - self.size_positions.push(self.writer.tell()); - let zeroes: &[u8] = &[0u8, 0u8, 0u8, 0u8]; - self.writer.write(zeroes); - } - - fn end_tag(&self) { - let last_size_pos = self.size_positions.pop(); - let cur_pos = self.writer.tell(); - self.writer.seek(last_size_pos as int, io::SeekSet); - let size = (cur_pos - last_size_pos - 4u); - write_sized_vuint(self.writer, size, 4u); - self.writer.seek(cur_pos as int, io::SeekSet); - - debug!("End tag (size = %u)", size); - } - - fn wr_tag(&self, tag_id: uint, blk: &fn()) { - self.start_tag(tag_id); - blk(); - self.end_tag(); - } - - fn wr_tagged_bytes(&self, tag_id: uint, b: &[u8]) { - write_vuint(self.writer, tag_id); - write_vuint(self.writer, vec::len(b)); - self.writer.write(b); - } - - fn wr_tagged_u64(&self, tag_id: uint, v: u64) { - do io::u64_to_be_bytes(v, 8u) |v| { - self.wr_tagged_bytes(tag_id, v); - } - } - - fn wr_tagged_u32(&self, tag_id: uint, v: u32) { - do io::u64_to_be_bytes(v as u64, 4u) |v| { - self.wr_tagged_bytes(tag_id, v); - } - } - - fn wr_tagged_u16(&self, tag_id: uint, v: u16) { - do io::u64_to_be_bytes(v as u64, 2u) |v| { - self.wr_tagged_bytes(tag_id, v); - } - } - - fn wr_tagged_u8(&self, tag_id: uint, v: u8) { - self.wr_tagged_bytes(tag_id, &[v]); - } - - fn wr_tagged_i64(&self, tag_id: uint, v: i64) { - do io::u64_to_be_bytes(v as u64, 8u) |v| { - self.wr_tagged_bytes(tag_id, v); - } - } - - fn wr_tagged_i32(&self, tag_id: uint, v: i32) { - do io::u64_to_be_bytes(v as u64, 4u) |v| { - self.wr_tagged_bytes(tag_id, v); - } - } - - fn wr_tagged_i16(&self, tag_id: uint, v: i16) { - do io::u64_to_be_bytes(v as u64, 2u) |v| { - self.wr_tagged_bytes(tag_id, v); - } - } - - fn wr_tagged_i8(&self, tag_id: uint, v: i8) { - self.wr_tagged_bytes(tag_id, &[v as u8]); - } - - fn wr_tagged_str(&self, tag_id: uint, v: &str) { - str::byte_slice(v, |b| self.wr_tagged_bytes(tag_id, b)); - } - - fn wr_bytes(&self, b: &[u8]) { - debug!("Write %u bytes", vec::len(b)); - self.writer.write(b); - } - - fn wr_str(&self, s: &str) { - debug!("Write str: %?", s); - self.writer.write(str::to_bytes(s)); - } - } - - // FIXME (#2741): Provide a function to write the standard ebml header. - #[cfg(not(stage0))] pub impl Encoder { fn start_tag(&mut self, tag_id: uint) { debug!("Start tag %u", tag_id); @@ -1091,26 +732,6 @@ pub mod writer { // Totally lame approach. static debug: bool = true; - #[cfg(stage0)] - priv impl Encoder { - // used internally to emit things like the vector length and so on - fn _emit_tagged_uint(&self, t: EbmlEncoderTag, v: uint) { - assert!(v <= 0xFFFF_FFFF_u); - self.wr_tagged_u32(t as uint, v as u32); - } - - fn _emit_label(&self, label: &str) { - // There are various strings that we have access to, such as - // the name of a record field, which do not actually appear in - // the encoded EBML (normally). This is just for - // efficiency. When debugging, though, we can emit such - // labels and then they will be checked by decoder to - // try and check failures more quickly. - if debug { self.wr_tagged_str(EsLabel as uint, label) } - } - } - - #[cfg(not(stage0))] priv impl Encoder { // used internally to emit things like the vector length and so on fn _emit_tagged_uint(&mut self, t: EbmlEncoderTag, v: uint) { @@ -1129,16 +750,6 @@ pub mod writer { } } - #[cfg(stage0)] - pub impl Encoder { - fn emit_opaque(&self, f: &fn()) { - do self.wr_tag(EsOpaque as uint) { - f() - } - } - } - - #[cfg(not(stage0))] pub impl Encoder { fn emit_opaque(&mut self, f: &fn(&mut Encoder)) { self.start_tag(EsOpaque as uint); @@ -1147,156 +758,6 @@ pub mod writer { } } - #[cfg(stage0)] - impl ::serialize::Encoder for Encoder { - fn emit_nil(&self) {} - - fn emit_uint(&self, v: uint) { - self.wr_tagged_u64(EsUint as uint, v as u64); - } - fn emit_u64(&self, v: u64) { - self.wr_tagged_u64(EsU64 as uint, v); - } - fn emit_u32(&self, v: u32) { - self.wr_tagged_u32(EsU32 as uint, v); - } - fn emit_u16(&self, v: u16) { - self.wr_tagged_u16(EsU16 as uint, v); - } - fn emit_u8(&self, v: u8) { - self.wr_tagged_u8(EsU8 as uint, v); - } - - fn emit_int(&self, v: int) { - self.wr_tagged_i64(EsInt as uint, v as i64); - } - fn emit_i64(&self, v: i64) { - self.wr_tagged_i64(EsI64 as uint, v); - } - fn emit_i32(&self, v: i32) { - self.wr_tagged_i32(EsI32 as uint, v); - } - fn emit_i16(&self, v: i16) { - self.wr_tagged_i16(EsI16 as uint, v); - } - fn emit_i8(&self, v: i8) { - self.wr_tagged_i8(EsI8 as uint, v); - } - - fn emit_bool(&self, v: bool) { - self.wr_tagged_u8(EsBool as uint, v as u8) - } - - // FIXME (#2742): implement these - fn emit_f64(&self, _v: f64) { - fail!(~"Unimplemented: serializing an f64"); - } - fn emit_f32(&self, _v: f32) { - fail!(~"Unimplemented: serializing an f32"); - } - fn emit_float(&self, _v: float) { - fail!(~"Unimplemented: serializing a float"); - } - - fn emit_char(&self, _v: char) { - fail!(~"Unimplemented: serializing a char"); - } - - fn emit_str(&self, v: &str) { - self.wr_tagged_str(EsStr as uint, v) - } - - fn emit_enum(&self, name: &str, f: &fn()) { - self._emit_label(name); - self.wr_tag(EsEnum as uint, f) - } - - fn emit_enum_variant(&self, - _: &str, - v_id: uint, - _: uint, - f: &fn()) { - self._emit_tagged_uint(EsEnumVid, v_id); - self.wr_tag(EsEnumBody as uint, f) - } - - fn emit_enum_variant_arg(&self, _: uint, f: &fn()) { - f() - } - - fn emit_enum_struct_variant(&self, - v_name: &str, - v_id: uint, - cnt: uint, - f: &fn()) { - self.emit_enum_variant(v_name, v_id, cnt, f) - } - - fn emit_enum_struct_variant_field(&self, - _: &str, - idx: uint, - f: &fn()) { - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct(&self, _: &str, _len: uint, f: &fn()) { - f() - } - - fn emit_field(&self, name: &str, _idx: uint, f: &fn()) { - self._emit_label(name); - f() - } - - fn emit_tuple(&self, len: uint, f: &fn()) { - self.emit_seq(len, f) - } - fn emit_tuple_arg(&self, idx: uint, f: &fn()) { - self.emit_seq_elt(idx, f) - } - - fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { - self.emit_seq(len, f) - } - fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { - self.emit_seq_elt(idx, f) - } - - fn emit_option(&self, f: &fn()) { - self.emit_enum("Option", f); - } - fn emit_option_none(&self) { - self.emit_enum_variant("None", 0, 0, || ()) - } - fn emit_option_some(&self, f: &fn()) { - self.emit_enum_variant("Some", 1, 1, f) - } - - fn emit_seq(&self, len: uint, f: &fn()) { - do self.wr_tag(EsVec as uint) { - self._emit_tagged_uint(EsVecLen, len); - f() - } - } - - fn emit_seq_elt(&self, _idx: uint, f: &fn()) { - self.wr_tag(EsVecElt as uint, f) - } - - fn emit_map(&self, _len: uint, _f: &fn()) { - fail!(~"emit_map is unimplemented"); - } - - fn emit_map_elt_key(&self, _idx: uint, _f: &fn()) { - fail!(~"emit_map_elt_key is unimplemented"); - } - - fn emit_map_elt_val(&self, _idx: uint, _f: &fn()) { - fail!(~"emit_map_elt_val is unimplemented"); - } - } - - #[cfg(not(stage0))] impl ::serialize::Encoder for Encoder { fn emit_nil(&mut self) {} diff --git a/src/libstd/flatpipes.rs b/src/libstd/flatpipes.rs index 52d6afbb93e86..88de53f360519 100644 --- a/src/libstd/flatpipes.rs +++ b/src/libstd/flatpipes.rs @@ -438,19 +438,6 @@ pub mod flatteners { SerializingFlattener */ - #[cfg(stage0)] - pub fn deserialize_buffer>( - buf: &[u8]) - -> T { - let buf = vec::from_slice(buf); - let buf_reader = @BufReader::new(buf); - let reader = buf_reader as @Reader; - let deser: D = FromReader::from_reader(reader); - Decodable::decode(&deser) - } - - #[cfg(not(stage0))] pub fn deserialize_buffer>( buf: &[u8]) @@ -462,18 +449,6 @@ pub mod flatteners { Decodable::decode(&mut deser) } - #[cfg(stage0)] - pub fn serialize_value>( - val: &T) - -> ~[u8] { - do io::with_bytes_writer |writer| { - let ser = FromWriter::from_writer(writer); - val.encode(&ser); - } - } - - #[cfg(not(stage0))] pub fn serialize_value>( val: &T) diff --git a/src/libstd/future.rs b/src/libstd/future.rs index a0312849a35cb..5e3e64b2f1cfa 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -54,35 +54,6 @@ pub impl Future { } pub impl Future { - #[cfg(stage0)] - fn get_ref(&self) -> &'self A { - /*! - * Executes the future's closure and then returns a borrowed - * pointer to the result. The borrowed pointer lasts as long as - * the future. - */ - unsafe { - match self.state { - Forced(ref mut v) => { return cast::transmute(v); } - Evaluating => fail!(~"Recursive forcing of future!"), - Pending(_) => {} - } - - let mut state = Evaluating; - self.state <-> state; - match state { - Forced(_) | Evaluating => fail!(~"Logic error."), - Pending(f) => { - self.state = Forced(f()); - self.get_ref() - } - } - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get_ref<'a>(&'a self) -> &'a A { /*! * Executes the future's closure and then returns a borrowed diff --git a/src/libstd/json.rs b/src/libstd/json.rs index 6951ee377c92a..3960a07dfce7b 100644 --- a/src/libstd/json.rs +++ b/src/libstd/json.rs @@ -77,150 +77,6 @@ pub fn Encoder(wr: @io::Writer) -> Encoder { } } -#[cfg(stage0)] -impl serialize::Encoder for Encoder { - fn emit_nil(&self) { self.wr.write_str("null") } - - fn emit_uint(&self, v: uint) { self.emit_float(v as float); } - fn emit_u64(&self, v: u64) { self.emit_float(v as float); } - fn emit_u32(&self, v: u32) { self.emit_float(v as float); } - fn emit_u16(&self, v: u16) { self.emit_float(v as float); } - fn emit_u8(&self, v: u8) { self.emit_float(v as float); } - - fn emit_int(&self, v: int) { self.emit_float(v as float); } - fn emit_i64(&self, v: i64) { self.emit_float(v as float); } - fn emit_i32(&self, v: i32) { self.emit_float(v as float); } - fn emit_i16(&self, v: i16) { self.emit_float(v as float); } - fn emit_i8(&self, v: i8) { self.emit_float(v as float); } - - fn emit_bool(&self, v: bool) { - if v { - self.wr.write_str("true"); - } else { - self.wr.write_str("false"); - } - } - - fn emit_f64(&self, v: f64) { self.emit_float(v as float); } - fn emit_f32(&self, v: f32) { self.emit_float(v as float); } - fn emit_float(&self, v: float) { - self.wr.write_str(float::to_str_digits(v, 6u)); - } - - fn emit_char(&self, v: char) { self.emit_str(str::from_char(v)) } - fn emit_str(&self, v: &str) { self.wr.write_str(escape_str(v)) } - - fn emit_enum(&self, _name: &str, f: &fn()) { f() } - - fn emit_enum_variant(&self, - name: &str, - _id: uint, - cnt: uint, - f: &fn()) { - // enums are encoded as strings or vectors: - // Bunny => "Bunny" - // Kangaroo(34,"William") => ["Kangaroo",[34,"William"]] - - if cnt == 0 { - self.wr.write_str(escape_str(name)); - } else { - self.wr.write_char('['); - self.wr.write_str(escape_str(name)); - self.wr.write_char(','); - f(); - self.wr.write_char(']'); - } - } - - fn emit_enum_variant_arg(&self, idx: uint, f: &fn()) { - if idx != 0 {self.wr.write_char(',');} - f(); - } - - fn emit_enum_struct_variant(&self, - name: &str, - id: uint, - cnt: uint, - f: &fn()) { - self.emit_enum_variant(name, id, cnt, f) - } - - fn emit_enum_struct_variant_field(&self, - _: &str, - idx: uint, - f: &fn()) { - self.emit_enum_variant_arg(idx, f) - } - - fn emit_struct(&self, _: &str, _: uint, f: &fn()) { - self.wr.write_char('{'); - f(); - self.wr.write_char('}'); - } - - #[cfg(stage0)] - fn emit_field(&self, name: &str, idx: uint, f: &fn()) { - if idx != 0 { self.wr.write_char(','); } - self.wr.write_str(escape_str(name)); - self.wr.write_char(':'); - f(); - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn emit_struct_field(&self, name: &str, idx: uint, f: &fn()) { - if idx != 0 { self.wr.write_char(','); } - self.wr.write_str(escape_str(name)); - self.wr.write_char(':'); - f(); - } - - fn emit_tuple(&self, len: uint, f: &fn()) { self.emit_seq(len, f) } - fn emit_tuple_arg(&self, idx: uint, f: &fn()) { - self.emit_seq_elt(idx, f) - } - - fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { - self.emit_seq(len, f) - } - fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { - self.emit_seq_elt(idx, f) - } - - fn emit_option(&self, f: &fn()) { f(); } - fn emit_option_none(&self) { self.emit_nil(); } - fn emit_option_some(&self, f: &fn()) { f(); } - - fn emit_seq(&self, _len: uint, f: &fn()) { - self.wr.write_char('['); - f(); - self.wr.write_char(']'); - } - - fn emit_seq_elt(&self, idx: uint, f: &fn()) { - if idx != 0 { self.wr.write_char(','); } - f() - } - - fn emit_map(&self, _len: uint, f: &fn()) { - self.wr.write_char('{'); - f(); - self.wr.write_char('}'); - } - - fn emit_map_elt_key(&self, idx: uint, f: &fn()) { - if idx != 0 { self.wr.write_char(','); } - f() - } - - fn emit_map_elt_val(&self, _idx: uint, f: &fn()) { - self.wr.write_char(':'); - f() - } -} - -#[cfg(not(stage0))] impl serialize::Encoder for Encoder { fn emit_nil(&mut self) { self.wr.write_str("null") } @@ -376,202 +232,6 @@ pub fn PrettyEncoder(wr: @io::Writer) -> PrettyEncoder { } } -#[cfg(stage0)] -impl serialize::Encoder for PrettyEncoder { - fn emit_nil(&self) { self.wr.write_str("null") } - - fn emit_uint(&self, v: uint) { self.emit_float(v as float); } - fn emit_u64(&self, v: u64) { self.emit_float(v as float); } - fn emit_u32(&self, v: u32) { self.emit_float(v as float); } - fn emit_u16(&self, v: u16) { self.emit_float(v as float); } - fn emit_u8(&self, v: u8) { self.emit_float(v as float); } - - fn emit_int(&self, v: int) { self.emit_float(v as float); } - fn emit_i64(&self, v: i64) { self.emit_float(v as float); } - fn emit_i32(&self, v: i32) { self.emit_float(v as float); } - fn emit_i16(&self, v: i16) { self.emit_float(v as float); } - fn emit_i8(&self, v: i8) { self.emit_float(v as float); } - - fn emit_bool(&self, v: bool) { - if v { - self.wr.write_str("true"); - } else { - self.wr.write_str("false"); - } - } - - fn emit_f64(&self, v: f64) { self.emit_float(v as float); } - fn emit_f32(&self, v: f32) { self.emit_float(v as float); } - fn emit_float(&self, v: float) { - self.wr.write_str(float::to_str_digits(v, 6u)); - } - - fn emit_char(&self, v: char) { self.emit_str(str::from_char(v)) } - fn emit_str(&self, v: &str) { self.wr.write_str(escape_str(v)); } - - fn emit_enum(&self, _name: &str, f: &fn()) { f() } - - fn emit_enum_variant(&self, - name: &str, - _: uint, - cnt: uint, - f: &fn()) { - if cnt == 0 { - self.wr.write_str(escape_str(name)); - } else { - self.wr.write_char('['); - self.indent += 2; - self.wr.write_char('\n'); - self.wr.write_str(spaces(self.indent)); - self.wr.write_str(escape_str(name)); - self.wr.write_str(",\n"); - f(); - self.wr.write_char('\n'); - self.indent -= 2; - self.wr.write_str(spaces(self.indent)); - self.wr.write_char(']'); - } - } - - fn emit_enum_variant_arg(&self, idx: uint, f: &fn()) { - if idx != 0 { - self.wr.write_str(",\n"); - } - self.wr.write_str(spaces(self.indent)); - f() - } - - fn emit_enum_struct_variant(&self, - name: &str, - id: uint, - cnt: uint, - f: &fn()) { - self.emit_enum_variant(name, id, cnt, f) - } - - fn emit_enum_struct_variant_field(&self, - _: &str, - idx: uint, - f: &fn()) { - self.emit_enum_variant_arg(idx, f) - } - - - fn emit_struct(&self, _name: &str, len: uint, f: &fn()) { - if len == 0 { - self.wr.write_str("{}"); - } else { - self.wr.write_char('{'); - self.indent += 2; - f(); - self.wr.write_char('\n'); - self.indent -= 2; - self.wr.write_str(spaces(self.indent)); - self.wr.write_char('}'); - } - } - - #[cfg(stage0)] - fn emit_field(&self, name: &str, idx: uint, f: &fn()) { - if idx == 0 { - self.wr.write_char('\n'); - } else { - self.wr.write_str(",\n"); - } - self.wr.write_str(spaces(self.indent)); - self.wr.write_str(escape_str(name)); - self.wr.write_str(": "); - f(); - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn emit_struct_field(&self, name: &str, idx: uint, f: &fn()) { - if idx == 0 { - self.wr.write_char('\n'); - } else { - self.wr.write_str(",\n"); - } - self.wr.write_str(spaces(self.indent)); - self.wr.write_str(escape_str(name)); - self.wr.write_str(": "); - f(); - } - - fn emit_tuple(&self, len: uint, f: &fn()) { - self.emit_seq(len, f) - } - fn emit_tuple_arg(&self, idx: uint, f: &fn()) { - self.emit_seq_elt(idx, f) - } - - fn emit_tuple_struct(&self, _name: &str, len: uint, f: &fn()) { - self.emit_seq(len, f) - } - fn emit_tuple_struct_arg(&self, idx: uint, f: &fn()) { - self.emit_seq_elt(idx, f) - } - - fn emit_option(&self, f: &fn()) { f(); } - fn emit_option_none(&self) { self.emit_nil(); } - fn emit_option_some(&self, f: &fn()) { f(); } - - fn emit_seq(&self, len: uint, f: &fn()) { - if len == 0 { - self.wr.write_str("[]"); - } else { - self.wr.write_char('['); - self.indent += 2; - f(); - self.wr.write_char('\n'); - self.indent -= 2; - self.wr.write_str(spaces(self.indent)); - self.wr.write_char(']'); - } - } - - fn emit_seq_elt(&self, idx: uint, f: &fn()) { - if idx == 0 { - self.wr.write_char('\n'); - } else { - self.wr.write_str(",\n"); - } - self.wr.write_str(spaces(self.indent)); - f() - } - - fn emit_map(&self, len: uint, f: &fn()) { - if len == 0 { - self.wr.write_str("{}"); - } else { - self.wr.write_char('{'); - self.indent += 2; - f(); - self.wr.write_char('\n'); - self.indent -= 2; - self.wr.write_str(spaces(self.indent)); - self.wr.write_char('}'); - } - } - - fn emit_map_elt_key(&self, idx: uint, f: &fn()) { - if idx == 0 { - self.wr.write_char('\n'); - } else { - self.wr.write_str(",\n"); - } - self.wr.write_str(spaces(self.indent)); - f(); - } - - fn emit_map_elt_val(&self, _idx: uint, f: &fn()) { - self.wr.write_str(": "); - f(); - } -} - -#[cfg(not(stage0))] impl serialize::Encoder for PrettyEncoder { fn emit_nil(&mut self) { self.wr.write_str("null") } @@ -765,21 +425,6 @@ impl serialize::Encoder for PrettyEncoder { } } -#[cfg(stage0)] -impl serialize::Encodable for Json { - fn encode(&self, e: &E) { - match *self { - Number(v) => v.encode(e), - String(ref v) => v.encode(e), - Boolean(v) => v.encode(e), - List(ref v) => v.encode(e), - Object(ref v) => v.encode(e), - Null => e.emit_nil(), - } - } -} - -#[cfg(not(stage0))] impl serialize::Encodable for Json { fn encode(&self, e: &mut E) { match *self { @@ -794,14 +439,6 @@ impl serialize::Encodable for Json { } /// Encodes a json value into a io::writer -#[cfg(stage0)] -pub fn to_writer(wr: @io::Writer, json: &Json) { - let encoder = Encoder(wr); - json.encode(&encoder) -} - -/// Encodes a json value into a io::writer -#[cfg(not(stage0))] pub fn to_writer(wr: @io::Writer, json: &Json) { let mut encoder = Encoder(wr); json.encode(&mut encoder) @@ -813,14 +450,6 @@ pub fn to_str(json: &Json) -> ~str { } /// Encodes a json value into a io::writer -#[cfg(stage0)] -pub fn to_pretty_writer(wr: @io::Writer, json: &Json) { - let encoder = PrettyEncoder(wr); - json.encode(&encoder) -} - -/// Encodes a json value into a io::writer -#[cfg(not(stage0))] pub fn to_pretty_writer(wr: @io::Writer, json: &Json) { let mut encoder = PrettyEncoder(wr); json.encode(&mut encoder) @@ -1219,243 +848,6 @@ pub fn Decoder(json: Json) -> Decoder { } } -#[cfg(stage0)] -impl serialize::Decoder for Decoder { - fn read_nil(&self) -> () { - debug!("read_nil"); - match self.stack.pop() { - Null => (), - value => fail!(fmt!("not a null: %?", value)) - } - } - - fn read_u64(&self) -> u64 { self.read_float() as u64 } - fn read_u32(&self) -> u32 { self.read_float() as u32 } - fn read_u16(&self) -> u16 { self.read_float() as u16 } - fn read_u8 (&self) -> u8 { self.read_float() as u8 } - fn read_uint(&self) -> uint { self.read_float() as uint } - - fn read_i64(&self) -> i64 { self.read_float() as i64 } - fn read_i32(&self) -> i32 { self.read_float() as i32 } - fn read_i16(&self) -> i16 { self.read_float() as i16 } - fn read_i8 (&self) -> i8 { self.read_float() as i8 } - fn read_int(&self) -> int { self.read_float() as int } - - fn read_bool(&self) -> bool { - debug!("read_bool"); - match self.stack.pop() { - Boolean(b) => b, - value => fail!(fmt!("not a boolean: %?", value)) - } - } - - fn read_f64(&self) -> f64 { self.read_float() as f64 } - fn read_f32(&self) -> f32 { self.read_float() as f32 } - fn read_float(&self) -> float { - debug!("read_float"); - match self.stack.pop() { - Number(f) => f, - value => fail!(fmt!("not a number: %?", value)) - } - } - - fn read_char(&self) -> char { - let mut v = ~[]; - for str::each_char(self.read_str()) |c| { v.push(c) } - if v.len() != 1 { fail!(~"string must have one character") } - v[0] - } - - fn read_str(&self) -> ~str { - debug!("read_str"); - match self.stack.pop() { - String(s) => s, - json => fail!(fmt!("not a string: %?", json)) - } - } - - fn read_enum(&self, name: &str, f: &fn() -> T) -> T { - debug!("read_enum(%s)", name); - f() - } - - fn read_enum_variant(&self, - names: &[&str], - f: &fn(uint) -> T) - -> T { - debug!("read_enum_variant(names=%?)", names); - let name = match self.stack.pop() { - String(s) => s, - List(list) => { - do vec::consume_reverse(list) |_i, v| { - self.stack.push(v); - } - match self.stack.pop() { - String(s) => s, - value => fail!(fmt!("invalid variant name: %?", value)), - } - } - ref json => fail!(fmt!("invalid variant: %?", *json)), - }; - let idx = match vec::position(names, |n| str::eq_slice(*n, name)) { - Some(idx) => idx, - None => fail!(fmt!("Unknown variant name: %?", name)), - }; - f(idx) - } - - fn read_enum_variant_arg(&self, idx: uint, f: &fn() -> T) -> T { - debug!("read_enum_variant_arg(idx=%u)", idx); - f() - } - - fn read_enum_struct_variant(&self, - names: &[&str], - f: &fn(uint) -> T) - -> T { - debug!("read_enum_struct_variant(names=%?)", names); - self.read_enum_variant(names, f) - } - - - fn read_enum_struct_variant_field(&self, - name: &str, - idx: uint, - f: &fn() -> T) - -> T { - debug!("read_enum_struct_variant_field(name=%?, idx=%u)", name, idx); - self.read_enum_variant_arg(idx, f) - } - - fn read_struct(&self, name: &str, len: uint, f: &fn() -> T) -> T { - debug!("read_struct(name=%s, len=%u)", name, len); - let value = f(); - self.stack.pop(); - value - } - - #[cfg(stage0)] - fn read_field(&self, name: &str, idx: uint, f: &fn() -> T) -> T { - debug!("read_field(name=%?, idx=%u)", name, idx); - match self.stack.pop() { - Object(obj) => { - let mut obj = obj; - let value = match obj.pop(&name.to_owned()) { - None => fail!(fmt!("no such field: %s", name)), - Some(json) => { - self.stack.push(json); - f() - } - }; - self.stack.push(Object(obj)); - value - } - value => fail!(fmt!("not an object: %?", value)) - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn read_struct_field(&self, - name: &str, - idx: uint, - f: &fn() -> T) - -> T { - debug!("read_struct_field(name=%?, idx=%u)", name, idx); - match self.stack.pop() { - Object(obj) => { - let mut obj = obj; - let value = match obj.pop(&name.to_owned()) { - None => fail!(fmt!("no such field: %s", name)), - Some(json) => { - self.stack.push(json); - f() - } - }; - self.stack.push(Object(obj)); - value - } - value => fail!(fmt!("not an object: %?", value)) - } - } - - fn read_tuple(&self, f: &fn(uint) -> T) -> T { - debug!("read_tuple()"); - self.read_seq(f) - } - - fn read_tuple_arg(&self, idx: uint, f: &fn() -> T) -> T { - debug!("read_tuple_arg(idx=%u)", idx); - self.read_seq_elt(idx, f) - } - - fn read_tuple_struct(&self, name: &str, f: &fn(uint) -> T) -> T { - debug!("read_tuple_struct(name=%?)", name); - self.read_tuple(f) - } - - fn read_tuple_struct_arg(&self, idx: uint, f: &fn() -> T) -> T { - debug!("read_tuple_struct_arg(idx=%u)", idx); - self.read_tuple_arg(idx, f) - } - - fn read_option(&self, f: &fn(bool) -> T) -> T { - match self.stack.pop() { - Null => f(false), - value => { self.stack.push(value); f(true) } - } - } - - fn read_seq(&self, f: &fn(uint) -> T) -> T { - debug!("read_seq()"); - let len = match self.stack.pop() { - List(list) => { - let len = list.len(); - do vec::consume_reverse(list) |_i, v| { - self.stack.push(v); - } - len - } - _ => fail!(~"not a list"), - }; - f(len) - } - - fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T { - debug!("read_seq_elt(idx=%u)", idx); - f() - } - - fn read_map(&self, f: &fn(uint) -> T) -> T { - debug!("read_map()"); - let len = match self.stack.pop() { - Object(obj) => { - let mut obj = obj; - let len = obj.len(); - do obj.consume |key, value| { - self.stack.push(value); - self.stack.push(String(key)); - } - len - } - json => fail!(fmt!("not an object: %?", json)), - }; - f(len) - } - - fn read_map_elt_key(&self, idx: uint, f: &fn() -> T) -> T { - debug!("read_map_elt_key(idx=%u)", idx); - f() - } - - fn read_map_elt_val(&self, idx: uint, f: &fn() -> T) -> T { - debug!("read_map_elt_val(idx=%u)", idx); - f() - } -} - -#[cfg(not(stage0))] impl serialize::Decoder for Decoder { fn read_nil(&mut self) -> () { debug!("read_nil"); @@ -1577,29 +969,6 @@ impl serialize::Decoder for Decoder { value } - #[cfg(stage0)] - fn read_field(&mut self, name: &str, idx: uint, f: &fn() -> T) -> T { - debug!("read_field(name=%?, idx=%u)", name, idx); - match self.stack.pop() { - Object(obj) => { - let mut obj = obj; - let value = match obj.pop(&name.to_owned()) { - None => fail!(fmt!("no such field: %s", name)), - Some(json) => { - self.stack.push(json); - f() - } - }; - self.stack.push(Object(obj)); - value - } - value => fail!(fmt!("not an object: %?", value)) - } - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn read_struct_field(&mut self, name: &str, idx: uint, diff --git a/src/libstd/priority_queue.rs b/src/libstd/priority_queue.rs index 47af3576c9062..33fe1cfff8e59 100644 --- a/src/libstd/priority_queue.rs +++ b/src/libstd/priority_queue.rs @@ -45,25 +45,9 @@ impl Mutable for PriorityQueue { pub impl PriorityQueue { /// Returns the greatest item in the queue - fails if empty - #[cfg(stage0)] - fn top(&self) -> &'self T { &self.data[0] } - - /// Returns the greatest item in the queue - fails if empty - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn top<'a>(&'a self) -> &'a T { &self.data[0] } /// Returns the greatest item in the queue - None if empty - #[cfg(stage0)] - fn maybe_top(&self) -> Option<&'self T> { - if self.is_empty() { None } else { Some(self.top()) } - } - - /// Returns the greatest item in the queue - None if empty - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn maybe_top<'a>(&'a self) -> Option<&'a T> { if self.is_empty() { None } else { Some(self.top()) } } diff --git a/src/libstd/serialize.rs b/src/libstd/serialize.rs index 39fb5a45d7e9c..a5d2604b6f6db 100644 --- a/src/libstd/serialize.rs +++ b/src/libstd/serialize.rs @@ -20,80 +20,8 @@ use core::hashmap::{HashMap, HashSet}; use core::trie::{TrieMap, TrieSet}; use deque::Deque; use dlist::DList; -#[cfg(stage1)] -#[cfg(stage2)] -#[cfg(stage3)] use treemap::{TreeMap, TreeSet}; -#[cfg(stage0)] -pub trait Encoder { - // Primitive types: - fn emit_nil(&self); - fn emit_uint(&self, v: uint); - fn emit_u64(&self, v: u64); - fn emit_u32(&self, v: u32); - fn emit_u16(&self, v: u16); - fn emit_u8(&self, v: u8); - fn emit_int(&self, v: int); - fn emit_i64(&self, v: i64); - fn emit_i32(&self, v: i32); - fn emit_i16(&self, v: i16); - fn emit_i8(&self, v: i8); - fn emit_bool(&self, v: bool); - fn emit_float(&self, v: float); - fn emit_f64(&self, v: f64); - fn emit_f32(&self, v: f32); - fn emit_char(&self, v: char); - fn emit_str(&self, v: &str); - - // Compound types: - fn emit_enum(&self, name: &str, f: &fn()); - - fn emit_enum_variant(&self, - v_name: &str, - v_id: uint, - len: uint, - f: &fn()); - fn emit_enum_variant_arg(&self, a_idx: uint, f: &fn()); - - fn emit_enum_struct_variant(&self, - v_name: &str, - v_id: uint, - len: uint, - f: &fn()); - fn emit_enum_struct_variant_field(&self, - f_name: &str, - f_idx: uint, - f: &fn()); - - fn emit_struct(&self, name: &str, len: uint, f: &fn()); - #[cfg(stage0)] - fn emit_field(&self, f_name: &str, f_idx: uint, f: &fn()); - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn emit_struct_field(&self, f_name: &str, f_idx: uint, f: &fn()); - - fn emit_tuple(&self, len: uint, f: &fn()); - fn emit_tuple_arg(&self, idx: uint, f: &fn()); - - fn emit_tuple_struct(&self, name: &str, len: uint, f: &fn()); - fn emit_tuple_struct_arg(&self, f_idx: uint, f: &fn()); - - // Specialized types: - fn emit_option(&self, f: &fn()); - fn emit_option_none(&self); - fn emit_option_some(&self, f: &fn()); - - fn emit_seq(&self, len: uint, f: &fn()); - fn emit_seq_elt(&self, idx: uint, f: &fn()); - - fn emit_map(&self, len: uint, f: &fn()); - fn emit_map_elt_key(&self, idx: uint, f: &fn()); - fn emit_map_elt_val(&self, idx: uint, f: &fn()); -} - -#[cfg(not(stage0))] pub trait Encoder { // Primitive types: fn emit_nil(&mut self); @@ -159,80 +87,6 @@ pub trait Encoder { fn emit_map_elt_val(&mut self, idx: uint, f: &fn(&mut Self)); } -#[cfg(stage0)] -pub trait Decoder { - // Primitive types: - fn read_nil(&self) -> (); - fn read_uint(&self) -> uint; - fn read_u64(&self) -> u64; - fn read_u32(&self) -> u32; - fn read_u16(&self) -> u16; - fn read_u8(&self) -> u8; - fn read_int(&self) -> int; - fn read_i64(&self) -> i64; - fn read_i32(&self) -> i32; - fn read_i16(&self) -> i16; - fn read_i8(&self) -> i8; - fn read_bool(&self) -> bool; - fn read_f64(&self) -> f64; - fn read_f32(&self) -> f32; - fn read_float(&self) -> float; - fn read_char(&self) -> char; - fn read_str(&self) -> ~str; - - // Compound types: - fn read_enum(&self, name: &str, f: &fn() -> T) -> T; - - fn read_enum_variant(&self, - names: &[&str], - f: &fn(uint) -> T) - -> T; - fn read_enum_variant_arg(&self, a_idx: uint, f: &fn() -> T) -> T; - - fn read_enum_struct_variant(&self, - names: &[&str], - f: &fn(uint) -> T) - -> T; - fn read_enum_struct_variant_field(&self, - &f_name: &str, - f_idx: uint, - f: &fn() -> T) - -> T; - - fn read_struct(&self, s_name: &str, len: uint, f: &fn() -> T) -> T; - #[cfg(stage0)] - fn read_field(&self, - f_name: &str, - f_idx: uint, - f: &fn() -> T) - -> T; - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] - fn read_struct_field(&self, - f_name: &str, - f_idx: uint, - f: &fn() -> T) - -> T; - - fn read_tuple(&self, f: &fn(uint) -> T) -> T; - fn read_tuple_arg(&self, a_idx: uint, f: &fn() -> T) -> T; - - fn read_tuple_struct(&self, s_name: &str, f: &fn(uint) -> T) -> T; - fn read_tuple_struct_arg(&self, a_idx: uint, f: &fn() -> T) -> T; - - // Specialized types: - fn read_option(&self, f: &fn(bool) -> T) -> T; - - fn read_seq(&self, f: &fn(uint) -> T) -> T; - fn read_seq_elt(&self, idx: uint, f: &fn() -> T) -> T; - - fn read_map(&self, f: &fn(uint) -> T) -> T; - fn read_map_elt_key(&self, idx: uint, f: &fn() -> T) -> T; - fn read_map_elt_val(&self, idx: uint, f: &fn() -> T) -> T; -} - -#[cfg(not(stage0))] pub trait Decoder { // Primitive types: fn read_nil(&mut self) -> (); @@ -280,15 +134,6 @@ pub trait Decoder { len: uint, f: &fn(&mut Self) -> T) -> T; - #[cfg(stage0)] - fn read_field(&mut self, - f_name: &str, - f_idx: uint, - f: &fn() -> T) - -> T; - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn read_struct_field(&mut self, f_name: &str, f_idx: uint, @@ -318,598 +163,254 @@ pub trait Decoder { fn read_map_elt_val(&mut self, idx: uint, f: &fn(&mut Self) -> T) -> T; } -#[cfg(stage0)] -pub trait Encodable { - fn encode(&self, s: &S); -} - -#[cfg(not(stage0))] pub trait Encodable { fn encode(&self, s: &mut S); } -#[cfg(stage0)] -pub trait Decodable { - fn decode(d: &D) -> Self; -} - -#[cfg(not(stage0))] pub trait Decodable { fn decode(d: &mut D) -> Self; } -#[cfg(stage0)] -impl Encodable for uint { - fn encode(&self, s: &S) { - s.emit_uint(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for uint { fn encode(&self, s: &mut S) { s.emit_uint(*self) } } -#[cfg(stage0)] -impl Decodable for uint { - fn decode(d: &D) -> uint { - d.read_uint() - } -} - -#[cfg(not(stage0))] impl Decodable for uint { fn decode(d: &mut D) -> uint { d.read_uint() } } -#[cfg(stage0)] -impl Encodable for u8 { - fn encode(&self, s: &S) { - s.emit_u8(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for u8 { fn encode(&self, s: &mut S) { s.emit_u8(*self) } } -#[cfg(stage0)] -impl Decodable for u8 { - fn decode(d: &D) -> u8 { - d.read_u8() - } -} - -#[cfg(not(stage0))] impl Decodable for u8 { fn decode(d: &mut D) -> u8 { d.read_u8() } } -#[cfg(stage0)] -impl Encodable for u16 { - fn encode(&self, s: &S) { - s.emit_u16(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for u16 { fn encode(&self, s: &mut S) { s.emit_u16(*self) } } -#[cfg(stage0)] -impl Decodable for u16 { - fn decode(d: &D) -> u16 { - d.read_u16() - } -} - -#[cfg(not(stage0))] impl Decodable for u16 { fn decode(d: &mut D) -> u16 { d.read_u16() } } -#[cfg(stage0)] -impl Encodable for u32 { - fn encode(&self, s: &S) { - s.emit_u32(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for u32 { fn encode(&self, s: &mut S) { s.emit_u32(*self) } } -#[cfg(stage0)] -impl Decodable for u32 { - fn decode(d: &D) -> u32 { - d.read_u32() - } -} - -#[cfg(not(stage0))] impl Decodable for u32 { fn decode(d: &mut D) -> u32 { d.read_u32() } } -#[cfg(stage0)] -impl Encodable for u64 { - fn encode(&self, s: &S) { - s.emit_u64(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for u64 { fn encode(&self, s: &mut S) { s.emit_u64(*self) } } -#[cfg(stage0)] -impl Decodable for u64 { - fn decode(d: &D) -> u64 { - d.read_u64() - } -} - -#[cfg(not(stage0))] impl Decodable for u64 { fn decode(d: &mut D) -> u64 { d.read_u64() } } -#[cfg(stage0)] -impl Encodable for int { - fn encode(&self, s: &S) { - s.emit_int(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for int { fn encode(&self, s: &mut S) { s.emit_int(*self) } } -#[cfg(stage0)] -impl Decodable for int { - fn decode(d: &D) -> int { - d.read_int() - } -} - -#[cfg(not(stage0))] impl Decodable for int { fn decode(d: &mut D) -> int { d.read_int() } } -#[cfg(stage0)] -impl Encodable for i8 { - fn encode(&self, s: &S) { - s.emit_i8(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for i8 { fn encode(&self, s: &mut S) { s.emit_i8(*self) } } -#[cfg(stage0)] -impl Decodable for i8 { - fn decode(d: &D) -> i8 { - d.read_i8() - } -} - -#[cfg(not(stage0))] impl Decodable for i8 { fn decode(d: &mut D) -> i8 { d.read_i8() } } -#[cfg(stage0)] -impl Encodable for i16 { - fn encode(&self, s: &S) { - s.emit_i16(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for i16 { fn encode(&self, s: &mut S) { s.emit_i16(*self) } } -#[cfg(stage0)] -impl Decodable for i16 { - fn decode(d: &D) -> i16 { - d.read_i16() - } -} - -#[cfg(not(stage0))] impl Decodable for i16 { fn decode(d: &mut D) -> i16 { d.read_i16() } } -#[cfg(stage0)] -impl Encodable for i32 { - fn encode(&self, s: &S) { - s.emit_i32(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for i32 { fn encode(&self, s: &mut S) { s.emit_i32(*self) } } -#[cfg(stage0)] -impl Decodable for i32 { - fn decode(d: &D) -> i32 { - d.read_i32() - } -} - -#[cfg(not(stage0))] impl Decodable for i32 { fn decode(d: &mut D) -> i32 { d.read_i32() } } -#[cfg(stage0)] -impl Encodable for i64 { - fn encode(&self, s: &S) { - s.emit_i64(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for i64 { fn encode(&self, s: &mut S) { s.emit_i64(*self) } } -#[cfg(stage0)] -impl Decodable for i64 { - fn decode(d: &D) -> i64 { - d.read_i64() - } -} - -#[cfg(not(stage0))] impl Decodable for i64 { fn decode(d: &mut D) -> i64 { d.read_i64() } } -#[cfg(stage0)] -impl<'self, S:Encoder> Encodable for &'self str { - fn encode(&self, s: &S) { - s.emit_str(*self) - } -} - -#[cfg(not(stage0))] impl<'self, S:Encoder> Encodable for &'self str { fn encode(&self, s: &mut S) { s.emit_str(*self) } } -#[cfg(stage0)] -impl Encodable for ~str { - fn encode(&self, s: &S) { - s.emit_str(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for ~str { fn encode(&self, s: &mut S) { s.emit_str(*self) } } -#[cfg(stage0)] -impl Decodable for ~str { - fn decode(d: &D) -> ~str { - d.read_str() - } -} - -#[cfg(not(stage0))] impl Decodable for ~str { fn decode(d: &mut D) -> ~str { d.read_str() } } -#[cfg(stage0)] -impl Encodable for @str { - fn encode(&self, s: &S) { - s.emit_str(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for @str { fn encode(&self, s: &mut S) { s.emit_str(*self) } } -#[cfg(stage0)] -impl Decodable for @str { - fn decode(d: &D) -> @str { - d.read_str().to_managed() - } -} - -#[cfg(not(stage0))] impl Decodable for @str { fn decode(d: &mut D) -> @str { d.read_str().to_managed() } } -#[cfg(stage0)] -impl Encodable for float { - fn encode(&self, s: &S) { - s.emit_float(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for float { fn encode(&self, s: &mut S) { s.emit_float(*self) } } -#[cfg(stage0)] -impl Decodable for float { - fn decode(d: &D) -> float { - d.read_float() - } -} - -#[cfg(not(stage0))] impl Decodable for float { fn decode(d: &mut D) -> float { d.read_float() } } -#[cfg(stage0)] -impl Encodable for f32 { - fn encode(&self, s: &S) { - s.emit_f32(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for f32 { fn encode(&self, s: &mut S) { s.emit_f32(*self) } } -#[cfg(stage0)] -impl Decodable for f32 { - fn decode(d: &D) -> f32 { - d.read_f32() - } -} - -#[cfg(not(stage0))] impl Decodable for f32 { fn decode(d: &mut D) -> f32 { d.read_f32() } } -#[cfg(stage0)] -impl Encodable for f64 { - fn encode(&self, s: &S) { - s.emit_f64(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for f64 { fn encode(&self, s: &mut S) { s.emit_f64(*self) } } -#[cfg(stage0)] -impl Decodable for f64 { - fn decode(d: &D) -> f64 { - d.read_f64() - } -} - -#[cfg(not(stage0))] impl Decodable for f64 { fn decode(d: &mut D) -> f64 { d.read_f64() } } -#[cfg(stage0)] -impl Encodable for bool { - fn encode(&self, s: &S) { - s.emit_bool(*self) - } -} - -#[cfg(not(stage0))] impl Encodable for bool { fn encode(&self, s: &mut S) { s.emit_bool(*self) } } -#[cfg(stage0)] -impl Decodable for bool { - fn decode(d: &D) -> bool { - d.read_bool() - } -} - -#[cfg(not(stage0))] impl Decodable for bool { fn decode(d: &mut D) -> bool { d.read_bool() } } -#[cfg(stage0)] -impl Encodable for () { - fn encode(&self, s: &S) { - s.emit_nil() - } -} - -#[cfg(not(stage0))] impl Encodable for () { fn encode(&self, s: &mut S) { s.emit_nil() } } -#[cfg(stage0)] -impl Decodable for () { - fn decode(d: &D) -> () { - d.read_nil() - } -} - -#[cfg(not(stage0))] impl Decodable for () { fn decode(d: &mut D) -> () { d.read_nil() } } -#[cfg(stage0)] -impl<'self, S:Encoder,T:Encodable> Encodable for &'self T { - fn encode(&self, s: &S) { - (**self).encode(s) - } -} - -#[cfg(not(stage0))] impl<'self, S:Encoder,T:Encodable> Encodable for &'self T { fn encode(&self, s: &mut S) { (**self).encode(s) } } -#[cfg(stage0)] -impl> Encodable for ~T { - fn encode(&self, s: &S) { - (**self).encode(s) - } -} - -#[cfg(not(stage0))] impl> Encodable for ~T { fn encode(&self, s: &mut S) { (**self).encode(s) } } -#[cfg(stage0)] -impl> Decodable for ~T { - fn decode(d: &D) -> ~T { - ~Decodable::decode(d) - } -} - -#[cfg(not(stage0))] impl> Decodable for ~T { fn decode(d: &mut D) -> ~T { ~Decodable::decode(d) } } -#[cfg(stage0)] -impl> Encodable for @T { - fn encode(&self, s: &S) { - (**self).encode(s) - } -} - -#[cfg(not(stage0))] impl> Encodable for @T { fn encode(&self, s: &mut S) { (**self).encode(s) } } -#[cfg(stage0)] -impl> Decodable for @T { - fn decode(d: &D) -> @T { - @Decodable::decode(d) - } -} - -#[cfg(not(stage0))] impl> Decodable for @T { fn decode(d: &mut D) -> @T { @Decodable::decode(d) } } -#[cfg(stage0)] -impl<'self, S:Encoder,T:Encodable> Encodable for &'self [T] { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { - for self.eachi |i, e| { - s.emit_seq_elt(i, || e.encode(s)) - } - } - } -} - -#[cfg(not(stage0))] impl<'self, S:Encoder,T:Encodable> Encodable for &'self [T] { fn encode(&self, s: &mut S) { do s.emit_seq(self.len()) |s| { @@ -920,18 +421,6 @@ impl<'self, S:Encoder,T:Encodable> Encodable for &'self [T] { } } -#[cfg(stage0)] -impl> Encodable for ~[T] { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { - for self.eachi |i, e| { - s.emit_seq_elt(i, || e.encode(s)) - } - } - } -} - -#[cfg(not(stage0))] impl> Encodable for ~[T] { fn encode(&self, s: &mut S) { do s.emit_seq(self.len()) |s| { @@ -942,18 +431,6 @@ impl> Encodable for ~[T] { } } -#[cfg(stage0)] -impl> Decodable for ~[T] { - fn decode(d: &D) -> ~[T] { - do d.read_seq |len| { - do vec::from_fn(len) |i| { - d.read_seq_elt(i, || Decodable::decode(d)) - } - } - } -} - -#[cfg(not(stage0))] impl> Decodable for ~[T] { fn decode(d: &mut D) -> ~[T] { do d.read_seq |d, len| { @@ -964,18 +441,6 @@ impl> Decodable for ~[T] { } } -#[cfg(stage0)] -impl> Encodable for @[T] { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { - for self.eachi |i, e| { - s.emit_seq_elt(i, || e.encode(s)) - } - } - } -} - -#[cfg(not(stage0))] impl> Encodable for @[T] { fn encode(&self, s: &mut S) { do s.emit_seq(self.len()) |s| { @@ -986,18 +451,6 @@ impl> Encodable for @[T] { } } -#[cfg(stage0)] -impl> Decodable for @[T] { - fn decode(d: &D) -> @[T] { - do d.read_seq |len| { - do at_vec::from_fn(len) |i| { - d.read_seq_elt(i, || Decodable::decode(d)) - } - } - } -} - -#[cfg(not(stage0))] impl> Decodable for @[T] { fn decode(d: &mut D) -> @[T] { do d.read_seq |d, len| { @@ -1008,19 +461,6 @@ impl> Decodable for @[T] { } } -#[cfg(stage0)] -impl> Encodable for Option { - fn encode(&self, s: &S) { - do s.emit_option { - match *self { - None => s.emit_option_none(), - Some(ref v) => s.emit_option_some(|| v.encode(s)), - } - } - } -} - -#[cfg(not(stage0))] impl> Encodable for Option { fn encode(&self, s: &mut S) { do s.emit_option |s| { @@ -1032,47 +472,18 @@ impl> Encodable for Option { } } -#[cfg(stage0)] -impl> Decodable for Option { - fn decode(d: &D) -> Option { - do d.read_option |b| { - if b { - Some(Decodable::decode(d)) - } else { - None - } - } - } -} - -#[cfg(not(stage0))] impl> Decodable for Option { - fn decode(d: &mut D) -> Option { - do d.read_option |d, b| { - if b { - Some(Decodable::decode(d)) - } else { - None - } - } - } -} - -#[cfg(stage0)] -impl,T1:Encodable> Encodable for (T0, T1) { - fn encode(&self, s: &S) { - match *self { - (ref t0, ref t1) => { - do s.emit_seq(2) { - s.emit_seq_elt(0, || t0.encode(s)); - s.emit_seq_elt(1, || t1.encode(s)); - } + fn decode(d: &mut D) -> Option { + do d.read_option |d, b| { + if b { + Some(Decodable::decode(d)) + } else { + None } } } } -#[cfg(not(stage0))] impl,T1:Encodable> Encodable for (T0, T1) { fn encode(&self, s: &mut S) { match *self { @@ -1086,20 +497,6 @@ impl,T1:Encodable> Encodable for (T0, T1) { } } -#[cfg(stage0)] -impl,T1:Decodable> Decodable for (T0, T1) { - fn decode(d: &D) -> (T0, T1) { - do d.read_seq |len| { - assert!(len == 2); - ( - d.read_seq_elt(0, || Decodable::decode(d)), - d.read_seq_elt(1, || Decodable::decode(d)) - ) - } - } -} - -#[cfg(not(stage0))] impl,T1:Decodable> Decodable for (T0, T1) { fn decode(d: &mut D) -> (T0, T1) { do d.read_seq |d, len| { @@ -1112,27 +509,6 @@ impl,T1:Decodable> Decodable for (T0, T1) { } } -#[cfg(stage0)] -impl< - S: Encoder, - T0: Encodable, - T1: Encodable, - T2: Encodable -> Encodable for (T0, T1, T2) { - fn encode(&self, s: &S) { - match *self { - (ref t0, ref t1, ref t2) => { - do s.emit_seq(3) { - s.emit_seq_elt(0, || t0.encode(s)); - s.emit_seq_elt(1, || t1.encode(s)); - s.emit_seq_elt(2, || t2.encode(s)); - } - } - } - } -} - -#[cfg(not(stage0))] impl< S: Encoder, T0: Encodable, @@ -1152,26 +528,6 @@ impl< } } -#[cfg(stage0)] -impl< - D: Decoder, - T0: Decodable, - T1: Decodable, - T2: Decodable -> Decodable for (T0, T1, T2) { - fn decode(d: &D) -> (T0, T1, T2) { - do d.read_seq |len| { - assert!(len == 3); - ( - d.read_seq_elt(0, || Decodable::decode(d)), - d.read_seq_elt(1, || Decodable::decode(d)), - d.read_seq_elt(2, || Decodable::decode(d)) - ) - } - } -} - -#[cfg(not(stage0))] impl< D: Decoder, T0: Decodable, @@ -1190,29 +546,6 @@ impl< } } -#[cfg(stage0)] -impl< - S: Encoder, - T0: Encodable, - T1: Encodable, - T2: Encodable, - T3: Encodable -> Encodable for (T0, T1, T2, T3) { - fn encode(&self, s: &S) { - match *self { - (ref t0, ref t1, ref t2, ref t3) => { - do s.emit_seq(4) { - s.emit_seq_elt(0, || t0.encode(s)); - s.emit_seq_elt(1, || t1.encode(s)); - s.emit_seq_elt(2, || t2.encode(s)); - s.emit_seq_elt(3, || t3.encode(s)); - } - } - } - } -} - -#[cfg(not(stage0))] impl< S: Encoder, T0: Encodable, @@ -1234,28 +567,6 @@ impl< } } -#[cfg(stage0)] -impl< - D: Decoder, - T0: Decodable, - T1: Decodable, - T2: Decodable, - T3: Decodable -> Decodable for (T0, T1, T2, T3) { - fn decode(d: &D) -> (T0, T1, T2, T3) { - do d.read_seq |len| { - assert!(len == 4); - ( - d.read_seq_elt(0, || Decodable::decode(d)), - d.read_seq_elt(1, || Decodable::decode(d)), - d.read_seq_elt(2, || Decodable::decode(d)), - d.read_seq_elt(3, || Decodable::decode(d)) - ) - } - } -} - -#[cfg(not(stage0))] impl< D: Decoder, T0: Decodable, @@ -1276,31 +587,6 @@ impl< } } -#[cfg(stage0)] -impl< - S: Encoder, - T0: Encodable, - T1: Encodable, - T2: Encodable, - T3: Encodable, - T4: Encodable -> Encodable for (T0, T1, T2, T3, T4) { - fn encode(&self, s: &S) { - match *self { - (ref t0, ref t1, ref t2, ref t3, ref t4) => { - do s.emit_seq(5) { - s.emit_seq_elt(0, || t0.encode(s)); - s.emit_seq_elt(1, || t1.encode(s)); - s.emit_seq_elt(2, || t2.encode(s)); - s.emit_seq_elt(3, || t3.encode(s)); - s.emit_seq_elt(4, || t4.encode(s)); - } - } - } - } -} - -#[cfg(not(stage0))] impl< S: Encoder, T0: Encodable, @@ -1324,30 +610,6 @@ impl< } } -#[cfg(stage0)] -impl< - D: Decoder, - T0: Decodable, - T1: Decodable, - T2: Decodable, - T3: Decodable, - T4: Decodable -> Decodable for (T0, T1, T2, T3, T4) { - fn decode(d: &D) -> (T0, T1, T2, T3, T4) { - do d.read_seq |len| { - assert!(len == 5); - ( - d.read_seq_elt(0, || Decodable::decode(d)), - d.read_seq_elt(1, || Decodable::decode(d)), - d.read_seq_elt(2, || Decodable::decode(d)), - d.read_seq_elt(3, || Decodable::decode(d)), - d.read_seq_elt(4, || Decodable::decode(d)) - ) - } - } -} - -#[cfg(not(stage0))] impl< D: Decoder, T0: Decodable, @@ -1370,23 +632,6 @@ impl< } } -#[cfg(stage0)] -impl< - S: Encoder, - T: Encodable + Copy -> Encodable for @mut DList { - fn encode(&self, s: &S) { - do s.emit_seq(self.size) { - let mut i = 0; - for self.each |e| { - s.emit_seq_elt(i, || e.encode(s)); - i += 1; - } - } - } -} - -#[cfg(not(stage0))] impl< S: Encoder, T: Encodable + Copy @@ -1402,20 +647,6 @@ impl< } } -#[cfg(stage0)] -impl> Decodable for @mut DList { - fn decode(d: &D) -> @mut DList { - let list = DList(); - do d.read_seq |len| { - for uint::range(0, len) |i| { - list.push(d.read_seq_elt(i, || Decodable::decode(d))); - } - } - list - } -} - -#[cfg(not(stage0))] impl> Decodable for @mut DList { fn decode(d: &mut D) -> @mut DList { let list = DList(); @@ -1428,21 +659,6 @@ impl> Decodable for @mut DList { } } -#[cfg(stage0)] -impl< - S: Encoder, - T: Encodable -> Encodable for Deque { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { - for self.eachi |i, e| { - s.emit_seq_elt(i, || e.encode(s)); - } - } - } -} - -#[cfg(not(stage0))] impl< S: Encoder, T: Encodable @@ -1456,20 +672,6 @@ impl< } } -#[cfg(stage0)] -impl> Decodable for Deque { - fn decode(d: &D) -> Deque { - let mut deque = Deque::new(); - do d.read_seq |len| { - for uint::range(0, len) |i| { - deque.add_back(d.read_seq_elt(i, || Decodable::decode(d))); - } - } - deque - } -} - -#[cfg(not(stage0))] impl> Decodable for Deque { fn decode(d: &mut D) -> Deque { let mut deque = Deque::new(); @@ -1482,25 +684,6 @@ impl> Decodable for Deque { } } -#[cfg(stage0)] -impl< - E: Encoder, - K: Encodable + Hash + IterBytes + Eq, - V: Encodable -> Encodable for HashMap { - fn encode(&self, e: &E) { - do e.emit_map(self.len()) { - let mut i = 0; - for self.each |key, val| { - e.emit_map_elt_key(i, || key.encode(e)); - e.emit_map_elt_val(i, || val.encode(e)); - i += 1; - } - } - } -} - -#[cfg(not(stage0))] impl< E: Encoder, K: Encodable + Hash + IterBytes + Eq, @@ -1518,26 +701,6 @@ impl< } } -#[cfg(stage0)] -impl< - D: Decoder, - K: Decodable + Hash + IterBytes + Eq, - V: Decodable -> Decodable for HashMap { - fn decode(d: &D) -> HashMap { - do d.read_map |len| { - let mut map = HashMap::with_capacity(len); - for uint::range(0, len) |i| { - let key = d.read_map_elt_key(i, || Decodable::decode(d)); - let val = d.read_map_elt_val(i, || Decodable::decode(d)); - map.insert(key, val); - } - map - } - } -} - -#[cfg(not(stage0))] impl< D: Decoder, K: Decodable + Hash + IterBytes + Eq, @@ -1556,23 +719,6 @@ impl< } } -#[cfg(stage0)] -impl< - S: Encoder, - T: Encodable + Hash + IterBytes + Eq -> Encodable for HashSet { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { - let mut i = 0; - for self.each |e| { - s.emit_seq_elt(i, || e.encode(s)); - i += 1; - } - } - } -} - -#[cfg(not(stage0))] impl< S: Encoder, T: Encodable + Hash + IterBytes + Eq @@ -1588,23 +734,6 @@ impl< } } -#[cfg(stage0)] -impl< - D: Decoder, - T: Decodable + Hash + IterBytes + Eq -> Decodable for HashSet { - fn decode(d: &D) -> HashSet { - do d.read_seq |len| { - let mut set = HashSet::with_capacity(len); - for uint::range(0, len) |i| { - set.insert(d.read_seq_elt(i, || Decodable::decode(d))); - } - set - } - } -} - -#[cfg(not(stage0))] impl< D: Decoder, T: Decodable + Hash + IterBytes + Eq @@ -1620,24 +749,6 @@ impl< } } -#[cfg(stage0)] -impl< - E: Encoder, - V: Encodable -> Encodable for TrieMap { - fn encode(&self, e: &E) { - do e.emit_map(self.len()) { - let mut i = 0; - for self.each |key, val| { - e.emit_map_elt_key(i, || key.encode(e)); - e.emit_map_elt_val(i, || val.encode(e)); - i += 1; - } - } - } -} - -#[cfg(not(stage0))] impl< E: Encoder, V: Encodable @@ -1654,25 +765,6 @@ impl< } } -#[cfg(stage0)] -impl< - D: Decoder, - V: Decodable -> Decodable for TrieMap { - fn decode(d: &D) -> TrieMap { - do d.read_map |len| { - let mut map = TrieMap::new(); - for uint::range(0, len) |i| { - let key = d.read_map_elt_key(i, || Decodable::decode(d)); - let val = d.read_map_elt_val(i, || Decodable::decode(d)); - map.insert(key, val); - } - map - } - } -} - -#[cfg(not(stage0))] impl< D: Decoder, V: Decodable @@ -1690,20 +782,6 @@ impl< } } -#[cfg(stage0)] -impl Encodable for TrieSet { - fn encode(&self, s: &S) { - do s.emit_seq(self.len()) { - let mut i = 0; - for self.each |e| { - s.emit_seq_elt(i, || e.encode(s)); - i += 1; - } - } - } -} - -#[cfg(not(stage0))] impl Encodable for TrieSet { fn encode(&self, s: &mut S) { do s.emit_seq(self.len()) |s| { @@ -1716,20 +794,6 @@ impl Encodable for TrieSet { } } -#[cfg(stage0)] -impl Decodable for TrieSet { - fn decode(d: &D) -> TrieSet { - do d.read_seq |len| { - let mut set = TrieSet::new(); - for uint::range(0, len) |i| { - set.insert(d.read_seq_elt(i, || Decodable::decode(d))); - } - set - } - } -} - -#[cfg(not(stage0))] impl Decodable for TrieSet { fn decode(d: &mut D) -> TrieSet { do d.read_seq |d, len| { @@ -1742,7 +806,6 @@ impl Decodable for TrieSet { } } -#[cfg(not(stage0))] impl< E: Encoder, K: Encodable + Eq + TotalOrd, @@ -1760,7 +823,6 @@ impl< } } -#[cfg(not(stage0))] impl< D: Decoder, K: Decodable + Eq + TotalOrd, @@ -1779,7 +841,6 @@ impl< } } -#[cfg(not(stage0))] impl< S: Encoder, T: Encodable + Eq + TotalOrd @@ -1795,7 +856,6 @@ impl< } } -#[cfg(not(stage0))] impl< D: Decoder, T: Decodable + Eq + TotalOrd @@ -1816,30 +876,10 @@ impl< // // In some cases, these should eventually be coded as traits. -#[cfg(stage0)] -pub trait EncoderHelpers { - fn emit_from_vec(&self, v: &[T], f: &fn(v: &T)); -} - -#[cfg(not(stage0))] pub trait EncoderHelpers { fn emit_from_vec(&mut self, v: &[T], f: &fn(&mut Self, v: &T)); } -#[cfg(stage0)] -impl EncoderHelpers for S { - fn emit_from_vec(&self, v: &[T], f: &fn(v: &T)) { - do self.emit_seq(v.len()) { - for v.eachi |i, e| { - do self.emit_seq_elt(i) { - f(e) - } - } - } - } -} - -#[cfg(not(stage0))] impl EncoderHelpers for S { fn emit_from_vec(&mut self, v: &[T], f: &fn(&mut S, &T)) { do self.emit_seq(v.len()) |this| { @@ -1852,28 +892,10 @@ impl EncoderHelpers for S { } } -#[cfg(stage0)] -pub trait DecoderHelpers { - fn read_to_vec(&self, f: &fn() -> T) -> ~[T]; -} - -#[cfg(not(stage0))] pub trait DecoderHelpers { fn read_to_vec(&mut self, f: &fn(&mut Self) -> T) -> ~[T]; } -#[cfg(stage0)] -impl DecoderHelpers for D { - fn read_to_vec(&self, f: &fn() -> T) -> ~[T] { - do self.read_seq |len| { - do vec::from_fn(len) |i| { - self.read_seq_elt(i, || f()) - } - } - } -} - -#[cfg(not(stage0))] impl DecoderHelpers for D { fn read_to_vec(&mut self, f: &fn(&mut D) -> T) -> ~[T] { do self.read_seq |this, len| { diff --git a/src/libstd/smallintmap.rs b/src/libstd/smallintmap.rs index fb17d4e50900c..1b72300a178ba 100644 --- a/src/libstd/smallintmap.rs +++ b/src/libstd/smallintmap.rs @@ -50,20 +50,6 @@ impl Map for SmallIntMap { } /// Visit all key-value pairs in order - #[cfg(stage0)] - fn each(&self, it: &fn(&uint, &'self V) -> bool) { - for uint::range(0, self.v.len()) |i| { - match self.v[i] { - Some(ref elt) => if !it(&i, elt) { break }, - None => () - } - } - } - - /// Visit all key-value pairs in order - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each<'a>(&'a self, it: &fn(&uint, &'a V) -> bool) { for uint::range(0, self.v.len()) |i| { match self.v[i] { @@ -79,15 +65,6 @@ impl Map for SmallIntMap { } /// Visit all values in order - #[cfg(stage0)] - fn each_value(&self, blk: &fn(value: &V) -> bool) { - self.each(|_, v| blk(v)) - } - - /// Visit all values in order - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each_value<'a>(&'a self, blk: &fn(value: &'a V) -> bool) { self.each(|_, v| blk(v)) } @@ -103,22 +80,6 @@ impl Map for SmallIntMap { } /// Return a reference to the value corresponding to the key - #[cfg(stage0)] - fn find(&self, key: &uint) -> Option<&'self V> { - if *key < self.v.len() { - match self.v[*key] { - Some(ref value) => Some(value), - None => None - } - } else { - None - } - } - - /// Return a reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find<'a>(&'a self, key: &uint) -> Option<&'a V> { if *key < self.v.len() { match self.v[*key] { @@ -131,22 +92,6 @@ impl Map for SmallIntMap { } /// Return a mutable reference to the value corresponding to the key - #[cfg(stage0)] - fn find_mut(&mut self, key: &uint) -> Option<&'self mut V> { - if *key < self.v.len() { - match self.v[*key] { - Some(ref mut value) => Some(value), - None => None - } - } else { - None - } - } - - /// Return a mutable reference to the value corresponding to the key - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn find_mut<'a>(&'a mut self, key: &uint) -> Option<&'a mut V> { if *key < self.v.len() { match self.v[*key] { @@ -188,20 +133,6 @@ pub impl SmallIntMap { fn new() -> SmallIntMap { SmallIntMap{v: ~[]} } /// Visit all key-value pairs in reverse order - #[cfg(stage0)] - fn each_reverse(&self, it: &fn(uint, &'self V) -> bool) { - for uint::range_rev(self.v.len(), 0) |i| { - match self.v[i - 1] { - Some(ref elt) => if !it(i - 1, elt) { break }, - None => () - } - } - } - - /// Visit all key-value pairs in reverse order - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn each_reverse<'a>(&'a self, it: &fn(uint, &'a V) -> bool) { for uint::range_rev(self.v.len(), 0) |i| { match self.v[i - 1] { @@ -211,14 +142,6 @@ pub impl SmallIntMap { } } - #[cfg(stage0)] - fn get(&self, key: &uint) -> &'self V { - self.find(key).expect("key not present") - } - - #[cfg(stage1)] - #[cfg(stage2)] - #[cfg(stage3)] fn get<'a>(&'a self, key: &uint) -> &'a V { self.find(key).expect("key not present") } diff --git a/src/libstd/std.rc b/src/libstd/std.rc index ea099090ebaba..4f9de29e7262f 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -71,7 +71,6 @@ pub mod rope; pub mod smallintmap; pub mod sort; pub mod dlist; -#[cfg(not(stage0))] pub mod treemap; // And ... other stuff @@ -91,13 +90,10 @@ pub mod cmp; pub mod base64; pub mod rl; pub mod workcache; -#[cfg(not(stage0))] #[path="num/bigint.rs"] pub mod bigint; -#[cfg(not(stage0))] #[path="num/rational.rs"] pub mod rational; -#[cfg(not(stage0))] #[path="num/complex.rs"] pub mod complex; pub mod stats; diff --git a/src/libstd/workcache.rs b/src/libstd/workcache.rs index f44d143004ede..e681382ffc828 100644 --- a/src/libstd/workcache.rs +++ b/src/libstd/workcache.rs @@ -138,19 +138,6 @@ impl WorkMap { fn new() -> WorkMap { WorkMap(HashMap::new()) } } -#[cfg(stage0)] -impl Encodable for WorkMap { - fn encode(&self, s: &S) { - let mut d = ~[]; - for self.each |k, v| { - d.push((copy *k, copy *v)) - } - sort::tim_sort(d); - d.encode(s) - } -} - -#[cfg(not(stage0))] impl Encodable for WorkMap { fn encode(&self, s: &mut S) { let mut d = ~[]; @@ -162,19 +149,6 @@ impl Encodable for WorkMap { } } -#[cfg(stage0)] -impl Decodable for WorkMap { - fn decode(d: &D) -> WorkMap { - let v : ~[(WorkKey,~str)] = Decodable::decode(d); - let mut w = WorkMap::new(); - for v.each |&(k, v)| { - w.insert(copy k, copy v); - } - w - } -} - -#[cfg(not(stage0))] impl Decodable for WorkMap { fn decode(d: &mut D) -> WorkMap { let v : ~[(WorkKey,~str)] = Decodable::decode(d); @@ -253,14 +227,6 @@ struct Work { res: Option>> } -#[cfg(stage0)] -fn json_encode>(t: &T) -> ~str { - do io::with_str_writer |wr| { - t.encode(&json::Encoder(wr)); - } -} - -#[cfg(not(stage0))] fn json_encode>(t: &T) -> ~str { do io::with_str_writer |wr| { let mut encoder = json::Encoder(wr); @@ -269,17 +235,6 @@ fn json_encode>(t: &T) -> ~str { } // FIXME(#5121) -#[cfg(stage0)] -fn json_decode>(s: &str) -> T { - do io::with_str_reader(s) |rdr| { - let j = result::unwrap(json::from_reader(rdr)); - let decoder = json::Decoder(j); - Decodable::decode(&decoder) - } -} - -// FIXME(#5121) -#[cfg(not(stage0))] fn json_decode>(s: &str) -> T { do io::with_str_reader(s) |rdr| { let j = result::unwrap(json::from_reader(rdr)); diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 77e7986616086..2216226ecb3ab 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -70,22 +70,6 @@ pub type Name = uint; // with a macro expansion pub type Mrk = uint; -#[cfg(stage0)] -impl Encodable for ident { - fn encode(&self, s: &S) { - unsafe { - let intr = - match task::local_data::local_data_get(interner_key!()) { - None => fail!(~"encode: TLS interner not set up"), - Some(intr) => intr - }; - - s.emit_str(*(*intr).get(*self)); - } - } -} - -#[cfg(not(stage0))] impl Encodable for ident { fn encode(&self, s: &mut S) { unsafe { @@ -100,21 +84,6 @@ impl Encodable for ident { } } -#[cfg(stage0)] -impl Decodable for ident { - fn decode(d: &D) -> ident { - let intr = match unsafe { - task::local_data::local_data_get(interner_key!()) - } { - None => fail!(~"decode: TLS interner not set up"), - Some(intr) => intr - }; - - (*intr).intern(@d.read_str()) - } -} - -#[cfg(not(stage0))] impl Decodable for ident { fn decode(d: &mut D) -> ident { let intr = match unsafe { diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs index bbb390e9dc948..66ed52f03528e 100644 --- a/src/libsyntax/codemap.rs +++ b/src/libsyntax/codemap.rs @@ -125,13 +125,6 @@ impl cmp::Eq for span { fn ne(&self, other: &span) -> bool { !(*self).eq(other) } } -#[cfg(stage0)] -impl Encodable for span { - /* Note #1972 -- spans are encoded but not decoded */ - fn encode(&self, _s: &S) { _s.emit_nil() } -} - -#[cfg(not(stage0))] impl Encodable for span { /* Note #1972 -- spans are encoded but not decoded */ fn encode(&self, s: &mut S) { @@ -139,14 +132,6 @@ impl Encodable for span { } } -#[cfg(stage0)] -impl Decodable for span { - fn decode(_d: &D) -> span { - dummy_sp() - } -} - -#[cfg(not(stage0))] impl Decodable for span { fn decode(_d: &mut D) -> span { dummy_sp() diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index db4912d213108..e56dab6db207e 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -451,17 +451,6 @@ impl MapChain{ // ugh: can't get this to compile with mut because of the // lack of flow sensitivity. - #[cfg(stage0)] - fn get_map(&self) -> &'self HashMap { - match *self { - BaseMapChain (~ref map) => map, - ConsMapChain (~ref map,_) => map - } - } - - // ugh: can't get this to compile with mut because of the - // lack of flow sensitivity. - #[cfg(not(stage0))] fn get_map<'a>(&'a self) -> &'a HashMap { match *self { BaseMapChain (~ref map) => map, diff --git a/src/libsyntax/opt_vec.rs b/src/libsyntax/opt_vec.rs index 6cf7bba600ec0..600ab964e5238 100644 --- a/src/libsyntax/opt_vec.rs +++ b/src/libsyntax/opt_vec.rs @@ -61,15 +61,6 @@ impl OptVec { } } - #[cfg(stage0)] - fn get(&self, i: uint) -> &'self T { - match *self { - Empty => fail!(fmt!("Invalid index %u", i)), - Vec(ref v) => &v[i] - } - } - - #[cfg(not(stage0))] fn get<'a>(&'a self, i: uint) -> &'a T { match *self { Empty => fail!(fmt!("Invalid index %u", i)), diff --git a/src/snapshots.txt b/src/snapshots.txt index 00cabe90d840f..c643b4dd25d43 100644 --- a/src/snapshots.txt +++ b/src/snapshots.txt @@ -1,3 +1,11 @@ +S 2013-05-03 213f7b2 + macos-i386 0bf8b88ea01cc4cdd81ac4db1d301ea9b3371f13 + macos-x86_64 2da3990639ab5a9c9d51b3478c437cb459de84e3 + linux-i386 094500e587bfac27d7be752b635c242e07774c0d + linux-x86_64 75733a5a58f53aa783253c8cfd56923b78676705 + winnt-i386 bd07c935a917c0796d4dc803d973b864d4794ade + freebsd-x86_64 b95d648d9bfeacdd04cc5213bdc803b0fd94add7 + S 2013-03-28 f7a2371 macos-i386 2e05a33716fc4982db53946c3b0dccf0194826fe macos-x86_64 fbd3feec8dd17a6b6c8df114e6e9b4cd17cc6172 From 8f2d71ac009e1f93c14266ecebb1c105a0a907e3 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 4 May 2013 21:53:43 -0400 Subject: [PATCH 197/215] small fix to the tutorial-ffi destructor example The previous example was erroneously attempting to destroy uninitialized memory, which was often zeroed (masking the bug). --- doc/tutorial-ffi.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/doc/tutorial-ffi.md b/doc/tutorial-ffi.md index 127f81589234f..b806df5dd20b5 100644 --- a/doc/tutorial-ffi.md +++ b/doc/tutorial-ffi.md @@ -150,11 +150,7 @@ wrapping `malloc` and `free`: ~~~~ use core::libc::{c_void, size_t, malloc, free}; - -#[abi = "rust-intrinsic"] -extern "rust-intrinsic" mod rusti { - fn init() -> T; -} +use core::unstable::intrinsics; // a wrapper around the handle returned by the foreign code pub struct Unique { @@ -166,7 +162,8 @@ pub impl<'self, T: Owned> Unique { unsafe { let ptr = malloc(core::sys::size_of::() as size_t) as *mut T; assert!(!ptr::is_null(ptr)); - *ptr = value; + // `*ptr` is uninitialized, and `*ptr = value` would attempt to destroy it + intrinsics::move_val_init(&mut *ptr, value); Unique{ptr: ptr} } } @@ -186,7 +183,7 @@ pub impl<'self, T: Owned> Unique { impl Drop for Unique { fn finalize(&self) { unsafe { - let mut x = rusti::init(); // dummy value to swap in + let mut x = intrinsics::init(); // dummy value to swap in x <-> *self.ptr; // moving the object out is needed to call the destructor free(self.ptr as *c_void) } From 987ad9c8782ba254c8326c9caac9796bcce9beb9 Mon Sep 17 00:00:00 2001 From: Young-il Choi Date: Sun, 5 May 2013 14:00:53 +0900 Subject: [PATCH 198/215] rt: rust_android_dummy.cpp fix for make tidy --- src/rt/rust_android_dummy.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/rt/rust_android_dummy.cpp b/src/rt/rust_android_dummy.cpp index 0032e9c6e7fea..b6fe78288e97a 100644 --- a/src/rt/rust_android_dummy.cpp +++ b/src/rt/rust_android_dummy.cpp @@ -64,7 +64,10 @@ extern "C" void tgammaf() { } -extern "C" int glob(const char *pattern, int flags, int (*errfunc) (const char *epath, int eerrno), glob_t *pglob) +extern "C" int glob(const char *pattern, + int flags, + int (*errfunc) (const char *epath, int eerrno), + glob_t *pglob) { return 0; } From 6806900a7c63950feb2540347fc3f94d83074bbd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 5 May 2013 07:43:43 -0400 Subject: [PATCH 199/215] disable lang debug for perf --- src/libcore/unstable/lang.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 5a65a5c24bb57..6b61df31fdc87 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -152,7 +152,7 @@ pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { /// Because this code is so perf. sensitive, use a static constant so that /// debug printouts are compiled out most of the time. -static ENABLE_DEBUG: bool = true; +static ENABLE_DEBUG: bool = false; #[inline] pub fn debug_mem(tag: &'static str, p: *const T) { From 0b0b8018a6a1271e6c8e82230e2e8496eebbba3f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 5 May 2013 12:17:59 -0400 Subject: [PATCH 200/215] add warning for #6248 and remove instances of it --- src/libcore/hashmap.rs | 13 +++++++ src/librustc/metadata/encoder.rs | 8 ++--- .../middle/borrowck/gather_loans/lifetime.rs | 36 +++++++++++++++---- src/librustc/middle/check_const.rs | 2 +- src/librustc/middle/check_match.rs | 4 +-- src/librustc/middle/kind.rs | 8 ++--- src/librustc/middle/lint.rs | 2 +- src/librustc/middle/liveness.rs | 8 ++--- src/librustc/middle/mem_categorization.rs | 4 +-- src/librustc/middle/moves.rs | 2 +- src/librustc/middle/privacy.rs | 4 +-- src/librustc/middle/region.rs | 2 +- src/librustc/middle/trans/_match.rs | 6 ++-- src/librustc/middle/trans/base.rs | 6 ++-- src/librustc/middle/trans/closure.rs | 2 +- src/librustc/middle/trans/consts.rs | 6 ++-- src/librustc/middle/trans/controlflow.rs | 2 +- src/librustc/middle/trans/debuginfo.rs | 6 ++-- src/librustc/middle/trans/expr.rs | 4 +-- src/librustc/middle/trans/foreign.rs | 2 +- src/librustc/middle/trans/machine.rs | 2 +- src/librustc/middle/trans/meth.rs | 8 ++--- src/librustc/middle/trans/monomorphize.rs | 14 ++++---- src/librustc/middle/trans/reachable.rs | 19 ++++++---- src/librustc/middle/trans/reflect.rs | 7 ++-- src/librustc/middle/trans/type_use.rs | 33 +++++++++-------- src/librustc/middle/ty.rs | 4 +-- src/librustc/middle/typeck/check/_match.rs | 2 +- src/librustc/middle/typeck/check/mod.rs | 8 ++--- src/librustc/middle/typeck/check/vtable.rs | 2 +- src/librustc/middle/typeck/coherence.rs | 6 ++-- src/librustc/middle/typeck/collect.rs | 2 +- 32 files changed, 142 insertions(+), 92 deletions(-) diff --git a/src/libcore/hashmap.rs b/src/libcore/hashmap.rs index ad1994a92d2bb..8ed54741f1276 100644 --- a/src/libcore/hashmap.rs +++ b/src/libcore/hashmap.rs @@ -25,6 +25,7 @@ use rand; use uint; use vec; use util::unreachable; +use kinds::Copy; static INITIAL_CAPACITY: uint = 32u; // 2^5 @@ -529,6 +530,18 @@ pub impl HashMap { } } +pub impl HashMap { + /// Like `find`, but returns a copy of the value. + fn find_copy(&self, k: &K) -> Option { + self.find(k).map_consume(|v| copy *v) + } + + /// Like `get`, but returns a copy of the value. + fn get_copy(&self, k: &K) -> V { + copy *self.get(k) + } +} + impl Eq for HashMap { fn eq(&self, other: &HashMap) -> bool { if self.len() != other.len() { return false; } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index dd4ef0d2e688f..6d7442b1ed5ee 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -190,7 +190,7 @@ fn encode_type_param_bounds(ebml_w: &writer::Encoder, ecx: @EncodeContext, params: &OptVec) { let ty_param_defs = - @params.map_to_vec(|param| *ecx.tcx.ty_param_defs.get(¶m.id)); + @params.map_to_vec(|param| ecx.tcx.ty_param_defs.get_copy(¶m.id)); encode_ty_type_param_defs(ebml_w, ecx, ty_param_defs, tag_items_data_item_ty_param_bounds); } @@ -275,7 +275,7 @@ fn encode_symbol(ecx: @EncodeContext, ebml_w: &writer::Encoder, id: node_id) { fn encode_discriminant(ecx: @EncodeContext, ebml_w: &writer::Encoder, id: node_id) { ebml_w.start_tag(tag_items_data_item_symbol); - ebml_w.writer.write(str::to_bytes(**ecx.discrim_symbols.get(&id))); + ebml_w.writer.write(str::to_bytes(*ecx.discrim_symbols.get_copy(&id))); ebml_w.end_tag(); } @@ -1035,7 +1035,7 @@ fn encode_info_for_items(ecx: @EncodeContext, ebml_w: &writer::Encoder, let ebml_w = copy *ebml_w; |i, cx, v| { visit::visit_item(i, cx, v); - match *ecx.tcx.items.get(&i.id) { + match ecx.tcx.items.get_copy(&i.id) { ast_map::node_item(_, pt) => { encode_info_for_item(ecx, &ebml_w, i, index, *pt); @@ -1048,7 +1048,7 @@ fn encode_info_for_items(ecx: @EncodeContext, ebml_w: &writer::Encoder, let ebml_w = copy *ebml_w; |ni, cx, v| { visit::visit_foreign_item(ni, cx, v); - match *ecx.tcx.items.get(&ni.id) { + match ecx.tcx.items.get_copy(&ni.id) { ast_map::node_foreign_item(_, abi, _, pt) => { encode_info_for_foreign_item(ecx, &ebml_w, ni, index, /*bad*/copy *pt, diff --git a/src/librustc/middle/borrowck/gather_loans/lifetime.rs b/src/librustc/middle/borrowck/gather_loans/lifetime.rs index 43fff110a7a7e..330d60a59d3ae 100644 --- a/src/librustc/middle/borrowck/gather_loans/lifetime.rs +++ b/src/librustc/middle/borrowck/gather_loans/lifetime.rs @@ -18,6 +18,7 @@ use middle::ty; use syntax::ast::{m_const, m_imm, m_mutbl}; use syntax::ast; use syntax::codemap::span; +use util::ppaux::{note_and_explain_region}; pub fn guarantee_lifetime(bccx: @BorrowckCtxt, item_scope_id: ast::node_id, @@ -215,13 +216,6 @@ impl GuaranteeLifetimeContext { } }; - // FIXME(#3511) grow to the nearest cleanup scope---this can - // cause observable errors if freezing! - if !self.bccx.tcx.region_maps.is_cleanup_scope(root_scope) { - debug!("%? is not a cleanup scope, adjusting", root_scope); - root_scope = self.bccx.tcx.region_maps.cleanup_scope(root_scope); - } - // If we are borrowing the inside of an `@mut` box, // we need to dynamically mark it to prevent incompatible // borrows from happening later. @@ -235,6 +229,34 @@ impl GuaranteeLifetimeContext { } }; + // FIXME(#3511) grow to the nearest cleanup scope---this can + // cause observable errors if freezing! + if !self.bccx.tcx.region_maps.is_cleanup_scope(root_scope) { + debug!("%? is not a cleanup scope, adjusting", root_scope); + + let cleanup_scope = + self.bccx.tcx.region_maps.cleanup_scope(root_scope); + + if opt_dyna.is_some() { + self.tcx().sess.span_warn( + self.span, + fmt!("Dynamic freeze scope artifically extended \ + (see Issue #6248)")); + note_and_explain_region( + self.bccx.tcx, + "managed value only needs to be frozen for ", + ty::re_scope(root_scope), + "..."); + note_and_explain_region( + self.bccx.tcx, + "...but due to Issue #6248, it will be frozen for ", + ty::re_scope(cleanup_scope), + ""); + } + + root_scope = cleanup_scope; + } + // Add a record of what is required let rm_key = root_map_key {id: cmt_deref.id, derefs: derefs}; let root_info = RootInfo {scope: root_scope, freeze: opt_dyna}; diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index 6a47eedcea8c3..0bb156dd5f642 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -237,7 +237,7 @@ pub fn check_item_recursion(sess: Session, match env.def_map.find(&e.id) { Some(&def_const(def_id)) => { if ast_util::is_local(def_id) { - match *env.ast_map.get(&def_id.node) { + match env.ast_map.get_copy(&def_id.node) { ast_map::node_item(it, _) => { (v.visit_item)(it, env, v); } diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index 852eb1b50a499..5be0c09f4ae4a 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -523,7 +523,7 @@ pub fn specialize(cx: @MatchCheckCtxt, } } pat_enum(_, args) => { - match *cx.tcx.def_map.get(&pat_id) { + match cx.tcx.def_map.get_copy(&pat_id) { def_const(did) => { let const_expr = lookup_const_by_id(cx.tcx, did).get(); @@ -567,7 +567,7 @@ pub fn specialize(cx: @MatchCheckCtxt, } pat_struct(_, ref flds, _) => { // Is this a struct or an enum variant? - match *cx.tcx.def_map.get(&pat_id) { + match cx.tcx.def_map.get_copy(&pat_id) { def_variant(_, variant_id) => { if variant(variant_id) == *ctor_id { // FIXME #4731: Is this right? --pcw diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 199eb274ab9e1..3afe8c3b9d68f 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -128,7 +128,7 @@ fn check_item(item: @item, cx: Context, visitor: visit::vt) { // Yes, it's a destructor. match self_type.node { ty_path(_, path_node_id) => { - let struct_def = *cx.tcx.def_map.get( + let struct_def = cx.tcx.def_map.get_copy( &path_node_id); let struct_did = ast_util::def_id_of_def(struct_def); @@ -272,7 +272,7 @@ pub fn check_expr(e: @expr, cx: Context, v: visit::vt) { let ts = /*bad*/ copy **ts; let type_param_defs = match e.node { expr_path(_) => { - let did = ast_util::def_id_of_def(*cx.tcx.def_map.get(&e.id)); + let did = ast_util::def_id_of_def(cx.tcx.def_map.get_copy(&e.id)); ty::lookup_item_type(cx.tcx, did).generics.type_param_defs } _ => { @@ -333,7 +333,7 @@ fn check_ty(aty: @Ty, cx: Context, v: visit::vt) { for cx.tcx.node_type_substs.find(&id).each |ts| { // FIXME(#5562): removing this copy causes a segfault before stage2 let ts = /*bad*/ copy **ts; - let did = ast_util::def_id_of_def(*cx.tcx.def_map.get(&id)); + let did = ast_util::def_id_of_def(cx.tcx.def_map.get_copy(&id)); let type_param_defs = ty::lookup_item_type(cx.tcx, did).generics.type_param_defs; for vec::each2(ts, *type_param_defs) |&ty, type_param_def| { @@ -399,7 +399,7 @@ pub fn check_bounds(cx: Context, fn is_nullary_variant(cx: Context, ex: @expr) -> bool { match ex.node { expr_path(_) => { - match *cx.tcx.def_map.get(&ex.id) { + match cx.tcx.def_map.get_copy(&ex.id) { def_variant(edid, vdid) => { vec::len(ty::enum_variant_with_id(cx.tcx, edid, vdid).args) == 0u } diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index faf4b1c31061b..c54ff6075faa7 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -696,7 +696,7 @@ fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) { for vec::each(vec::append_one(tys, decl.output)) |ty| { match ty.node { ast::ty_path(_, id) => { - match *cx.def_map.get(&id) { + match cx.def_map.get_copy(&id) { ast::def_prim_ty(ast::ty_int(ast::ty_i)) => { cx.sess.span_lint( ctypes, id, fn_id, diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 59a6e6469e2bb..60ce34c3af271 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -469,7 +469,7 @@ fn visit_expr(expr: @expr, self: @mut IrMaps, vt: vt<@mut IrMaps>) { match expr.node { // live nodes required for uses or definitions of variables: expr_path(_) => { - let def = *self.tcx.def_map.get(&expr.id); + let def = self.tcx.def_map.get_copy(&expr.id); debug!("expr %d: path that leads to %?", expr.id, def); if moves::moved_variable_node_id_from_def(def).is_some() { self.add_live_node_for_node(expr.id, ExprNode(expr.span)); @@ -616,7 +616,7 @@ pub impl Liveness { fn variable_from_path(&self, expr: @expr) -> Option { match expr.node { expr_path(_) => { - let def = *self.tcx.def_map.get(&expr.id); + let def = self.tcx.def_map.get_copy(&expr.id); moves::moved_variable_node_id_from_def(def).map( |rdef| self.variable(*rdef, expr.span) ) @@ -1338,7 +1338,7 @@ pub impl Liveness { fn access_path(&self, expr: @expr, succ: LiveNode, acc: uint) -> LiveNode { - let def = *self.tcx.def_map.get(&expr.id); + let def = self.tcx.def_map.get_copy(&expr.id); match moves::moved_variable_node_id_from_def(def) { Some(nid) => { let ln = self.live_node(expr.id, expr.span); @@ -1605,7 +1605,7 @@ pub impl Liveness { fn check_lvalue(@self, expr: @expr, vt: vt<@Liveness>) { match expr.node { expr_path(_) => { - match *self.tcx.def_map.get(&expr.id) { + match self.tcx.def_map.get_copy(&expr.id) { def_local(nid, mutbl) => { // Assignment to an immutable variable or argument: only legal // if there is no later assignment. If this local is actually diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 2e5e53654a455..da0a3ba25d071 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -409,7 +409,7 @@ pub impl mem_categorization_ctxt { } ast::expr_path(_) => { - let def = *self.tcx.def_map.get(&expr.id); + let def = self.tcx.def_map.get_copy(&expr.id); self.cat_def(expr.id, expr.span, expr_ty, def) } @@ -977,7 +977,7 @@ pub fn field_mutbl(tcx: ty::ctxt, } } ty::ty_enum(*) => { - match *tcx.def_map.get(&node_id) { + match tcx.def_map.get_copy(&node_id) { ast::def_variant(_, variant_id) => { for ty::lookup_struct_fields(tcx, variant_id).each |fld| { if fld.ident == f_name { diff --git a/src/librustc/middle/moves.rs b/src/librustc/middle/moves.rs index 0daad80af5db7..58345302d16fb 100644 --- a/src/librustc/middle/moves.rs +++ b/src/librustc/middle/moves.rs @@ -441,7 +441,7 @@ pub impl VisitContext { self.move_maps.variable_moves_map.insert( expr.id, entire_expr); - let def = *self.tcx.def_map.get(&expr.id); + let def = self.tcx.def_map.get_copy(&expr.id); for moved_variable_node_id_from_def(def).each |&id| { self.move_maps.moved_variables_set.insert(id); } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index a37ebdcfaa263..0df09553ad014 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -481,7 +481,7 @@ pub fn check_crate(tcx: ty::ctxt, } } expr_path(path) => { - check_path(expr.span, *tcx.def_map.get(&expr.id), path); + check_path(expr.span, tcx.def_map.get_copy(&expr.id), path); } expr_struct(_, ref fields, _) => { match ty::get(ty::expr_ty(tcx, expr)).sty { @@ -499,7 +499,7 @@ pub fn check_crate(tcx: ty::ctxt, ty_enum(id, _) => { if id.crate != local_crate || !privileged_items.contains(&(id.node)) { - match *tcx.def_map.get(&expr.id) { + match tcx.def_map.get_copy(&expr.id) { def_variant(_, variant_id) => { for (*fields).each |field| { debug!("(privacy checking) \ diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 06eb2542235e4..d23a798b6239e 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -949,7 +949,7 @@ pub fn determine_rp_in_crate(sess: Session, let cx = &mut *cx; while cx.worklist.len() != 0 { let c_id = cx.worklist.pop(); - let c_variance = { *cx.region_paramd_items.get(&c_id) }; + let c_variance = cx.region_paramd_items.get_copy(&c_id); // NOTE cleanup scopes cause an exaggerated lock here debug!("popped %d from worklist", c_id); match cx.dep_map.find(&c_id) { diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 1a81d483dfc3c..61a8b367d6cf6 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -280,7 +280,7 @@ pub fn trans_opt(bcx: block, o: &Opt) -> opt_result { pub fn variant_opt(bcx: block, pat_id: ast::node_id) -> Opt { let ccx = bcx.ccx(); - match *ccx.tcx.def_map.get(&pat_id) { + match ccx.tcx.def_map.get_copy(&pat_id) { ast::def_variant(enum_id, var_id) => { let variants = ty::enum_variants(ccx.tcx, enum_id); for vec::each(*variants) |v| { @@ -516,7 +516,7 @@ pub fn enter_opt<'r>(bcx: block, match p.node { ast::pat_enum(*) | ast::pat_ident(_, _, None) if pat_is_const(tcx.def_map, p) => { - let const_def = *tcx.def_map.get(&p.id); + let const_def = tcx.def_map.get_copy(&p.id); let const_def_id = ast_util::def_id_of_def(const_def); if opt_eq(tcx, &lit(ConstLit(const_def_id)), opt) { Some(~[]) @@ -552,7 +552,7 @@ pub fn enter_opt<'r>(bcx: block, if opt_eq(tcx, &variant_opt(bcx, p.id), opt) { // Look up the struct variant ID. let struct_id; - match *tcx.def_map.get(&p.id) { + match tcx.def_map.get_copy(&p.id) { ast::def_variant(_, found_struct_id) => { struct_id = found_struct_id; } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 47363aa9263f2..5419628cd958a 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2052,7 +2052,7 @@ pub fn trans_tuple_struct(ccx: @CrateContext, fcx.llretptr.get(), 0, i); - let llarg = match *fcx.llargs.get(&field.node.id) { + let llarg = match fcx.llargs.get_copy(&field.node.id) { local_mem(x) => x, _ => { ccx.tcx.sess.bug(~"trans_tuple_struct: llarg wasn't \ @@ -2141,7 +2141,7 @@ pub fn trans_enum_def(ccx: @CrateContext, enum_definition: &ast::enum_def, pub fn trans_item(ccx: @CrateContext, item: &ast::item) { let _icx = ccx.insn_ctxt("trans_item"); - let path = match *ccx.tcx.items.get(&item.id) { + let path = match ccx.tcx.items.get_copy(&item.id) { ast_map::node_item(_, p) => p, // tjc: ? _ => fail!(~"trans_item"), @@ -2443,7 +2443,7 @@ pub fn fill_fn_pair(bcx: block, pair: ValueRef, llfn: ValueRef, } pub fn item_path(ccx: @CrateContext, i: @ast::item) -> path { - let base = match *ccx.tcx.items.get(&i.id) { + let base = match ccx.tcx.items.get_copy(&i.id) { ast_map::node_item(_, p) => p, // separate map for paths? _ => fail!(~"item_path") diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index acd52907b9f73..a2a1f3d8b72fb 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -424,7 +424,7 @@ pub fn trans_expr_fn(bcx: block, let Result {bcx: bcx, val: closure} = match sigil { ast::BorrowedSigil | ast::ManagedSigil | ast::OwnedSigil => { - let cap_vars = *ccx.maps.capture_map.get(&user_id); + let cap_vars = ccx.maps.capture_map.get_copy(&user_id); let ret_handle = match is_loop_body {Some(x) => x, None => None}; let ClosureResult {llbox, cdata_ty, bcx} diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 3a331e8791ba2..dd68670287b7b 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -158,7 +158,7 @@ pub fn get_const_val(cx: @CrateContext, def_id: ast::def_id) -> ValueRef { if !ast_util::is_local(def_id) { def_id = inline::maybe_instantiate_inline(cx, def_id, true); } - match *cx.tcx.items.get(&def_id.node) { + match cx.tcx.items.get_copy(&def_id.node) { ast_map::node_item(@ast::item { node: ast::item_const(_, subexpr), _ }, _) => { @@ -167,7 +167,7 @@ pub fn get_const_val(cx: @CrateContext, def_id: ast::def_id) -> ValueRef { _ => cx.tcx.sess.bug(~"expected a const to be an item") } } - *cx.const_values.get(&def_id.node) + cx.const_values.get_copy(&def_id.node) } pub fn const_expr(cx: @CrateContext, e: @ast::expr) -> ValueRef { @@ -560,7 +560,7 @@ pub fn trans_const(ccx: @CrateContext, _e: @ast::expr, id: ast::node_id) { let g = base::get_item_val(ccx, id); // At this point, get_item_val has already translated the // constant's initializer to determine its LLVM type. - let v = *ccx.const_values.get(&id); + let v = ccx.const_values.get_copy(&id); llvm::LLVMSetInitializer(g, v); llvm::LLVMSetGlobalConstant(g, True); } diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index e91bec5efed4a..b16b77320860c 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -193,7 +193,7 @@ pub fn trans_log(log_ex: @ast::expr, }; let global = if ccx.module_data.contains_key(&modname) { - *ccx.module_data.get(&modname) + ccx.module_data.get_copy(&modname) } else { let s = link::mangle_internal_name_by_path_and_seq( ccx, modpath, ~"loglevel"); diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index 2a2bf7ba4ad68..1571fd71152cc 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -864,7 +864,7 @@ pub fn create_local_var(bcx: block, local: @ast::local) something weird"); } option::None => { - match *bcx.fcx.lllocals.get(&local.node.pat.id) { + match bcx.fcx.lllocals.get_copy(&local.node.pat.id) { local_imm(v) => v, _ => bcx.tcx().sess.span_bug(local.span, ~"local is bound to \ something weird") @@ -917,7 +917,7 @@ pub fn create_arg(bcx: block, arg: ast::arg, sp: span) }; update_cache(cache, tg, argument_metadata(mdval)); - let llptr = match *fcx.llargs.get(&arg.id) { + let llptr = match fcx.llargs.get_copy(&arg.id) { local_mem(v) | local_imm(v) => v, }; let declargs = ~[llmdnode(~[llptr]), mdnode]; @@ -960,7 +960,7 @@ pub fn create_function(fcx: fn_ctxt) -> @Metadata { let sp = fcx.span.get(); debug!("%s", cx.sess.codemap.span_to_str(sp)); - let (ident, ret_ty, id) = match *cx.tcx.items.get(&fcx.id) { + let (ident, ret_ty, id) = match cx.tcx.items.get_copy(&fcx.id) { ast_map::node_item(item, _) => { match item.node { ast::item_fn(ref decl, _, _, _, _) => { diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index b8cdfeb796db0..d961c0705e44c 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -1117,7 +1117,7 @@ pub fn with_field_tys(tcx: ty::ctxt, ty.repr(tcx))); } Some(node_id) => { - match *tcx.def_map.get(&node_id) { + match tcx.def_map.get_copy(&node_id) { ast::def_variant(enum_id, variant_id) => { let variant_info = ty::enum_variant_with_id( tcx, enum_id, variant_id); @@ -1536,7 +1536,7 @@ fn trans_overloaded_op(bcx: block, ret_ty: ty::t, dest: Dest) -> block { - let origin = *bcx.ccx().maps.method_map.get(&expr.id); + let origin = bcx.ccx().maps.method_map.get_copy(&expr.id); let fty = node_id_type(bcx, expr.callee_id); callee::trans_call_inner(bcx, expr.info(), diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index c45ba64c58470..f49a7fb0de41f 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -724,7 +724,7 @@ pub fn trans_intrinsic(ccx: @CrateContext, let in_type_size = machine::llbitsize_of_real(ccx, llintype); let out_type_size = machine::llbitsize_of_real(ccx, llouttype); if in_type_size != out_type_size { - let sp = match *ccx.tcx.items.get(&ref_id.get()) { + let sp = match ccx.tcx.items.get_copy(&ref_id.get()) { ast_map::node_expr(e) => e.span, _ => fail!(~"transmute has non-expr arg"), }; diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs index 3ae2421a55589..73b79fa37e2ee 100644 --- a/src/librustc/middle/trans/machine.rs +++ b/src/librustc/middle/trans/machine.rs @@ -118,7 +118,7 @@ pub fn llalign_of(cx: @CrateContext, t: TypeRef) -> ValueRef { // Computes the size of the data part of an enum. pub fn static_size_of_enum(cx: @CrateContext, t: ty::t) -> uint { if cx.enum_sizes.contains_key(&t) { - return *cx.enum_sizes.get(&t); + return cx.enum_sizes.get_copy(&t); } debug!("static_size_of_enum %s", ty_to_str(cx.tcx, t)); diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 86b087b937f25..693947d7e99bd 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -312,7 +312,7 @@ pub fn trans_static_method_callee(bcx: block, }; let mname = if method_id.crate == ast::local_crate { - match *bcx.tcx().items.get(&method_id.node) { + match bcx.tcx().items.get_copy(&method_id.node) { ast_map::node_trait_method(trait_method, _, _) => { ast_util::trait_method_to_ty_method(trait_method).ident } @@ -329,7 +329,7 @@ pub fn trans_static_method_callee(bcx: block, name=%s", method_id, callee_id, *ccx.sess.str_of(mname)); let vtbls = resolve_vtables_in_fn_ctxt( - bcx.fcx, *ccx.maps.vtable_map.get(&callee_id)); + bcx.fcx, ccx.maps.vtable_map.get_copy(&callee_id)); match vtbls[bound_index] { typeck::vtable_static(impl_did, ref rcvr_substs, rcvr_origins) => { @@ -367,7 +367,7 @@ pub fn method_from_methods(ms: &[@ast::method], name: ast::ident) pub fn method_with_name(ccx: @CrateContext, impl_id: ast::def_id, name: ast::ident) -> ast::def_id { if impl_id.crate == ast::local_crate { - match *ccx.tcx.items.get(&impl_id.node) { + match ccx.tcx.items.get_copy(&impl_id.node) { ast_map::node_item(@ast::item { node: ast::item_impl(_, _, _, ref ms), _ @@ -385,7 +385,7 @@ pub fn method_with_name_or_default(ccx: @CrateContext, impl_id: ast::def_id, name: ast::ident) -> ast::def_id { if impl_id.crate == ast::local_crate { - match *ccx.tcx.items.get(&impl_id.node) { + match ccx.tcx.items.get_copy(&impl_id.node) { ast_map::node_item(@ast::item { node: ast::item_impl(_, _, _, ref ms), _ }, _) => { diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs index 98db829370c0c..e1b81933e6881 100644 --- a/src/librustc/middle/trans/monomorphize.rs +++ b/src/librustc/middle/trans/monomorphize.rs @@ -101,12 +101,14 @@ pub fn monomorphic_fn(ccx: @CrateContext, let tpt = ty::lookup_item_type(ccx.tcx, fn_id); let llitem_ty = tpt.ty; - let map_node = session::expect(ccx.sess, ccx.tcx.items.find(&fn_id.node), - || fmt!("While monomorphizing %?, couldn't find it in the item map \ - (may have attempted to monomorphize an item defined in a different \ - crate?)", fn_id)); + let map_node = session::expect( + ccx.sess, + ccx.tcx.items.find_copy(&fn_id.node), + || fmt!("While monomorphizing %?, couldn't find it in the item map \ + (may have attempted to monomorphize an item \ + defined in a different crate?)", fn_id)); // Get the path so that we can create a symbol - let (pt, name, span) = match *map_node { + let (pt, name, span) = match map_node { ast_map::node_item(i, pt) => (pt, i.ident, i.span), ast_map::node_variant(ref v, enm, pt) => (pt, (*v).node.name, enm.span), ast_map::node_method(m, _, pt) => (pt, m.ident, m.span), @@ -188,7 +190,7 @@ pub fn monomorphic_fn(ccx: @CrateContext, self_ty: impl_ty_opt }); - let lldecl = match *map_node { + let lldecl = match map_node { ast_map::node_item(i@@ast::item { node: ast::item_fn(ref decl, _, _, _, ref body), _ diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs index a446408d00a10..058ce638030b9 100644 --- a/src/librustc/middle/trans/reachable.rs +++ b/src/librustc/middle/trans/reachable.rs @@ -109,7 +109,8 @@ fn traverse_public_item(cx: @mut ctx, item: @item) { item_foreign_mod(ref nm) => { if !traverse_exports(cx, item.id) { for nm.items.each |item| { - (&mut *cx).rmap.insert(item.id); // NOTE reborrow @mut + let cx = &mut *cx; // NOTE reborrow @mut + cx.rmap.insert(item.id); } } } @@ -125,17 +126,24 @@ fn traverse_public_item(cx: @mut ctx, item: @item) { m.generics.ty_params.len() > 0u || attr::find_inline_attr(m.attrs) != attr::ia_none { - (&mut *cx).rmap.insert(m.id); // NOTE reborrow @mut + { + let cx = &mut *cx; // NOTE reborrow @mut + cx.rmap.insert(m.id); + } traverse_inline_body(cx, &m.body); } } } item_struct(ref struct_def, ref generics) => { for struct_def.ctor_id.each |&ctor_id| { - (&mut *cx).rmap.insert(ctor_id); // NOTE reborrow @mut + let cx = &mut *cx; // NOTE reborrow @mut + cx.rmap.insert(ctor_id); } for struct_def.dtor.each |dtor| { - (&mut *cx).rmap.insert(dtor.node.id); + { + let cx = &mut *cx; // NOTE reborrow @mut + cx.rmap.insert(dtor.node.id); + } if generics.ty_params.len() > 0u || attr::find_inline_attr(dtor.node.attrs) != attr::ia_none { @@ -156,8 +164,7 @@ fn traverse_public_item(cx: @mut ctx, item: @item) { fn traverse_ty<'a>(ty: @Ty, cx: @mut ctx<'a>, v: visit::vt<@mut ctx<'a>>) { { - // FIXME #6021: naming rmap shouldn't be necessary - let cx = &mut *cx; + let cx = &mut *cx; // NOTE reborrow @mut if cx.rmap.contains(&ty.id) { return; } cx.rmap.insert(ty.id); } diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs index 7e59f580a2c3c..5f77173f56321 100644 --- a/src/librustc/middle/trans/reflect.rs +++ b/src/librustc/middle/trans/reflect.rs @@ -274,8 +274,9 @@ pub impl Reflector { let repr = adt::represent_type(bcx.ccx(), t); let variants = ty::substd_enum_variants(ccx.tcx, did, substs); let llptrty = T_ptr(type_of(ccx, t)); - let (_, opaquety) = *(ccx.tcx.intrinsic_defs.find(&ccx.sess.ident_of(~"Opaque")) - .expect("Failed to resolve intrinsic::Opaque")); + let (_, opaquety) = + ccx.tcx.intrinsic_defs.find_copy(&ccx.sess.ident_of(~"Opaque")) + .expect("Failed to resolve intrinsic::Opaque"); let opaqueptrty = ty::mk_ptr(ccx.tcx, ty::mt { ty: opaquety, mutbl: ast::m_imm }); let make_get_disr = || { @@ -374,7 +375,7 @@ pub fn emit_calls_to_trait_visit_ty(bcx: block, use syntax::parse::token::special_idents::tydesc; let final = sub_block(bcx, ~"final"); assert!(bcx.ccx().tcx.intrinsic_defs.contains_key(&tydesc)); - let (_, tydesc_ty) = *bcx.ccx().tcx.intrinsic_defs.get(&tydesc); + let (_, tydesc_ty) = bcx.ccx().tcx.intrinsic_defs.get_copy(&tydesc); let tydesc_ty = type_of(bcx.ccx(), tydesc_ty); let mut r = Reflector { visitor_val: visitor_val, diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index 33145dd4334a5..fb2358a57e2a7 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -239,18 +239,11 @@ pub fn node_type_needs(cx: Context, use_: uint, id: node_id) { } pub fn mark_for_method_call(cx: Context, e_id: node_id, callee_id: node_id) { + let mut opt_static_did = None; for cx.ccx.maps.method_map.find(&e_id).each |mth| { match mth.origin { typeck::method_static(did) => { - for cx.ccx.tcx.node_type_substs.find(&callee_id).each |ts| { - // FIXME(#5562): removing this copy causes a segfault - // before stage2 - let ts = /*bad*/ copy **ts; - let type_uses = type_uses_for(cx.ccx, did, ts.len()); - for vec::each2(*type_uses, ts) |uses, subst| { - type_needs(cx, *uses, *subst) - } - } + opt_static_did = Some(did); } typeck::method_param(typeck::method_param { param_num: param, @@ -262,6 +255,19 @@ pub fn mark_for_method_call(cx: Context, e_id: node_id, callee_id: node_id) { | typeck::method_super(*) => (), } } + + // Note: we do not execute this code from within the each() call + // above because the recursive call to `type_needs` can trigger + // inlining and hence can cause `method_map` and + // `node_type_substs` to be modified. + for opt_static_did.each |did| { + for cx.ccx.tcx.node_type_substs.find_copy(&callee_id).each |ts| { + let type_uses = type_uses_for(cx.ccx, did, ts.len()); + for vec::each2(*type_uses, ts) |uses, subst| { + type_needs(cx, *uses, *subst) + } + } + } } pub fn mark_for_expr(cx: Context, e: @expr) { @@ -291,12 +297,11 @@ pub fn mark_for_expr(cx: Context, e: @expr) { } } expr_path(_) => { - for cx.ccx.tcx.node_type_substs.find(&e.id).each |ts| { - // FIXME(#5562): removing this copy causes a segfault before stage2 - let ts = copy **ts; - let id = ast_util::def_id_of_def(*cx.ccx.tcx.def_map.get(&e.id)); + let opt_ts = cx.ccx.tcx.node_type_substs.find_copy(&e.id); + for opt_ts.each |ts| { + let id = ast_util::def_id_of_def(cx.ccx.tcx.def_map.get_copy(&e.id)); let uses_for_ts = type_uses_for(cx.ccx, id, ts.len()); - for vec::each2(*uses_for_ts, ts) |uses, subst| { + for vec::each2(*uses_for_ts, *ts) |uses, subst| { type_needs(cx, *uses, *subst) } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index b17dac82048bf..eac73ce1a2e0a 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -3893,7 +3893,7 @@ pub fn enum_variants(cx: ctxt, id: ast::def_id) -> @~[VariantInfo] { call eval_const_expr, it should never get called twice for the same expr, since check_enum_variants also updates the enum_var_cache */ - match *cx.items.get(&id.node) { + match cx.items.get_copy(&id.node) { ast_map::node_item(@ast::item { node: ast::item_enum(ref enum_definition, _), _ @@ -4424,7 +4424,7 @@ pub fn get_impl_id(tcx: ctxt, trait_id: def_id, self_ty: t) -> def_id { pub fn visitor_object_ty(tcx: ctxt) -> (@TraitRef, t) { let ty_visitor_name = special_idents::ty_visitor; assert!(tcx.intrinsic_traits.contains_key(&ty_visitor_name)); - let trait_ref = *tcx.intrinsic_traits.get(&ty_visitor_name); + let trait_ref = tcx.intrinsic_traits.get_copy(&ty_visitor_name); (trait_ref, mk_trait(tcx, trait_ref.def_id, copy trait_ref.substs, BoxTraitStore, ast::m_imm)) } diff --git a/src/librustc/middle/typeck/check/_match.rs b/src/librustc/middle/typeck/check/_match.rs index 0c9b61164d231..a3bf1a5ef52d4 100644 --- a/src/librustc/middle/typeck/check/_match.rs +++ b/src/librustc/middle/typeck/check/_match.rs @@ -404,7 +404,7 @@ pub fn check_pat(pcx: &pat_ctxt, pat: @ast::pat, expected: ty::t) { } ast::pat_enum(*) | ast::pat_ident(*) if pat_is_const(tcx.def_map, pat) => { - let const_did = ast_util::def_id_of_def(*tcx.def_map.get(&pat.id)); + let const_did = ast_util::def_id_of_def(tcx.def_map.get_copy(&pat.id)); let const_tpt = ty::lookup_item_type(tcx, const_did); demand::suptype(fcx, pat.span, expected, const_tpt.ty); fcx.write_ty(pat.id, const_tpt.ty); diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 70282fdc57cfe..09022b5829a14 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -433,7 +433,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, assign(self_info.self_id, Some(self_info.self_ty)); debug!("self is assigned to %s", fcx.infcx().ty_to_str( - *fcx.inh.locals.get(&self_info.self_id))); + fcx.inh.locals.get_copy(&self_info.self_id))); } // Add formal parameters. @@ -466,7 +466,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, debug!("Local variable %s is assigned type %s", fcx.pat_to_str(local.node.pat), fcx.infcx().ty_to_str( - *fcx.inh.locals.get(&local.node.id))); + fcx.inh.locals.get_copy(&local.node.id))); visit::visit_local(local, e, v); }; @@ -479,7 +479,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, debug!("Pattern binding %s is assigned to %s", *tcx.sess.str_of(path.idents[0]), fcx.infcx().ty_to_str( - *fcx.inh.locals.get(&p.id))); + fcx.inh.locals.get_copy(&p.id))); } _ => {} } @@ -3492,7 +3492,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) { ~"visit_tydesc" => { let tydesc_name = special_idents::tydesc; assert!(tcx.intrinsic_defs.contains_key(&tydesc_name)); - let (_, tydesc_ty) = *tcx.intrinsic_defs.get(&tydesc_name); + let (_, tydesc_ty) = tcx.intrinsic_defs.get_copy(&tydesc_name); let (_, visitor_object_ty) = ty::visitor_object_ty(tcx); let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt { ty: tydesc_ty, diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index c177d5ab0eb3a..100e23e024c45 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -490,7 +490,7 @@ pub fn early_resolve_expr(ex: @ast::expr, for fcx.opt_node_ty_substs(ex.id) |substs| { debug!("vtable resolution on parameter bounds for expr %s", ex.repr(fcx.tcx())); - let def = *cx.tcx.def_map.get(&ex.id); + let def = cx.tcx.def_map.get_copy(&ex.id); let did = ast_util::def_id_of_def(def); let item_ty = ty::lookup_item_type(cx.tcx, did); debug!("early resolve expr: def %? %?, %?, %s", ex.id, did, def, diff --git a/src/librustc/middle/typeck/coherence.rs b/src/librustc/middle/typeck/coherence.rs index d779c20b3e81c..09f0b83e61689 100644 --- a/src/librustc/middle/typeck/coherence.rs +++ b/src/librustc/middle/typeck/coherence.rs @@ -651,7 +651,7 @@ pub impl CoherenceChecker { fn get_self_type_for_implementation(&self, implementation: @Impl) -> ty_param_bounds_and_ty { - return *self.crate_context.tcx.tcache.get(&implementation.did); + return self.crate_context.tcx.tcache.get_copy(&implementation.did); } // Privileged scope checking @@ -711,7 +711,7 @@ pub impl CoherenceChecker { fn trait_ref_to_trait_def_id(&self, trait_ref: @trait_ref) -> def_id { let def_map = self.crate_context.tcx.def_map; - let trait_def = *def_map.get(&trait_ref.ref_id); + let trait_def = def_map.get_copy(&trait_ref.ref_id); let trait_id = def_id_of_def(trait_def); return trait_id; } @@ -751,7 +751,7 @@ pub impl CoherenceChecker { -> bool { match original_type.node { ty_path(_, path_id) => { - match *self.crate_context.tcx.def_map.get(&path_id) { + match self.crate_context.tcx.def_map.get_copy(&path_id) { def_ty(def_id) | def_struct(def_id) => { if def_id.crate != local_crate { return false; diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 0ffd398d03c19..3da6995b42362 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -220,7 +220,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt, { let tcx = ccx.tcx; let region_paramd = tcx.region_paramd_items.find(&trait_id).map(|&x| *x); - match *tcx.items.get(&trait_id) { + match tcx.items.get_copy(&trait_id) { ast_map::node_item(@ast::item { node: ast::item_trait(ref generics, _, ref ms), _ From 6cb273ed4efb6724b1c713c3ac35d14e52999fb1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 5 May 2013 13:50:10 -0400 Subject: [PATCH 201/215] Address all FIXMEs from #5562 --- src/librustc/middle/astencode.rs | 8 +++----- src/librustc/middle/kind.rs | 8 ++------ src/librustc/middle/trans/base.rs | 2 +- src/librustc/middle/trans/callee.rs | 6 +----- src/librustc/middle/trans/type_of.rs | 6 ++---- src/librustc/middle/trans/type_use.rs | 4 ++-- 6 files changed, 11 insertions(+), 23 deletions(-) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 7a3bdce875da2..fad1af749ea7e 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -739,7 +739,7 @@ trait ebml_writer_helpers { fn emit_arg(&self, ecx: @e::EncodeContext, arg: ty::arg); fn emit_ty(&self, ecx: @e::EncodeContext, ty: ty::t); fn emit_vstore(&self, ecx: @e::EncodeContext, vstore: ty::vstore); - fn emit_tys(&self, ecx: @e::EncodeContext, tys: ~[ty::t]); + fn emit_tys(&self, ecx: @e::EncodeContext, tys: &[ty::t]); fn emit_type_param_def(&self, ecx: @e::EncodeContext, type_param_def: &ty::TypeParameterDef); @@ -766,7 +766,7 @@ impl ebml_writer_helpers for writer::Encoder { } } - fn emit_tys(&self, ecx: @e::EncodeContext, tys: ~[ty::t]) { + fn emit_tys(&self, ecx: @e::EncodeContext, tys: &[ty::t]) { do self.emit_from_vec(tys) |ty| { self.emit_ty(ecx, *ty) } @@ -868,9 +868,7 @@ fn encode_side_tables_for_id(ecx: @e::EncodeContext, do ebml_w.tag(c::tag_table_node_type_subst) { ebml_w.id(id); do ebml_w.tag(c::tag_table_val) { - // FIXME(#5562): removing this copy causes a segfault - // before stage2 - ebml_w.emit_tys(ecx, /*bad*/copy **tys) + ebml_w.emit_tys(ecx, **tys) } } } diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index 3afe8c3b9d68f..44090e32880bc 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -268,8 +268,6 @@ pub fn check_expr(e: @expr, cx: Context, v: visit::vt) { _ => e.id }; for cx.tcx.node_type_substs.find(&type_parameter_id).each |ts| { - // FIXME(#5562): removing this copy causes a segfault before stage2 - let ts = /*bad*/ copy **ts; let type_param_defs = match e.node { expr_path(_) => { let did = ast_util::def_id_of_def(cx.tcx.def_map.get_copy(&e.id)); @@ -293,7 +291,7 @@ pub fn check_expr(e: @expr, cx: Context, v: visit::vt) { ts.repr(cx.tcx), type_param_defs.repr(cx.tcx))); } - for vec::each2(ts, *type_param_defs) |&ty, type_param_def| { + for vec::each2(**ts, *type_param_defs) |&ty, type_param_def| { check_bounds(cx, type_parameter_id, e.span, ty, type_param_def) } } @@ -331,12 +329,10 @@ fn check_ty(aty: @Ty, cx: Context, v: visit::vt) { match aty.node { ty_path(_, id) => { for cx.tcx.node_type_substs.find(&id).each |ts| { - // FIXME(#5562): removing this copy causes a segfault before stage2 - let ts = /*bad*/ copy **ts; let did = ast_util::def_id_of_def(cx.tcx.def_map.get_copy(&id)); let type_param_defs = ty::lookup_item_type(cx.tcx, did).generics.type_param_defs; - for vec::each2(ts, *type_param_defs) |&ty, type_param_def| { + for vec::each2(**ts, *type_param_defs) |&ty, type_param_def| { check_bounds(cx, aty.id, aty.span, ty, type_param_def) } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 5419628cd958a..8082e9cce5171 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2501,7 +2501,7 @@ pub fn get_item_val(ccx: @CrateContext, id: ast::node_id) -> ValueRef { Some(&v) => v, None => { let mut exprt = false; - let val = match *ccx.tcx.items.get(&id) { + let val = match ccx.tcx.items.get_copy(&id) { ast_map::node_item(i, pth) => { let my_path = vec::append(/*bad*/copy *pth, ~[path_name(i.ident)]); diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index c4c6133b405c0..12f91fb8597bd 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -339,16 +339,12 @@ pub fn trans_method_call(in_cx: block, node_id_type(in_cx, call_ex.callee_id), expr_ty(in_cx, call_ex), |cx| { - match cx.ccx().maps.method_map.find(&call_ex.id) { + match cx.ccx().maps.method_map.find_copy(&call_ex.id) { Some(origin) => { debug!("origin for %s: %s", call_ex.repr(in_cx.tcx()), origin.repr(in_cx.tcx())); - // FIXME(#5562): removing this copy causes a segfault - // before stage2 - let origin = /*bad*/ copy *origin; - meth::trans_method_callee(cx, call_ex.callee_id, rcvr, diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index a842f91f0ed6e..fc27c11c06f24 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -110,8 +110,7 @@ pub fn type_of_non_gc_box(cx: @CrateContext, t: ty::t) -> TypeRef { pub fn sizing_type_of(cx: @CrateContext, t: ty::t) -> TypeRef { match cx.llsizingtypes.find(&t) { - // FIXME(#5562): removing this copy causes a segfault in stage1 core - Some(t) => return /*bad*/ copy *t, + Some(t) => return *t, None => () } @@ -178,8 +177,7 @@ pub fn type_of(cx: @CrateContext, t: ty::t) -> TypeRef { // Check the cache. match cx.lltypes.find(&t) { - // FIXME(#5562): removing this copy causes a segfault in stage1 core - Some(t) => return /*bad*/ copy *t, + Some(&t) => return t, None => () } diff --git a/src/librustc/middle/trans/type_use.rs b/src/librustc/middle/trans/type_use.rs index fb2358a57e2a7..46cc99e71cc11 100644 --- a/src/librustc/middle/trans/type_use.rs +++ b/src/librustc/middle/trans/type_use.rs @@ -260,10 +260,10 @@ pub fn mark_for_method_call(cx: Context, e_id: node_id, callee_id: node_id) { // above because the recursive call to `type_needs` can trigger // inlining and hence can cause `method_map` and // `node_type_substs` to be modified. - for opt_static_did.each |did| { + for opt_static_did.each |&did| { for cx.ccx.tcx.node_type_substs.find_copy(&callee_id).each |ts| { let type_uses = type_uses_for(cx.ccx, did, ts.len()); - for vec::each2(*type_uses, ts) |uses, subst| { + for vec::each2(*type_uses, *ts) |uses, subst| { type_needs(cx, *uses, *subst) } } From aca2a00fb4cf2ec182cb7802194813c5dd6bbf27 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Mon, 6 May 2013 03:09:19 +0900 Subject: [PATCH 202/215] Fix span tests --- src/libsyntax/parse/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/parse/mod.rs b/src/libsyntax/parse/mod.rs index 74e4f562ce5c5..4e6abc68ffa75 100644 --- a/src/libsyntax/parse/mod.rs +++ b/src/libsyntax/parse/mod.rs @@ -590,7 +590,7 @@ mod test { types: ~[]}, None // no idea ), - span: sp(0,3)}, // really? + span: sp(0,1)}, id: 4 // fixme }) } @@ -627,7 +627,7 @@ mod test { types: ~[]}, None // no idea ), - span: sp(6,9)}, // bleah. + span: sp(6,7)}, id: 4 // fixme }], output: @ast::Ty{id:5, // fixme From 7b36e34c89372b4a159d4ad565ce11d412fbea04 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sun, 5 May 2013 21:05:37 -0400 Subject: [PATCH 203/215] Fix two more write guard failures --- src/librustc/middle/resolve.rs | 10 ++-- src/libsyntax/ext/pipes/liveness.rs | 2 +- src/test/run-fail/borrowck-wg-imm-then-mut.rs | 19 +++++++ src/test/run-fail/borrowck-wg-mut-then-imm.rs | 19 +++++++ src/test/run-pass/regions-mock-trans-impls.rs | 54 ------------------- 5 files changed, 45 insertions(+), 59 deletions(-) create mode 100644 src/test/run-fail/borrowck-wg-imm-then-mut.rs create mode 100644 src/test/run-fail/borrowck-wg-mut-then-imm.rs delete mode 100644 src/test/run-pass/regions-mock-trans-impls.rs diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 911e265e6163c..946bf26fd2713 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -4825,10 +4825,12 @@ pub impl Resolver { expr_loop(_, Some(label)) => { do self.with_label_rib { - let this = &mut *self; - let def_like = dl_def(def_label(expr.id)); - let rib = this.label_ribs[this.label_ribs.len() - 1]; - rib.bindings.insert(label, def_like); + { + let this = &mut *self; + let def_like = dl_def(def_label(expr.id)); + let rib = this.label_ribs[this.label_ribs.len() - 1]; + rib.bindings.insert(label, def_like); + } visit_expr(expr, (), visitor); } diff --git a/src/libsyntax/ext/pipes/liveness.rs b/src/libsyntax/ext/pipes/liveness.rs index bd5353b210031..8799bd064f658 100644 --- a/src/libsyntax/ext/pipes/liveness.rs +++ b/src/libsyntax/ext/pipes/liveness.rs @@ -42,7 +42,7 @@ use ext::pipes::proto::{protocol_}; use std::bitv::Bitv; -pub fn analyze(proto: &mut protocol_, _cx: @ext_ctxt) { +pub fn analyze(proto: @mut protocol_, _cx: @ext_ctxt) { debug!("initializing colive analysis"); let num_states = proto.num_states(); let mut colive = do (copy proto.states).map_to_vec |state| { diff --git a/src/test/run-fail/borrowck-wg-imm-then-mut.rs b/src/test/run-fail/borrowck-wg-imm-then-mut.rs new file mode 100644 index 0000000000000..e2c8a0b549c36 --- /dev/null +++ b/src/test/run-fail/borrowck-wg-imm-then-mut.rs @@ -0,0 +1,19 @@ +// error-pattern:borrowed + +// Test that if you imm borrow then mut borrow it fails. + +fn add1(a:@mut int) +{ + add2(a); // already frozen +} + +fn add2(_:&mut int) +{ +} + +pub fn main() +{ + let a = @mut 3; + let b = &*a; // freezes a + add1(a); +} diff --git a/src/test/run-fail/borrowck-wg-mut-then-imm.rs b/src/test/run-fail/borrowck-wg-mut-then-imm.rs new file mode 100644 index 0000000000000..58b2a1d87beed --- /dev/null +++ b/src/test/run-fail/borrowck-wg-mut-then-imm.rs @@ -0,0 +1,19 @@ +// error-pattern:borrowed + +// Test that if you mut borrow then imm borrow it fails. + +fn add1(a:@mut int) +{ + add2(a); // already frozen +} + +fn add2(_:&int) +{ +} + +pub fn main() +{ + let a = @mut 3; + let b = &mut *a; // freezes a + add1(a); +} diff --git a/src/test/run-pass/regions-mock-trans-impls.rs b/src/test/run-pass/regions-mock-trans-impls.rs deleted file mode 100644 index d54aae7bb6337..0000000000000 --- a/src/test/run-pass/regions-mock-trans-impls.rs +++ /dev/null @@ -1,54 +0,0 @@ -// xfail-fast - -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -extern mod std; -use core::libc; -use core::sys; -use core::cast; -use std::arena::Arena; - -struct Bcx<'self> { - fcx: &'self Fcx<'self> -} - -struct Fcx<'self> { - arena: &'self mut Arena, - ccx: &'self Ccx -} - -struct Ccx { - x: int -} - -fn h<'r>(bcx : &'r mut Bcx<'r>) -> &'r mut Bcx<'r> { - // XXX: Arena has a bad interface here; it should return mutable pointers. - // But this patch is too big to roll that in. - unsafe { - cast::transmute(bcx.fcx.arena.alloc(|| Bcx { fcx: bcx.fcx })) - } -} - -fn g(fcx: &mut Fcx) { - let mut bcx = Bcx { fcx: fcx }; - h(&mut bcx); -} - -fn f(ccx: &mut Ccx) { - let mut a = Arena(); - let mut fcx = Fcx { arena: &mut a, ccx: ccx }; - return g(&mut fcx); -} - -pub fn main() { - let mut ccx = Ccx { x: 0 }; - f(&mut ccx); -} From 4dc62dfcf35bda8c8edf424c6c50f8584f554217 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 May 2013 05:17:36 -0400 Subject: [PATCH 204/215] do not run regionck if there have been type errors --- src/librustc/middle/typeck/check/regionck.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 36606ab7d8990..b4a1cab7b219c 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -138,15 +138,19 @@ pub impl Rcx { pub fn regionck_expr(fcx: @mut FnCtxt, e: @ast::expr) { let rcx = @mut Rcx { fcx: fcx, errors_reported: 0 }; - let v = regionck_visitor(); - (v.visit_expr)(e, rcx, v); + if !fcx.tcx().sess.has_errors() { // regionck assumes typeck succeeded + let v = regionck_visitor(); + (v.visit_expr)(e, rcx, v); + } fcx.infcx().resolve_regions(); } pub fn regionck_fn(fcx: @mut FnCtxt, blk: &ast::blk) { let rcx = @mut Rcx { fcx: fcx, errors_reported: 0 }; - let v = regionck_visitor(); - (v.visit_block)(blk, rcx, v); + if !fcx.tcx().sess.has_errors() { // regionck assumes typeck succeeded + let v = regionck_visitor(); + (v.visit_block)(blk, rcx, v); + } fcx.infcx().resolve_regions(); } From e235f6ca53bac14158a6320aab49f31bd8e8bbe0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 May 2013 05:18:23 -0400 Subject: [PATCH 205/215] remove some unused mut decls and vars --- src/librustc/back/link.rs | 2 +- src/librustc/middle/trans/closure.rs | 4 ---- src/librustc/middle/trans/reachable.rs | 2 +- src/librustc/middle/ty.rs | 2 +- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/librustc/back/link.rs b/src/librustc/back/link.rs index de6469e81807d..c34c7fe303ee2 100644 --- a/src/librustc/back/link.rs +++ b/src/librustc/back/link.rs @@ -788,7 +788,7 @@ pub fn link_binary(sess: Session, }; debug!("output: %s", output.to_str()); - let mut cc_args = link_args(sess, obj_filename, out_filename, lm); + let cc_args = link_args(sess, obj_filename, out_filename, lm); debug!("%s link args: %s", cc_prog, str::connect(cc_args, ~" ")); // We run 'cc' here let prog = run::program_output(cc_prog, cc_args); diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs index 5742463174f65..e0a20f6490715 100644 --- a/src/librustc/middle/trans/closure.rs +++ b/src/librustc/middle/trans/closure.rs @@ -208,7 +208,6 @@ pub fn store_environment(bcx: block, // allocate closure in the heap let Result {bcx: bcx, val: llbox} = allocate_cbox(bcx, sigil, cdata_ty); - let mut temp_cleanups = ~[]; // cbox_ty has the form of a tuple: (a, b, c) we want a ptr to a // tuple. This could be a ptr in uniq or a box or on stack, @@ -244,9 +243,6 @@ pub fn store_environment(bcx: block, } } - for vec::each(temp_cleanups) |cleanup| { - revoke_clean(bcx, *cleanup); - } ClosureResult { llbox: llbox, cdata_ty: cdata_ty, bcx: bcx } } diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs index 4d5a7a72a8d5c..1dd73f76da735 100644 --- a/src/librustc/middle/trans/reachable.rs +++ b/src/librustc/middle/trans/reachable.rs @@ -42,7 +42,7 @@ pub fn find_reachable(crate_mod: &_mod, exp_map2: resolve::ExportMap2, tcx: ty::ctxt, method_map: typeck::method_map) -> map { let mut rmap = HashSet::new(); { - let mut cx = @mut ctx { + let cx = @mut ctx { exp_map2: exp_map2, tcx: tcx, method_map: method_map, diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 03704afdb861f..d3875bad13a7b 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -1950,7 +1950,7 @@ pub fn type_contents(cx: ctxt, ty: t) -> TypeContents { let _i = indenter(); - let mut result = match get(ty).sty { + let result = match get(ty).sty { // Scalar and unique types are sendable, constant, and owned ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) | ty_bare_fn(_) | ty_ptr(_) => { From 02118330084539fdc87533d46aabeef2257ee835 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 6 May 2013 16:10:26 +1000 Subject: [PATCH 206/215] Move FuzzyEq trait into core::cmp and rename it to 'ApproxEq' --- src/libcore/cmp.rs | 7 ++ src/libcore/num/f32.rs | 25 +++++ src/libcore/num/f64.rs | 25 +++++ src/libcore/num/float.rs | 25 +++++ src/libcore/num/num.rs | 5 +- src/libcore/prelude.rs | 2 +- src/libstd/cmp.rs | 102 -------------------- src/libstd/std.rc | 1 - src/test/run-pass/intrinsics-math.rs | 56 +++++------ src/test/run-pass/trait-inheritance-num.rs | 3 +- src/test/run-pass/trait-inheritance-num2.rs | 3 +- 11 files changed, 114 insertions(+), 140 deletions(-) delete mode 100644 src/libstd/cmp.rs diff --git a/src/libcore/cmp.rs b/src/libcore/cmp.rs index b933b60a39f1f..80f1f05961a5d 100644 --- a/src/libcore/cmp.rs +++ b/src/libcore/cmp.rs @@ -66,6 +66,13 @@ totaleq_impl!(uint) totaleq_impl!(char) +/// Trait for testing approximate equality +pub trait ApproxEq { + fn approx_epsilon() -> Eps; + fn approx_eq(&self, other: &Self) -> bool; + fn approx_eq_eps(&self, other: &Self, approx_epsilon: &Eps) -> bool; +} + #[deriving(Clone, Eq)] pub enum Ordering { Less = -1, Equal = 0, Greater = 1 } diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 416ec2069b521..feeb2c3f83605 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -210,6 +210,22 @@ impl Eq for f32 { fn ne(&self, other: &f32) -> bool { (*self) != (*other) } } +#[cfg(notest)] +impl ApproxEq for f32 { + #[inline(always)] + fn approx_epsilon() -> f32 { 1.0e-6 } + + #[inline(always)] + fn approx_eq(&self, other: &f32) -> bool { + self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) + } + + #[inline(always)] + fn approx_eq_eps(&self, other: &f32, approx_epsilon: &f32) -> bool { + (*self - *other).abs() < *approx_epsilon + } +} + #[cfg(notest)] impl Ord for f32 { #[inline(always)] @@ -974,6 +990,15 @@ mod tests { assert!(!NaN.is_negative()); } + #[test] + fn test_approx_eq() { + assert!(1.0f32.approx_eq(&1f32)); + assert!(0.9999999f32.approx_eq(&1f32)); + assert!(1.000001f32.approx_eq_eps(&1f32, &1.0e-5)); + assert!(1.0000001f32.approx_eq_eps(&1f32, &1.0e-6)); + assert!(!1.0000001f32.approx_eq_eps(&1f32, &1.0e-7)); + } + #[test] fn test_primitive() { assert_eq!(Primitive::bits::(), sys::size_of::() * 8); diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 6e09ca61a7d4c..08f9c341188ad 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -233,6 +233,22 @@ impl Eq for f64 { fn ne(&self, other: &f64) -> bool { (*self) != (*other) } } +#[cfg(notest)] +impl ApproxEq for f64 { + #[inline(always)] + fn approx_epsilon() -> f64 { 1.0e-6 } + + #[inline(always)] + fn approx_eq(&self, other: &f64) -> bool { + self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) + } + + #[inline(always)] + fn approx_eq_eps(&self, other: &f64, approx_epsilon: &f64) -> bool { + (*self - *other).abs() < *approx_epsilon + } +} + #[cfg(notest)] impl Ord for f64 { #[inline(always)] @@ -1022,6 +1038,15 @@ mod tests { assert!(!NaN.is_negative()); } + #[test] + fn test_approx_eq() { + assert!(1.0f64.approx_eq(&1f64)); + assert!(0.9999999f64.approx_eq(&1f64)); + assert!(1.000001f64.approx_eq_eps(&1f64, &1.0e-5)); + assert!(1.0000001f64.approx_eq_eps(&1f64, &1.0e-6)); + assert!(!1.0000001f64.approx_eq_eps(&1f64, &1.0e-7)); + } + #[test] fn test_primitive() { assert_eq!(Primitive::bits::(), sys::size_of::() * 8); diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index da9d03f6a7bc3..61dd741b671b5 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -371,6 +371,22 @@ impl Eq for float { fn ne(&self, other: &float) -> bool { (*self) != (*other) } } +#[cfg(notest)] +impl ApproxEq for float { + #[inline(always)] + fn approx_epsilon() -> float { 1.0e-6 } + + #[inline(always)] + fn approx_eq(&self, other: &float) -> bool { + self.approx_eq_eps(other, &ApproxEq::approx_epsilon::()) + } + + #[inline(always)] + fn approx_eq_eps(&self, other: &float, approx_epsilon: &float) -> bool { + (*self - *other).abs() < *approx_epsilon + } +} + #[cfg(notest)] impl Ord for float { #[inline(always)] @@ -985,6 +1001,15 @@ mod tests { assert!(!NaN.is_negative()); } + #[test] + fn test_approx_eq() { + assert!(1.0f.approx_eq(&1f)); + assert!(0.9999999f.approx_eq(&1f)); + assert!(1.000001f.approx_eq_eps(&1f, &1.0e-5)); + assert!(1.0000001f.approx_eq_eps(&1f, &1.0e-6)); + assert!(!1.0000001f.approx_eq_eps(&1f, &1.0e-7)); + } + #[test] fn test_primitive() { assert_eq!(Primitive::bits::(), sys::size_of::() * 8); diff --git a/src/libcore/num/num.rs b/src/libcore/num/num.rs index 1a59a069df7e8..caa14ea802f6c 100644 --- a/src/libcore/num/num.rs +++ b/src/libcore/num/num.rs @@ -9,7 +9,7 @@ // except according to those terms. //! An interface for numeric types -use cmp::{Eq, Ord}; +use cmp::{Eq, ApproxEq, Ord}; use ops::{Add, Sub, Mul, Div, Rem, Neg}; use ops::{Not, BitAnd, BitOr, BitXor, Shl, Shr}; use option::Option; @@ -240,7 +240,8 @@ pub trait Int: Integer /// pub trait Float: Real + Signed - + Primitive { + + Primitive + + ApproxEq { // FIXME (#5527): These should be associated constants fn NaN() -> Self; fn infinity() -> Self; diff --git a/src/libcore/prelude.rs b/src/libcore/prelude.rs index 42401ae5a1fcd..10b36d38d43ae 100644 --- a/src/libcore/prelude.rs +++ b/src/libcore/prelude.rs @@ -28,7 +28,7 @@ pub use io::{print, println}; /* Reexported types and traits */ pub use clone::Clone; -pub use cmp::{Eq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv}; +pub use cmp::{Eq, ApproxEq, Ord, TotalEq, TotalOrd, Ordering, Less, Equal, Greater, Equiv}; pub use container::{Container, Mutable, Map, Set}; pub use hash::Hash; pub use old_iter::{BaseIter, ReverseIter, MutableIter, ExtendedIter, EqIter}; diff --git a/src/libstd/cmp.rs b/src/libstd/cmp.rs deleted file mode 100644 index ea3793c137483..0000000000000 --- a/src/libstd/cmp.rs +++ /dev/null @@ -1,102 +0,0 @@ -// Copyright 2012-2013 The Rust Project Developers. See the -// COPYRIGHT file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Additional general-purpose comparison functionality. - -use core::f32; -use core::f64; -use core::float; - -pub static FUZZY_EPSILON: float = 1.0e-6; - -pub trait FuzzyEq { - fn fuzzy_eq(&self, other: &Self) -> bool; - fn fuzzy_eq_eps(&self, other: &Self, epsilon: &Eps) -> bool; -} - -impl FuzzyEq for float { - fn fuzzy_eq(&self, other: &float) -> bool { - self.fuzzy_eq_eps(other, &FUZZY_EPSILON) - } - - fn fuzzy_eq_eps(&self, other: &float, epsilon: &float) -> bool { - float::abs(*self - *other) < *epsilon - } -} - -impl FuzzyEq for f32 { - fn fuzzy_eq(&self, other: &f32) -> bool { - self.fuzzy_eq_eps(other, &(FUZZY_EPSILON as f32)) - } - - fn fuzzy_eq_eps(&self, other: &f32, epsilon: &f32) -> bool { - f32::abs(*self - *other) < *epsilon - } -} - -impl FuzzyEq for f64 { - fn fuzzy_eq(&self, other: &f64) -> bool { - self.fuzzy_eq_eps(other, &(FUZZY_EPSILON as f64)) - } - - fn fuzzy_eq_eps(&self, other: &f64, epsilon: &f64) -> bool { - f64::abs(*self - *other) < *epsilon - } -} - -#[test] -fn test_fuzzy_equals() { - assert!((&1.0f).fuzzy_eq(&1.0)); - assert!((&1.0f32).fuzzy_eq(&1.0f32)); - assert!((&1.0f64).fuzzy_eq(&1.0f64)); -} - -#[test] -fn test_fuzzy_eq_eps() { - assert!((&1.2f).fuzzy_eq_eps(&0.9, &0.5)); - assert!(!(&1.5f).fuzzy_eq_eps(&0.9, &0.5)); -} - -#[cfg(test)] -mod test_complex{ - use cmp::*; - - struct Complex { r: float, i: float } - - impl FuzzyEq for Complex { - fn fuzzy_eq(&self, other: &Complex) -> bool { - self.fuzzy_eq_eps(other, &FUZZY_EPSILON) - } - - fn fuzzy_eq_eps(&self, other: &Complex, - epsilon: &float) -> bool { - self.r.fuzzy_eq_eps(&other.r, epsilon) && - self.i.fuzzy_eq_eps(&other.i, epsilon) - } - } - - #[test] - fn test_fuzzy_equals() { - let a = Complex {r: 0.9, i: 0.9}; - let b = Complex {r: 0.9, i: 0.9}; - - assert!((a.fuzzy_eq(&b))); - } - - #[test] - fn test_fuzzy_eq_eps() { - let other = Complex {r: 0.9, i: 0.9}; - - assert!((&Complex {r: 0.9, i: 1.2}).fuzzy_eq_eps(&other, &0.5)); - assert!((&Complex {r: 1.2, i: 0.9}).fuzzy_eq_eps(&other, &0.5)); - assert!(!(&Complex {r: 0.9, i: 1.5}).fuzzy_eq_eps(&other, &0.5)); - assert!(!(&Complex {r: 1.5, i: 0.9}).fuzzy_eq_eps(&other, &0.5)); - } -} diff --git a/src/libstd/std.rc b/src/libstd/std.rc index 4f9de29e7262f..32c7c82a3127e 100644 --- a/src/libstd/std.rc +++ b/src/libstd/std.rc @@ -86,7 +86,6 @@ pub mod term; pub mod time; pub mod arena; pub mod par; -pub mod cmp; pub mod base64; pub mod rl; pub mod workcache; diff --git a/src/test/run-pass/intrinsics-math.rs b/src/test/run-pass/intrinsics-math.rs index 6f9179bc89d09..c73df8209e8b9 100644 --- a/src/test/run-pass/intrinsics-math.rs +++ b/src/test/run-pass/intrinsics-math.rs @@ -10,10 +10,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -extern mod std; - -use std::cmp::FuzzyEq; - mod rusti { #[abi = "rust-intrinsic"] pub extern "rust-intrinsic" { @@ -54,44 +50,44 @@ pub fn main() { unsafe { use rusti::*; - assert!((sqrtf32(64f32).fuzzy_eq(&8f32))); - assert!((sqrtf64(64f64).fuzzy_eq(&8f64))); + assert!((sqrtf32(64f32).approx_eq(&8f32))); + assert!((sqrtf64(64f64).approx_eq(&8f64))); - assert!((powif32(25f32, -2i32).fuzzy_eq(&0.0016f32))); - assert!((powif64(23.2f64, 2i32).fuzzy_eq(&538.24f64))); + assert!((powif32(25f32, -2i32).approx_eq(&0.0016f32))); + assert!((powif64(23.2f64, 2i32).approx_eq(&538.24f64))); - assert!((sinf32(0f32).fuzzy_eq(&0f32))); - assert!((sinf64(f64::consts::pi / 2f64).fuzzy_eq(&1f64))); + assert!((sinf32(0f32).approx_eq(&0f32))); + assert!((sinf64(f64::consts::pi / 2f64).approx_eq(&1f64))); - assert!((cosf32(0f32).fuzzy_eq(&1f32))); - assert!((cosf64(f64::consts::pi * 2f64).fuzzy_eq(&1f64))); + assert!((cosf32(0f32).approx_eq(&1f32))); + assert!((cosf64(f64::consts::pi * 2f64).approx_eq(&1f64))); - assert!((powf32(25f32, -2f32).fuzzy_eq(&0.0016f32))); - assert!((powf64(400f64, 0.5f64).fuzzy_eq(&20f64))); + assert!((powf32(25f32, -2f32).approx_eq(&0.0016f32))); + assert!((powf64(400f64, 0.5f64).approx_eq(&20f64))); - assert!((fabsf32(expf32(1f32) - f32::consts::e).fuzzy_eq(&0f32))); - assert!((expf64(1f64).fuzzy_eq(&f64::consts::e))); + assert!((fabsf32(expf32(1f32) - f32::consts::e).approx_eq(&0f32))); + assert!((expf64(1f64).approx_eq(&f64::consts::e))); - assert!((exp2f32(10f32).fuzzy_eq(&1024f32))); - assert!((exp2f64(50f64).fuzzy_eq(&1125899906842624f64))); + assert!((exp2f32(10f32).approx_eq(&1024f32))); + assert!((exp2f64(50f64).approx_eq(&1125899906842624f64))); - assert!((fabsf32(logf32(f32::consts::e) - 1f32).fuzzy_eq(&0f32))); - assert!((logf64(1f64).fuzzy_eq(&0f64))); + assert!((fabsf32(logf32(f32::consts::e) - 1f32).approx_eq(&0f32))); + assert!((logf64(1f64).approx_eq(&0f64))); - assert!((log10f32(10f32).fuzzy_eq(&1f32))); - assert!((log10f64(f64::consts::e).fuzzy_eq(&f64::consts::log10_e))); + assert!((log10f32(10f32).approx_eq(&1f32))); + assert!((log10f64(f64::consts::e).approx_eq(&f64::consts::log10_e))); - assert!((log2f32(8f32).fuzzy_eq(&3f32))); - assert!((log2f64(f64::consts::e).fuzzy_eq(&f64::consts::log2_e))); + assert!((log2f32(8f32).approx_eq(&3f32))); + assert!((log2f64(f64::consts::e).approx_eq(&f64::consts::log2_e))); - assert!((fmaf32(1.0f32, 2.0f32, 5.0f32).fuzzy_eq(&7.0f32))); - assert!((fmaf64(0.0f64, -2.0f64, f64::consts::e).fuzzy_eq(&f64::consts::e))); + assert!((fmaf32(1.0f32, 2.0f32, 5.0f32).approx_eq(&7.0f32))); + assert!((fmaf64(0.0f64, -2.0f64, f64::consts::e).approx_eq(&f64::consts::e))); - assert!((fabsf32(-1.0f32).fuzzy_eq(&1.0f32))); - assert!((fabsf64(34.2f64).fuzzy_eq(&34.2f64))); + assert!((fabsf32(-1.0f32).approx_eq(&1.0f32))); + assert!((fabsf64(34.2f64).approx_eq(&34.2f64))); - assert!((floorf32(3.8f32).fuzzy_eq(&3.0f32))); - assert!((floorf64(-1.1f64).fuzzy_eq(&-2.0f64))); + assert!((floorf32(3.8f32).approx_eq(&3.0f32))); + assert!((floorf64(-1.1f64).approx_eq(&-2.0f64))); // Causes linker error // undefined reference to llvm.ceil.f32/64 diff --git a/src/test/run-pass/trait-inheritance-num.rs b/src/test/run-pass/trait-inheritance-num.rs index 0fb2a6b2e724b..5179d13813cea 100644 --- a/src/test/run-pass/trait-inheritance-num.rs +++ b/src/test/run-pass/trait-inheritance-num.rs @@ -14,11 +14,10 @@ extern mod std; use core::cmp::{Eq, Ord}; use core::num::NumCast::from; -use std::cmp::FuzzyEq; pub trait NumExt: Num + NumCast + Eq + Ord {} -pub trait FloatExt: NumExt + FuzzyEq {} +pub trait FloatExt: NumExt + ApproxEq {} fn greater_than_one(n: &T) -> bool { *n > from(1) } fn greater_than_one_float(n: &T) -> bool { *n > from(1) } diff --git a/src/test/run-pass/trait-inheritance-num2.rs b/src/test/run-pass/trait-inheritance-num2.rs index b40f647814f0c..f7edd2855a4cd 100644 --- a/src/test/run-pass/trait-inheritance-num2.rs +++ b/src/test/run-pass/trait-inheritance-num2.rs @@ -16,7 +16,6 @@ extern mod std; use core::cmp::{Eq, Ord}; use core::num::NumCast::from; -use std::cmp::FuzzyEq; pub trait TypeExt {} @@ -94,7 +93,7 @@ impl IntegerExt for i64 {} impl IntegerExt for int {} -pub trait FloatExt: NumExt + FuzzyEq {} +pub trait FloatExt: NumExt + ApproxEq {} impl FloatExt for f32 {} impl FloatExt for f64 {} From 0e2242f6d62d6d49bf8a2d1860a41273c1fdfa0d Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Mon, 6 May 2013 21:51:48 +1000 Subject: [PATCH 207/215] Add assert_approx_eq! macro --- src/libcore/num/f32.rs | 139 ++++++++--------- src/libcore/num/f64.rs | 140 ++++++++---------- src/libcore/num/float.rs | 139 ++++++++--------- src/libsyntax/ext/expand.rs | 36 +++++ .../assert-approx-eq-eps-macro-fail.rs | 14 ++ .../run-fail/assert-approx-eq-macro-fail.rs | 14 ++ .../assert-approx-eq-macro-success.rs | 16 ++ 7 files changed, 275 insertions(+), 223 deletions(-) create mode 100644 src/test/run-fail/assert-approx-eq-eps-macro-fail.rs create mode 100644 src/test/run-fail/assert-approx-eq-macro-fail.rs create mode 100644 src/test/run-pass/assert-approx-eq-macro-success.rs diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index feeb2c3f83605..7c13f136a80f2 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -826,15 +826,6 @@ mod tests { use super::*; use prelude::*; - macro_rules! assert_fuzzy_eq( - ($a:expr, $b:expr) => ({ - let a = $a, b = $b; - if !((a - b).abs() < 1.0e-6) { - fail!(fmt!("The values were not approximately equal. Found: %? and %?", a, b)); - } - }) - ) - #[test] fn test_num() { num::test_num(10f32, 2f32); @@ -864,91 +855,91 @@ mod tests { #[test] fn test_floor() { - assert_fuzzy_eq!(1.0f32.floor(), 1.0f32); - assert_fuzzy_eq!(1.3f32.floor(), 1.0f32); - assert_fuzzy_eq!(1.5f32.floor(), 1.0f32); - assert_fuzzy_eq!(1.7f32.floor(), 1.0f32); - assert_fuzzy_eq!(0.0f32.floor(), 0.0f32); - assert_fuzzy_eq!((-0.0f32).floor(), -0.0f32); - assert_fuzzy_eq!((-1.0f32).floor(), -1.0f32); - assert_fuzzy_eq!((-1.3f32).floor(), -2.0f32); - assert_fuzzy_eq!((-1.5f32).floor(), -2.0f32); - assert_fuzzy_eq!((-1.7f32).floor(), -2.0f32); + assert_approx_eq!(1.0f32.floor(), 1.0f32); + assert_approx_eq!(1.3f32.floor(), 1.0f32); + assert_approx_eq!(1.5f32.floor(), 1.0f32); + assert_approx_eq!(1.7f32.floor(), 1.0f32); + assert_approx_eq!(0.0f32.floor(), 0.0f32); + assert_approx_eq!((-0.0f32).floor(), -0.0f32); + assert_approx_eq!((-1.0f32).floor(), -1.0f32); + assert_approx_eq!((-1.3f32).floor(), -2.0f32); + assert_approx_eq!((-1.5f32).floor(), -2.0f32); + assert_approx_eq!((-1.7f32).floor(), -2.0f32); } #[test] fn test_ceil() { - assert_fuzzy_eq!(1.0f32.ceil(), 1.0f32); - assert_fuzzy_eq!(1.3f32.ceil(), 2.0f32); - assert_fuzzy_eq!(1.5f32.ceil(), 2.0f32); - assert_fuzzy_eq!(1.7f32.ceil(), 2.0f32); - assert_fuzzy_eq!(0.0f32.ceil(), 0.0f32); - assert_fuzzy_eq!((-0.0f32).ceil(), -0.0f32); - assert_fuzzy_eq!((-1.0f32).ceil(), -1.0f32); - assert_fuzzy_eq!((-1.3f32).ceil(), -1.0f32); - assert_fuzzy_eq!((-1.5f32).ceil(), -1.0f32); - assert_fuzzy_eq!((-1.7f32).ceil(), -1.0f32); + assert_approx_eq!(1.0f32.ceil(), 1.0f32); + assert_approx_eq!(1.3f32.ceil(), 2.0f32); + assert_approx_eq!(1.5f32.ceil(), 2.0f32); + assert_approx_eq!(1.7f32.ceil(), 2.0f32); + assert_approx_eq!(0.0f32.ceil(), 0.0f32); + assert_approx_eq!((-0.0f32).ceil(), -0.0f32); + assert_approx_eq!((-1.0f32).ceil(), -1.0f32); + assert_approx_eq!((-1.3f32).ceil(), -1.0f32); + assert_approx_eq!((-1.5f32).ceil(), -1.0f32); + assert_approx_eq!((-1.7f32).ceil(), -1.0f32); } #[test] fn test_round() { - assert_fuzzy_eq!(1.0f32.round(), 1.0f32); - assert_fuzzy_eq!(1.3f32.round(), 1.0f32); - assert_fuzzy_eq!(1.5f32.round(), 2.0f32); - assert_fuzzy_eq!(1.7f32.round(), 2.0f32); - assert_fuzzy_eq!(0.0f32.round(), 0.0f32); - assert_fuzzy_eq!((-0.0f32).round(), -0.0f32); - assert_fuzzy_eq!((-1.0f32).round(), -1.0f32); - assert_fuzzy_eq!((-1.3f32).round(), -1.0f32); - assert_fuzzy_eq!((-1.5f32).round(), -2.0f32); - assert_fuzzy_eq!((-1.7f32).round(), -2.0f32); + assert_approx_eq!(1.0f32.round(), 1.0f32); + assert_approx_eq!(1.3f32.round(), 1.0f32); + assert_approx_eq!(1.5f32.round(), 2.0f32); + assert_approx_eq!(1.7f32.round(), 2.0f32); + assert_approx_eq!(0.0f32.round(), 0.0f32); + assert_approx_eq!((-0.0f32).round(), -0.0f32); + assert_approx_eq!((-1.0f32).round(), -1.0f32); + assert_approx_eq!((-1.3f32).round(), -1.0f32); + assert_approx_eq!((-1.5f32).round(), -2.0f32); + assert_approx_eq!((-1.7f32).round(), -2.0f32); } #[test] fn test_trunc() { - assert_fuzzy_eq!(1.0f32.trunc(), 1.0f32); - assert_fuzzy_eq!(1.3f32.trunc(), 1.0f32); - assert_fuzzy_eq!(1.5f32.trunc(), 1.0f32); - assert_fuzzy_eq!(1.7f32.trunc(), 1.0f32); - assert_fuzzy_eq!(0.0f32.trunc(), 0.0f32); - assert_fuzzy_eq!((-0.0f32).trunc(), -0.0f32); - assert_fuzzy_eq!((-1.0f32).trunc(), -1.0f32); - assert_fuzzy_eq!((-1.3f32).trunc(), -1.0f32); - assert_fuzzy_eq!((-1.5f32).trunc(), -1.0f32); - assert_fuzzy_eq!((-1.7f32).trunc(), -1.0f32); + assert_approx_eq!(1.0f32.trunc(), 1.0f32); + assert_approx_eq!(1.3f32.trunc(), 1.0f32); + assert_approx_eq!(1.5f32.trunc(), 1.0f32); + assert_approx_eq!(1.7f32.trunc(), 1.0f32); + assert_approx_eq!(0.0f32.trunc(), 0.0f32); + assert_approx_eq!((-0.0f32).trunc(), -0.0f32); + assert_approx_eq!((-1.0f32).trunc(), -1.0f32); + assert_approx_eq!((-1.3f32).trunc(), -1.0f32); + assert_approx_eq!((-1.5f32).trunc(), -1.0f32); + assert_approx_eq!((-1.7f32).trunc(), -1.0f32); } #[test] fn test_fract() { - assert_fuzzy_eq!(1.0f32.fract(), 0.0f32); - assert_fuzzy_eq!(1.3f32.fract(), 0.3f32); - assert_fuzzy_eq!(1.5f32.fract(), 0.5f32); - assert_fuzzy_eq!(1.7f32.fract(), 0.7f32); - assert_fuzzy_eq!(0.0f32.fract(), 0.0f32); - assert_fuzzy_eq!((-0.0f32).fract(), -0.0f32); - assert_fuzzy_eq!((-1.0f32).fract(), -0.0f32); - assert_fuzzy_eq!((-1.3f32).fract(), -0.3f32); - assert_fuzzy_eq!((-1.5f32).fract(), -0.5f32); - assert_fuzzy_eq!((-1.7f32).fract(), -0.7f32); + assert_approx_eq!(1.0f32.fract(), 0.0f32); + assert_approx_eq!(1.3f32.fract(), 0.3f32); + assert_approx_eq!(1.5f32.fract(), 0.5f32); + assert_approx_eq!(1.7f32.fract(), 0.7f32); + assert_approx_eq!(0.0f32.fract(), 0.0f32); + assert_approx_eq!((-0.0f32).fract(), -0.0f32); + assert_approx_eq!((-1.0f32).fract(), -0.0f32); + assert_approx_eq!((-1.3f32).fract(), -0.3f32); + assert_approx_eq!((-1.5f32).fract(), -0.5f32); + assert_approx_eq!((-1.7f32).fract(), -0.7f32); } #[test] fn test_real_consts() { - assert_fuzzy_eq!(Real::two_pi::(), 2f32 * Real::pi::()); - assert_fuzzy_eq!(Real::frac_pi_2::(), Real::pi::() / 2f32); - assert_fuzzy_eq!(Real::frac_pi_3::(), Real::pi::() / 3f32); - assert_fuzzy_eq!(Real::frac_pi_4::(), Real::pi::() / 4f32); - assert_fuzzy_eq!(Real::frac_pi_6::(), Real::pi::() / 6f32); - assert_fuzzy_eq!(Real::frac_pi_8::(), Real::pi::() / 8f32); - assert_fuzzy_eq!(Real::frac_1_pi::(), 1f32 / Real::pi::()); - assert_fuzzy_eq!(Real::frac_2_pi::(), 2f32 / Real::pi::()); - assert_fuzzy_eq!(Real::frac_2_sqrtpi::(), 2f32 / Real::pi::().sqrt()); - assert_fuzzy_eq!(Real::sqrt2::(), 2f32.sqrt()); - assert_fuzzy_eq!(Real::frac_1_sqrt2::(), 1f32 / 2f32.sqrt()); - assert_fuzzy_eq!(Real::log2_e::(), Real::e::().log2()); - assert_fuzzy_eq!(Real::log10_e::(), Real::e::().log10()); - assert_fuzzy_eq!(Real::log_2::(), 2f32.log()); - assert_fuzzy_eq!(Real::log_10::(), 10f32.log()); + assert_approx_eq!(Real::two_pi::(), 2f32 * Real::pi::()); + assert_approx_eq!(Real::frac_pi_2::(), Real::pi::() / 2f32); + assert_approx_eq!(Real::frac_pi_3::(), Real::pi::() / 3f32); + assert_approx_eq!(Real::frac_pi_4::(), Real::pi::() / 4f32); + assert_approx_eq!(Real::frac_pi_6::(), Real::pi::() / 6f32); + assert_approx_eq!(Real::frac_pi_8::(), Real::pi::() / 8f32); + assert_approx_eq!(Real::frac_1_pi::(), 1f32 / Real::pi::()); + assert_approx_eq!(Real::frac_2_pi::(), 2f32 / Real::pi::()); + assert_approx_eq!(Real::frac_2_sqrtpi::(), 2f32 / Real::pi::().sqrt()); + assert_approx_eq!(Real::sqrt2::(), 2f32.sqrt()); + assert_approx_eq!(Real::frac_1_sqrt2::(), 1f32 / 2f32.sqrt()); + assert_approx_eq!(Real::log2_e::(), Real::e::().log2()); + assert_approx_eq!(Real::log10_e::(), Real::e::().log10()); + assert_approx_eq!(Real::log_2::(), 2f32.log()); + assert_approx_eq!(Real::log_10::(), 10f32.log()); } #[test] diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 08f9c341188ad..e5f10c23ecd87 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -869,16 +869,6 @@ mod tests { use super::*; use prelude::*; - macro_rules! assert_fuzzy_eq( - ($a:expr, $b:expr) => ({ - let a = $a, b = $b; - if !((a - b).abs() < 1.0e-6) { - fail!(fmt!("The values were not approximately equal. \ - Found: %? and expected %?", a, b)); - } - }) - ) - #[test] fn test_num() { num::test_num(10f64, 2f64); @@ -912,91 +902,91 @@ mod tests { #[test] fn test_floor() { - assert_fuzzy_eq!(1.0f64.floor(), 1.0f64); - assert_fuzzy_eq!(1.3f64.floor(), 1.0f64); - assert_fuzzy_eq!(1.5f64.floor(), 1.0f64); - assert_fuzzy_eq!(1.7f64.floor(), 1.0f64); - assert_fuzzy_eq!(0.0f64.floor(), 0.0f64); - assert_fuzzy_eq!((-0.0f64).floor(), -0.0f64); - assert_fuzzy_eq!((-1.0f64).floor(), -1.0f64); - assert_fuzzy_eq!((-1.3f64).floor(), -2.0f64); - assert_fuzzy_eq!((-1.5f64).floor(), -2.0f64); - assert_fuzzy_eq!((-1.7f64).floor(), -2.0f64); + assert_approx_eq!(1.0f64.floor(), 1.0f64); + assert_approx_eq!(1.3f64.floor(), 1.0f64); + assert_approx_eq!(1.5f64.floor(), 1.0f64); + assert_approx_eq!(1.7f64.floor(), 1.0f64); + assert_approx_eq!(0.0f64.floor(), 0.0f64); + assert_approx_eq!((-0.0f64).floor(), -0.0f64); + assert_approx_eq!((-1.0f64).floor(), -1.0f64); + assert_approx_eq!((-1.3f64).floor(), -2.0f64); + assert_approx_eq!((-1.5f64).floor(), -2.0f64); + assert_approx_eq!((-1.7f64).floor(), -2.0f64); } #[test] fn test_ceil() { - assert_fuzzy_eq!(1.0f64.ceil(), 1.0f64); - assert_fuzzy_eq!(1.3f64.ceil(), 2.0f64); - assert_fuzzy_eq!(1.5f64.ceil(), 2.0f64); - assert_fuzzy_eq!(1.7f64.ceil(), 2.0f64); - assert_fuzzy_eq!(0.0f64.ceil(), 0.0f64); - assert_fuzzy_eq!((-0.0f64).ceil(), -0.0f64); - assert_fuzzy_eq!((-1.0f64).ceil(), -1.0f64); - assert_fuzzy_eq!((-1.3f64).ceil(), -1.0f64); - assert_fuzzy_eq!((-1.5f64).ceil(), -1.0f64); - assert_fuzzy_eq!((-1.7f64).ceil(), -1.0f64); + assert_approx_eq!(1.0f64.ceil(), 1.0f64); + assert_approx_eq!(1.3f64.ceil(), 2.0f64); + assert_approx_eq!(1.5f64.ceil(), 2.0f64); + assert_approx_eq!(1.7f64.ceil(), 2.0f64); + assert_approx_eq!(0.0f64.ceil(), 0.0f64); + assert_approx_eq!((-0.0f64).ceil(), -0.0f64); + assert_approx_eq!((-1.0f64).ceil(), -1.0f64); + assert_approx_eq!((-1.3f64).ceil(), -1.0f64); + assert_approx_eq!((-1.5f64).ceil(), -1.0f64); + assert_approx_eq!((-1.7f64).ceil(), -1.0f64); } #[test] fn test_round() { - assert_fuzzy_eq!(1.0f64.round(), 1.0f64); - assert_fuzzy_eq!(1.3f64.round(), 1.0f64); - assert_fuzzy_eq!(1.5f64.round(), 2.0f64); - assert_fuzzy_eq!(1.7f64.round(), 2.0f64); - assert_fuzzy_eq!(0.0f64.round(), 0.0f64); - assert_fuzzy_eq!((-0.0f64).round(), -0.0f64); - assert_fuzzy_eq!((-1.0f64).round(), -1.0f64); - assert_fuzzy_eq!((-1.3f64).round(), -1.0f64); - assert_fuzzy_eq!((-1.5f64).round(), -2.0f64); - assert_fuzzy_eq!((-1.7f64).round(), -2.0f64); + assert_approx_eq!(1.0f64.round(), 1.0f64); + assert_approx_eq!(1.3f64.round(), 1.0f64); + assert_approx_eq!(1.5f64.round(), 2.0f64); + assert_approx_eq!(1.7f64.round(), 2.0f64); + assert_approx_eq!(0.0f64.round(), 0.0f64); + assert_approx_eq!((-0.0f64).round(), -0.0f64); + assert_approx_eq!((-1.0f64).round(), -1.0f64); + assert_approx_eq!((-1.3f64).round(), -1.0f64); + assert_approx_eq!((-1.5f64).round(), -2.0f64); + assert_approx_eq!((-1.7f64).round(), -2.0f64); } #[test] fn test_trunc() { - assert_fuzzy_eq!(1.0f64.trunc(), 1.0f64); - assert_fuzzy_eq!(1.3f64.trunc(), 1.0f64); - assert_fuzzy_eq!(1.5f64.trunc(), 1.0f64); - assert_fuzzy_eq!(1.7f64.trunc(), 1.0f64); - assert_fuzzy_eq!(0.0f64.trunc(), 0.0f64); - assert_fuzzy_eq!((-0.0f64).trunc(), -0.0f64); - assert_fuzzy_eq!((-1.0f64).trunc(), -1.0f64); - assert_fuzzy_eq!((-1.3f64).trunc(), -1.0f64); - assert_fuzzy_eq!((-1.5f64).trunc(), -1.0f64); - assert_fuzzy_eq!((-1.7f64).trunc(), -1.0f64); + assert_approx_eq!(1.0f64.trunc(), 1.0f64); + assert_approx_eq!(1.3f64.trunc(), 1.0f64); + assert_approx_eq!(1.5f64.trunc(), 1.0f64); + assert_approx_eq!(1.7f64.trunc(), 1.0f64); + assert_approx_eq!(0.0f64.trunc(), 0.0f64); + assert_approx_eq!((-0.0f64).trunc(), -0.0f64); + assert_approx_eq!((-1.0f64).trunc(), -1.0f64); + assert_approx_eq!((-1.3f64).trunc(), -1.0f64); + assert_approx_eq!((-1.5f64).trunc(), -1.0f64); + assert_approx_eq!((-1.7f64).trunc(), -1.0f64); } #[test] fn test_fract() { - assert_fuzzy_eq!(1.0f64.fract(), 0.0f64); - assert_fuzzy_eq!(1.3f64.fract(), 0.3f64); - assert_fuzzy_eq!(1.5f64.fract(), 0.5f64); - assert_fuzzy_eq!(1.7f64.fract(), 0.7f64); - assert_fuzzy_eq!(0.0f64.fract(), 0.0f64); - assert_fuzzy_eq!((-0.0f64).fract(), -0.0f64); - assert_fuzzy_eq!((-1.0f64).fract(), -0.0f64); - assert_fuzzy_eq!((-1.3f64).fract(), -0.3f64); - assert_fuzzy_eq!((-1.5f64).fract(), -0.5f64); - assert_fuzzy_eq!((-1.7f64).fract(), -0.7f64); + assert_approx_eq!(1.0f64.fract(), 0.0f64); + assert_approx_eq!(1.3f64.fract(), 0.3f64); + assert_approx_eq!(1.5f64.fract(), 0.5f64); + assert_approx_eq!(1.7f64.fract(), 0.7f64); + assert_approx_eq!(0.0f64.fract(), 0.0f64); + assert_approx_eq!((-0.0f64).fract(), -0.0f64); + assert_approx_eq!((-1.0f64).fract(), -0.0f64); + assert_approx_eq!((-1.3f64).fract(), -0.3f64); + assert_approx_eq!((-1.5f64).fract(), -0.5f64); + assert_approx_eq!((-1.7f64).fract(), -0.7f64); } #[test] fn test_real_consts() { - assert_fuzzy_eq!(Real::two_pi::(), 2.0 * Real::pi::()); - assert_fuzzy_eq!(Real::frac_pi_2::(), Real::pi::() / 2f64); - assert_fuzzy_eq!(Real::frac_pi_3::(), Real::pi::() / 3f64); - assert_fuzzy_eq!(Real::frac_pi_4::(), Real::pi::() / 4f64); - assert_fuzzy_eq!(Real::frac_pi_6::(), Real::pi::() / 6f64); - assert_fuzzy_eq!(Real::frac_pi_8::(), Real::pi::() / 8f64); - assert_fuzzy_eq!(Real::frac_1_pi::(), 1f64 / Real::pi::()); - assert_fuzzy_eq!(Real::frac_2_pi::(), 2f64 / Real::pi::()); - assert_fuzzy_eq!(Real::frac_2_sqrtpi::(), 2f64 / Real::pi::().sqrt()); - assert_fuzzy_eq!(Real::sqrt2::(), 2f64.sqrt()); - assert_fuzzy_eq!(Real::frac_1_sqrt2::(), 1f64 / 2f64.sqrt()); - assert_fuzzy_eq!(Real::log2_e::(), Real::e::().log2()); - assert_fuzzy_eq!(Real::log10_e::(), Real::e::().log10()); - assert_fuzzy_eq!(Real::log_2::(), 2f64.log()); - assert_fuzzy_eq!(Real::log_10::(), 10f64.log()); + assert_approx_eq!(Real::two_pi::(), 2.0 * Real::pi::()); + assert_approx_eq!(Real::frac_pi_2::(), Real::pi::() / 2f64); + assert_approx_eq!(Real::frac_pi_3::(), Real::pi::() / 3f64); + assert_approx_eq!(Real::frac_pi_4::(), Real::pi::() / 4f64); + assert_approx_eq!(Real::frac_pi_6::(), Real::pi::() / 6f64); + assert_approx_eq!(Real::frac_pi_8::(), Real::pi::() / 8f64); + assert_approx_eq!(Real::frac_1_pi::(), 1f64 / Real::pi::()); + assert_approx_eq!(Real::frac_2_pi::(), 2f64 / Real::pi::()); + assert_approx_eq!(Real::frac_2_sqrtpi::(), 2f64 / Real::pi::().sqrt()); + assert_approx_eq!(Real::sqrt2::(), 2f64.sqrt()); + assert_approx_eq!(Real::frac_1_sqrt2::(), 1f64 / 2f64.sqrt()); + assert_approx_eq!(Real::log2_e::(), Real::e::().log2()); + assert_approx_eq!(Real::log10_e::(), Real::e::().log10()); + assert_approx_eq!(Real::log_2::(), 2f64.log()); + assert_approx_eq!(Real::log_10::(), 10f64.log()); } #[test] diff --git a/src/libcore/num/float.rs b/src/libcore/num/float.rs index 61dd741b671b5..a548165326396 100644 --- a/src/libcore/num/float.rs +++ b/src/libcore/num/float.rs @@ -837,15 +837,6 @@ mod tests { use super::*; use prelude::*; - macro_rules! assert_fuzzy_eq( - ($a:expr, $b:expr) => ({ - let a = $a, b = $b; - if !((a - b).abs() < 1.0e-6) { - fail!(fmt!("The values were not approximately equal. Found: %? and %?", a, b)); - } - }) - ) - #[test] fn test_num() { num::test_num(10f, 2f); @@ -875,91 +866,91 @@ mod tests { #[test] fn test_floor() { - assert_fuzzy_eq!(1.0f.floor(), 1.0f); - assert_fuzzy_eq!(1.3f.floor(), 1.0f); - assert_fuzzy_eq!(1.5f.floor(), 1.0f); - assert_fuzzy_eq!(1.7f.floor(), 1.0f); - assert_fuzzy_eq!(0.0f.floor(), 0.0f); - assert_fuzzy_eq!((-0.0f).floor(), -0.0f); - assert_fuzzy_eq!((-1.0f).floor(), -1.0f); - assert_fuzzy_eq!((-1.3f).floor(), -2.0f); - assert_fuzzy_eq!((-1.5f).floor(), -2.0f); - assert_fuzzy_eq!((-1.7f).floor(), -2.0f); + assert_approx_eq!(1.0f.floor(), 1.0f); + assert_approx_eq!(1.3f.floor(), 1.0f); + assert_approx_eq!(1.5f.floor(), 1.0f); + assert_approx_eq!(1.7f.floor(), 1.0f); + assert_approx_eq!(0.0f.floor(), 0.0f); + assert_approx_eq!((-0.0f).floor(), -0.0f); + assert_approx_eq!((-1.0f).floor(), -1.0f); + assert_approx_eq!((-1.3f).floor(), -2.0f); + assert_approx_eq!((-1.5f).floor(), -2.0f); + assert_approx_eq!((-1.7f).floor(), -2.0f); } #[test] fn test_ceil() { - assert_fuzzy_eq!(1.0f.ceil(), 1.0f); - assert_fuzzy_eq!(1.3f.ceil(), 2.0f); - assert_fuzzy_eq!(1.5f.ceil(), 2.0f); - assert_fuzzy_eq!(1.7f.ceil(), 2.0f); - assert_fuzzy_eq!(0.0f.ceil(), 0.0f); - assert_fuzzy_eq!((-0.0f).ceil(), -0.0f); - assert_fuzzy_eq!((-1.0f).ceil(), -1.0f); - assert_fuzzy_eq!((-1.3f).ceil(), -1.0f); - assert_fuzzy_eq!((-1.5f).ceil(), -1.0f); - assert_fuzzy_eq!((-1.7f).ceil(), -1.0f); + assert_approx_eq!(1.0f.ceil(), 1.0f); + assert_approx_eq!(1.3f.ceil(), 2.0f); + assert_approx_eq!(1.5f.ceil(), 2.0f); + assert_approx_eq!(1.7f.ceil(), 2.0f); + assert_approx_eq!(0.0f.ceil(), 0.0f); + assert_approx_eq!((-0.0f).ceil(), -0.0f); + assert_approx_eq!((-1.0f).ceil(), -1.0f); + assert_approx_eq!((-1.3f).ceil(), -1.0f); + assert_approx_eq!((-1.5f).ceil(), -1.0f); + assert_approx_eq!((-1.7f).ceil(), -1.0f); } #[test] fn test_round() { - assert_fuzzy_eq!(1.0f.round(), 1.0f); - assert_fuzzy_eq!(1.3f.round(), 1.0f); - assert_fuzzy_eq!(1.5f.round(), 2.0f); - assert_fuzzy_eq!(1.7f.round(), 2.0f); - assert_fuzzy_eq!(0.0f.round(), 0.0f); - assert_fuzzy_eq!((-0.0f).round(), -0.0f); - assert_fuzzy_eq!((-1.0f).round(), -1.0f); - assert_fuzzy_eq!((-1.3f).round(), -1.0f); - assert_fuzzy_eq!((-1.5f).round(), -2.0f); - assert_fuzzy_eq!((-1.7f).round(), -2.0f); + assert_approx_eq!(1.0f.round(), 1.0f); + assert_approx_eq!(1.3f.round(), 1.0f); + assert_approx_eq!(1.5f.round(), 2.0f); + assert_approx_eq!(1.7f.round(), 2.0f); + assert_approx_eq!(0.0f.round(), 0.0f); + assert_approx_eq!((-0.0f).round(), -0.0f); + assert_approx_eq!((-1.0f).round(), -1.0f); + assert_approx_eq!((-1.3f).round(), -1.0f); + assert_approx_eq!((-1.5f).round(), -2.0f); + assert_approx_eq!((-1.7f).round(), -2.0f); } #[test] fn test_trunc() { - assert_fuzzy_eq!(1.0f.trunc(), 1.0f); - assert_fuzzy_eq!(1.3f.trunc(), 1.0f); - assert_fuzzy_eq!(1.5f.trunc(), 1.0f); - assert_fuzzy_eq!(1.7f.trunc(), 1.0f); - assert_fuzzy_eq!(0.0f.trunc(), 0.0f); - assert_fuzzy_eq!((-0.0f).trunc(), -0.0f); - assert_fuzzy_eq!((-1.0f).trunc(), -1.0f); - assert_fuzzy_eq!((-1.3f).trunc(), -1.0f); - assert_fuzzy_eq!((-1.5f).trunc(), -1.0f); - assert_fuzzy_eq!((-1.7f).trunc(), -1.0f); + assert_approx_eq!(1.0f.trunc(), 1.0f); + assert_approx_eq!(1.3f.trunc(), 1.0f); + assert_approx_eq!(1.5f.trunc(), 1.0f); + assert_approx_eq!(1.7f.trunc(), 1.0f); + assert_approx_eq!(0.0f.trunc(), 0.0f); + assert_approx_eq!((-0.0f).trunc(), -0.0f); + assert_approx_eq!((-1.0f).trunc(), -1.0f); + assert_approx_eq!((-1.3f).trunc(), -1.0f); + assert_approx_eq!((-1.5f).trunc(), -1.0f); + assert_approx_eq!((-1.7f).trunc(), -1.0f); } #[test] fn test_fract() { - assert_fuzzy_eq!(1.0f.fract(), 0.0f); - assert_fuzzy_eq!(1.3f.fract(), 0.3f); - assert_fuzzy_eq!(1.5f.fract(), 0.5f); - assert_fuzzy_eq!(1.7f.fract(), 0.7f); - assert_fuzzy_eq!(0.0f.fract(), 0.0f); - assert_fuzzy_eq!((-0.0f).fract(), -0.0f); - assert_fuzzy_eq!((-1.0f).fract(), -0.0f); - assert_fuzzy_eq!((-1.3f).fract(), -0.3f); - assert_fuzzy_eq!((-1.5f).fract(), -0.5f); - assert_fuzzy_eq!((-1.7f).fract(), -0.7f); + assert_approx_eq!(1.0f.fract(), 0.0f); + assert_approx_eq!(1.3f.fract(), 0.3f); + assert_approx_eq!(1.5f.fract(), 0.5f); + assert_approx_eq!(1.7f.fract(), 0.7f); + assert_approx_eq!(0.0f.fract(), 0.0f); + assert_approx_eq!((-0.0f).fract(), -0.0f); + assert_approx_eq!((-1.0f).fract(), -0.0f); + assert_approx_eq!((-1.3f).fract(), -0.3f); + assert_approx_eq!((-1.5f).fract(), -0.5f); + assert_approx_eq!((-1.7f).fract(), -0.7f); } #[test] fn test_real_consts() { - assert_fuzzy_eq!(Real::two_pi::(), 2f * Real::pi::()); - assert_fuzzy_eq!(Real::frac_pi_2::(), Real::pi::() / 2f); - assert_fuzzy_eq!(Real::frac_pi_3::(), Real::pi::() / 3f); - assert_fuzzy_eq!(Real::frac_pi_4::(), Real::pi::() / 4f); - assert_fuzzy_eq!(Real::frac_pi_6::(), Real::pi::() / 6f); - assert_fuzzy_eq!(Real::frac_pi_8::(), Real::pi::() / 8f); - assert_fuzzy_eq!(Real::frac_1_pi::(), 1f / Real::pi::()); - assert_fuzzy_eq!(Real::frac_2_pi::(), 2f / Real::pi::()); - assert_fuzzy_eq!(Real::frac_2_sqrtpi::(), 2f / Real::pi::().sqrt()); - assert_fuzzy_eq!(Real::sqrt2::(), 2f.sqrt()); - assert_fuzzy_eq!(Real::frac_1_sqrt2::(), 1f / 2f.sqrt()); - assert_fuzzy_eq!(Real::log2_e::(), Real::e::().log2()); - assert_fuzzy_eq!(Real::log10_e::(), Real::e::().log10()); - assert_fuzzy_eq!(Real::log_2::(), 2f.log()); - assert_fuzzy_eq!(Real::log_10::(), 10f.log()); + assert_approx_eq!(Real::two_pi::(), 2f * Real::pi::()); + assert_approx_eq!(Real::frac_pi_2::(), Real::pi::() / 2f); + assert_approx_eq!(Real::frac_pi_3::(), Real::pi::() / 3f); + assert_approx_eq!(Real::frac_pi_4::(), Real::pi::() / 4f); + assert_approx_eq!(Real::frac_pi_6::(), Real::pi::() / 6f); + assert_approx_eq!(Real::frac_pi_8::(), Real::pi::() / 8f); + assert_approx_eq!(Real::frac_1_pi::(), 1f / Real::pi::()); + assert_approx_eq!(Real::frac_2_pi::(), 2f / Real::pi::()); + assert_approx_eq!(Real::frac_2_sqrtpi::(), 2f / Real::pi::().sqrt()); + assert_approx_eq!(Real::sqrt2::(), 2f.sqrt()); + assert_approx_eq!(Real::frac_1_sqrt2::(), 1f / 2f.sqrt()); + assert_approx_eq!(Real::log2_e::(), Real::e::().log2()); + assert_approx_eq!(Real::log10_e::(), Real::e::().log10()); + assert_approx_eq!(Real::log_2::(), 2f.log()); + assert_approx_eq!(Real::log_10::(), 10f.log()); } #[test] diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 02721a02fbd0c..9363807ab9b9e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -483,6 +483,42 @@ pub fn core_macros() -> ~str { ) ) + macro_rules! assert_approx_eq ( + ($given:expr , $expected:expr) => ( + { + use core::cmp::ApproxEq; + + let given_val = $given; + let expected_val = $expected; + // check both directions of equality.... + if !( + given_val.approx_eq(&expected_val) && + expected_val.approx_eq(&given_val) + ) { + fail!(\"left: %? does not approximately equal right: %?\", + given_val, expected_val); + } + } + ); + ($given:expr , $expected:expr , $epsilon:expr) => ( + { + use core::cmp::ApproxEq; + + let given_val = $given; + let expected_val = $expected; + let epsilon_val = $epsilon; + // check both directions of equality.... + if !( + given_val.approx_eq_eps(&expected_val, &epsilon_val) && + expected_val.approx_eq_eps(&given_val, &epsilon_val) + ) { + fail!(\"left: %? does not approximately equal right: %? with epsilon: %?\", + given_val, expected_val, epsilon_val); + } + } + ) + ) + macro_rules! condition ( { $c:ident: $in:ty -> $out:ty; } => { diff --git a/src/test/run-fail/assert-approx-eq-eps-macro-fail.rs b/src/test/run-fail/assert-approx-eq-eps-macro-fail.rs new file mode 100644 index 0000000000000..c0c20f7af4351 --- /dev/null +++ b/src/test/run-fail/assert-approx-eq-eps-macro-fail.rs @@ -0,0 +1,14 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:left: 1.0000001 does not approximately equal right: 1 with epsilon: 0.0000001 +pub fn main() { + assert_approx_eq!(1.0000001f, 1.0f, 1.0e-7); +} diff --git a/src/test/run-fail/assert-approx-eq-macro-fail.rs b/src/test/run-fail/assert-approx-eq-macro-fail.rs new file mode 100644 index 0000000000000..43de4f92b63b1 --- /dev/null +++ b/src/test/run-fail/assert-approx-eq-macro-fail.rs @@ -0,0 +1,14 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// error-pattern:left: 1.00001 does not approximately equal right: 1 +pub fn main() { + assert_approx_eq!(1.00001f, 1.0f); +} diff --git a/src/test/run-pass/assert-approx-eq-macro-success.rs b/src/test/run-pass/assert-approx-eq-macro-success.rs new file mode 100644 index 0000000000000..5c7c11ef50343 --- /dev/null +++ b/src/test/run-pass/assert-approx-eq-macro-success.rs @@ -0,0 +1,16 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + assert_approx_eq!(1.0f, 1.0f); + assert_approx_eq!(1.0000001f, 1.0f); + assert_approx_eq!(1.0000001f, 1.0f, 1.0e-6); + assert_approx_eq!(1.000001f, 1.0f, 1.0e-5); +} From 2ea52a38e59b85b4b6998661b38425ce29839aed Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 May 2013 09:00:37 -0400 Subject: [PATCH 208/215] refinement to technique used to not run regionck --- src/libcore/cleanup.rs | 2 +- src/librustc/driver/session.rs | 3 ++ src/librustc/middle/typeck/check/mod.rs | 18 +++++-- src/librustc/middle/typeck/check/regionck.rs | 54 +++++++++---------- src/librustc/middle/typeck/mod.rs | 6 ++- src/libsyntax/diagnostic.rs | 8 ++- src/test/compile-fail/dead-code-ret.rs | 12 +++-- src/test/compile-fail/for-loop-decl.rs | 35 ------------ src/test/compile-fail/regions-bounds.rs | 6 +-- .../compile-fail/regions-ret-borrowed-1.rs | 2 - src/test/compile-fail/regions-ret-borrowed.rs | 2 - src/test/compile-fail/type-shadow.rs | 7 +-- 12 files changed, 66 insertions(+), 89 deletions(-) delete mode 100644 src/test/compile-fail/for-loop-decl.rs diff --git a/src/libcore/cleanup.rs b/src/libcore/cleanup.rs index 435b1cb7f34c3..06f6185586d85 100644 --- a/src/libcore/cleanup.rs +++ b/src/libcore/cleanup.rs @@ -15,7 +15,7 @@ use ptr::mut_null; use repr::BoxRepr; use sys::TypeDesc; use cast::transmute; -use unstable::lang::clear_task_borrow_list; +#[cfg(notest)] use unstable::lang::clear_task_borrow_list; #[cfg(notest)] use ptr::to_unsafe_ptr; diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs index 3b9bbbb9f1c5d..582e1d606bca6 100644 --- a/src/librustc/driver/session.rs +++ b/src/librustc/driver/session.rs @@ -188,6 +188,9 @@ pub impl Session_ { fn err(@self, msg: &str) { self.span_diagnostic.handler().err(msg) } + fn err_count(@self) -> uint { + self.span_diagnostic.handler().err_count() + } fn has_errors(@self) -> bool { self.span_diagnostic.handler().has_errors() } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 5357d092a9077..7e63db89edbcc 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -207,9 +207,11 @@ pub impl PurityState { } pub struct FnCtxt { - // var_bindings, locals and next_var_id are shared - // with any nested functions that capture the environment - // (and with any functions whose environment is being captured). + // Number of errors that had been reported when we started + // checking this function. On exit, if we find that *more* errors + // have been reported, we will skip regionck and other work that + // expects the types within the function to be consistent. + err_count_on_creation: uint, ret_ty: ty::t, // Used by loop bodies that return from the outer function @@ -263,6 +265,7 @@ pub fn blank_fn_ctxt(ccx: @mut CrateCtxt, // It's kind of a kludge to manufacture a fake function context // and statement context, but we might as well do write the code only once @mut FnCtxt { + err_count_on_creation: ccx.tcx.sess.err_count(), ret_ty: rty, indirect_ret_ty: None, ps: PurityState::function(ast::pure_fn, 0), @@ -328,6 +331,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, */ let tcx = ccx.tcx; + let err_count_on_creation = tcx.sess.err_count(); // ______________________________________________________________________ // First, we have to replace any bound regions in the fn and self @@ -368,6 +372,7 @@ pub fn check_fn(ccx: @mut CrateCtxt, }; @mut FnCtxt { + err_count_on_creation: err_count_on_creation, ret_ty: ret_ty, indirect_ret_ty: indirect_ret_ty, ps: PurityState::function(purity, id), @@ -642,7 +647,12 @@ impl AstConv for FnCtxt { } pub impl FnCtxt { - fn infcx(&self) -> @mut infer::InferCtxt { self.inh.infcx } + fn infcx(&self) -> @mut infer::InferCtxt { + self.inh.infcx + } + fn err_count_since_creation(&self) -> uint { + self.ccx.tcx.sess.err_count() - self.err_count_on_creation + } fn search_in_scope_regions( &self, span: span, diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index b4a1cab7b219c..03dd32353db6a 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -138,7 +138,8 @@ pub impl Rcx { pub fn regionck_expr(fcx: @mut FnCtxt, e: @ast::expr) { let rcx = @mut Rcx { fcx: fcx, errors_reported: 0 }; - if !fcx.tcx().sess.has_errors() { // regionck assumes typeck succeeded + if fcx.err_count_since_creation() == 0 { + // regionck assumes typeck succeeded let v = regionck_visitor(); (v.visit_expr)(e, rcx, v); } @@ -147,7 +148,8 @@ pub fn regionck_expr(fcx: @mut FnCtxt, e: @ast::expr) { pub fn regionck_fn(fcx: @mut FnCtxt, blk: &ast::blk) { let rcx = @mut Rcx { fcx: fcx, errors_reported: 0 }; - if !fcx.tcx().sess.has_errors() { // regionck assumes typeck succeeded + if fcx.err_count_since_creation() == 0 { + // regionck assumes typeck succeeded let v = regionck_visitor(); (v.visit_block)(blk, rcx, v); } @@ -409,10 +411,6 @@ fn constrain_callee(rcx: @mut Rcx, let call_region = ty::re_scope(call_expr.id); let callee_ty = rcx.resolve_node_type(call_expr.callee_id); - if ty::type_is_error(callee_ty) { - return; - } - match ty::get(callee_ty).sty { ty::ty_bare_fn(*) => { } ty::ty_closure(ref closure_ty) => { @@ -432,9 +430,12 @@ fn constrain_callee(rcx: @mut Rcx, } } _ => { - tcx.sess.span_bug( - callee_expr.span, - fmt!("Calling non-function: %s", callee_ty.repr(tcx))); + // this should not happen, but it does if the program is + // erroneous + // + // tcx.sess.span_bug( + // callee_expr.span, + // fmt!("Calling non-function: %s", callee_ty.repr(tcx))); } } } @@ -456,9 +457,6 @@ fn constrain_call(rcx: @mut Rcx, debug!("constrain_call(call_expr=%s, implicitly_ref_args=%?)", call_expr.repr(tcx), implicitly_ref_args); let callee_ty = rcx.resolve_node_type(call_expr.callee_id); - if ty::type_is_error(callee_ty) { - return; - } let fn_sig = ty::ty_fn_sig(callee_ty); // `callee_region` is the scope representing the time in which the @@ -919,7 +917,7 @@ pub mod guarantor { // expressions, both of which always yield a region variable, so // mk_subr should never fail. let rptr_ty = rcx.resolve_node_type(id); - if !ty::type_is_error(rptr_ty) && !ty::type_is_bot(rptr_ty) { + if !ty::type_is_bot(rptr_ty) { let tcx = rcx.fcx.ccx.tcx; debug!("rptr_ty=%s", ty_to_str(tcx, rptr_ty)); let r = ty::ty_region(tcx, span, rptr_ty); @@ -1216,29 +1214,25 @@ pub mod guarantor { } ast::pat_region(p) => { let rptr_ty = rcx.resolve_node_type(pat.id); - if !ty::type_is_error(rptr_ty) { - let r = ty::ty_region(rcx.fcx.tcx(), pat.span, rptr_ty); - link_ref_bindings_in_pat(rcx, p, Some(r)); - } + let r = ty::ty_region(rcx.fcx.tcx(), pat.span, rptr_ty); + link_ref_bindings_in_pat(rcx, p, Some(r)); } ast::pat_lit(*) => {} ast::pat_range(*) => {} ast::pat_vec(ref before, ref slice, ref after) => { let vec_ty = rcx.resolve_node_type(pat.id); - if !ty::type_is_error(vec_ty) { - let vstore = ty::ty_vstore(vec_ty); - let guarantor1 = match vstore { - ty::vstore_fixed(_) | ty::vstore_uniq => guarantor, - ty::vstore_slice(r) => Some(r), - ty::vstore_box => None - }; - - link_ref_bindings_in_pats(rcx, before, guarantor1); - for slice.each |&p| { - link_ref_bindings_in_pat(rcx, p, guarantor); - } - link_ref_bindings_in_pats(rcx, after, guarantor1); + let vstore = ty::ty_vstore(vec_ty); + let guarantor1 = match vstore { + ty::vstore_fixed(_) | ty::vstore_uniq => guarantor, + ty::vstore_slice(r) => Some(r), + ty::vstore_box => None + }; + + link_ref_bindings_in_pats(rcx, before, guarantor1); + for slice.each |&p| { + link_ref_bindings_in_pat(rcx, p, guarantor); } + link_ref_bindings_in_pats(rcx, after, guarantor1); } } } diff --git a/src/librustc/middle/typeck/mod.rs b/src/librustc/middle/typeck/mod.rs index 0012eb700302a..1a152f3c29119 100644 --- a/src/librustc/middle/typeck/mod.rs +++ b/src/librustc/middle/typeck/mod.rs @@ -414,7 +414,11 @@ pub fn check_crate(tcx: ty::ctxt, time(time_passes, ~"type collecting", || collect::collect_item_types(ccx, crate)); - time(time_passes, ~"method resolution", || + // this ensures that later parts of type checking can assume that items + // have valid types and not error + tcx.sess.abort_if_errors(); + + time(time_passes, ~"coherence checking", || coherence::check_coherence(ccx, crate)); time(time_passes, ~"type checking", || diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index 0f2374a892b4a..b313a2fc6fcc9 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -24,6 +24,7 @@ pub trait handler { fn fatal(@mut self, msg: &str) -> !; fn err(@mut self, msg: &str); fn bump_err_count(@mut self); + fn err_count(@mut self) -> uint; fn has_errors(@mut self) -> bool; fn abort_if_errors(@mut self); fn warn(@mut self, msg: &str); @@ -98,7 +99,12 @@ impl handler for HandlerT { fn bump_err_count(@mut self) { self.err_count += 1u; } - fn has_errors(@mut self) -> bool { self.err_count > 0u } + fn err_count(@mut self) -> uint { + self.err_count + } + fn has_errors(@mut self) -> bool { + self.err_count > 0u + } fn abort_if_errors(@mut self) { let s; match self.err_count { diff --git a/src/test/compile-fail/dead-code-ret.rs b/src/test/compile-fail/dead-code-ret.rs index 97f6149b162fc..5fa796db88444 100644 --- a/src/test/compile-fail/dead-code-ret.rs +++ b/src/test/compile-fail/dead-code-ret.rs @@ -10,8 +10,12 @@ // except according to those terms. -// error-pattern: dead +fn f(caller: &str) { + debug!(caller); + let x: uint = 0u32; // induce type error //~ ERROR mismatched types +} -fn f(caller: str) { debug!(caller); } - -fn main() { return f("main"); debug!("Paul is dead"); } +fn main() { + return f("main"); + debug!("Paul is dead"); //~ WARNING unreachable +} diff --git a/src/test/compile-fail/for-loop-decl.rs b/src/test/compile-fail/for-loop-decl.rs deleted file mode 100644 index de28d72677728..0000000000000 --- a/src/test/compile-fail/for-loop-decl.rs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern: mismatched types -extern mod std; -use std::bitv; -use core::hashmap::HashMap; - -struct FnInfo { - vars: HashMap -} - -struct VarInfo { - a: uint, - b: uint, -} - -fn bitv_to_str(enclosing: FnInfo, v: ~bitv::Bitv) -> str { - let s = ""; - - // error is that the value type in the hash map is var_info, not a box - for enclosing.vars.each_value |val| { - if *v.get(val) { s += "foo"; } - } - return s; -} - -fn main() { debug!("OK"); } diff --git a/src/test/compile-fail/regions-bounds.rs b/src/test/compile-fail/regions-bounds.rs index cccd135e9f836..ab2620d46fdc5 100644 --- a/src/test/compile-fail/regions-bounds.rs +++ b/src/test/compile-fail/regions-bounds.rs @@ -23,10 +23,8 @@ fn a_fn3<'a,'b>(e: a_class<'a>) -> a_class<'b> { return e; //~ ERROR mismatched types: expected `a_class/&'b ` but found `a_class/&'a ` } -fn a_fn4<'a,'b>(e: int<'a>) -> int<'b> { - //~^ ERROR region parameters are not allowed on this type - //~^^ ERROR region parameters are not allowed on this type - return e; +fn a_fn4<'a,'b>() { + let _: int<'a> = 1; //~ ERROR region parameters are not allowed on this type } fn main() { } diff --git a/src/test/compile-fail/regions-ret-borrowed-1.rs b/src/test/compile-fail/regions-ret-borrowed-1.rs index f600f6f6edd92..a572d90313b6a 100644 --- a/src/test/compile-fail/regions-ret-borrowed-1.rs +++ b/src/test/compile-fail/regions-ret-borrowed-1.rs @@ -18,8 +18,6 @@ fn with<'a, R>(f: &fn(x: &'a int) -> R) -> R { fn return_it<'a>() -> &'a int { with(|o| o) //~ ERROR mismatched types - //~^ ERROR reference is not valid outside of its lifetime - //~^^ ERROR reference is not valid outside of its lifetime } fn main() { diff --git a/src/test/compile-fail/regions-ret-borrowed.rs b/src/test/compile-fail/regions-ret-borrowed.rs index a3540f8f931f9..ec9a908ba9876 100644 --- a/src/test/compile-fail/regions-ret-borrowed.rs +++ b/src/test/compile-fail/regions-ret-borrowed.rs @@ -21,8 +21,6 @@ fn with(f: &fn(x: &int) -> R) -> R { fn return_it() -> &int { with(|o| o) //~ ERROR mismatched types - //~^ ERROR reference is not valid outside of its lifetime - //~^^ ERROR reference is not valid outside of its lifetime } fn main() { diff --git a/src/test/compile-fail/type-shadow.rs b/src/test/compile-fail/type-shadow.rs index a9b4a85e6385c..c4a412f64c8d4 100644 --- a/src/test/compile-fail/type-shadow.rs +++ b/src/test/compile-fail/type-shadow.rs @@ -9,14 +9,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -// error-pattern: mismatched types - fn main() { type X = int; type Y = X; if true { - type X = str; - let y: Y = "hello"; + type X = &'static str; + let y: Y = "hello"; //~ ERROR mismatched types } } From 84f7ecce5c8b727309d0d48e84a965a5a3437fd1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 May 2013 09:56:17 -0400 Subject: [PATCH 209/215] Adust arena test: can no longer allocate recursively --- src/libstd/arena.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/libstd/arena.rs b/src/libstd/arena.rs index b9a09323f81d0..da882d53fcffa 100644 --- a/src/libstd/arena.rs +++ b/src/libstd/arena.rs @@ -315,9 +315,6 @@ fn test_arena_destructors_fail() { } // Now, fail while allocating do arena.alloc::<@int> { - // First, recursively allocate something else; that needs to - // get freed too. - do arena.alloc { @20 }; // Now fail. fail!(); }; From 502817a9c19752cafcc270d9d3e5a5104ce2eac9 Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Mon, 6 May 2013 23:35:27 +0900 Subject: [PATCH 210/215] Fix cross-crate packed structs --- src/librustc/metadata/encoder.rs | 1 + src/test/auxiliary/packed.rs | 5 +++++ src/test/run-pass/packed-struct-size-xc.rs | 8 ++++++++ 3 files changed, 14 insertions(+) create mode 100644 src/test/auxiliary/packed.rs create mode 100644 src/test/run-pass/packed-struct-size-xc.rs diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 6a9c564f36828..7db362c692030 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -819,6 +819,7 @@ fn encode_info_for_item(ecx: @EncodeContext, } encode_name(ecx, ebml_w, item.ident); + encode_attributes(ebml_w, item.attrs); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); encode_region_param(ecx, ebml_w, item); diff --git a/src/test/auxiliary/packed.rs b/src/test/auxiliary/packed.rs new file mode 100644 index 0000000000000..478d51b540cdf --- /dev/null +++ b/src/test/auxiliary/packed.rs @@ -0,0 +1,5 @@ +#[packed] +struct S { + a: u8, + b: u32 +} diff --git a/src/test/run-pass/packed-struct-size-xc.rs b/src/test/run-pass/packed-struct-size-xc.rs new file mode 100644 index 0000000000000..ddfc2b17aa706 --- /dev/null +++ b/src/test/run-pass/packed-struct-size-xc.rs @@ -0,0 +1,8 @@ +// xfail-fast +// aux-build:packed.rs + +extern mod packed; + +fn main() { + assert_eq!(sys::size_of::(), 5); +} From c50a9d5b664478e533ba1d1d353213d70c8ad589 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 May 2013 11:16:17 -0400 Subject: [PATCH 211/215] Use rust_try_get_task for compat with new rt, and strenghten assumptions about borrow list --- src/libcore/unstable/lang.rs | 62 +++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index deff06d46f6c9..934874968d716 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -22,7 +22,6 @@ use rt::{context, OldTaskContext}; use rt::local_services::borrow_local_services; use option::{Option, Some, None}; use io; -use task::rt::rust_get_task; #[allow(non_camel_case_types)] pub type rust_task = c_void; @@ -56,6 +55,9 @@ pub mod rustrt { #[rust_stack] fn rust_set_task_borrow_list(task: *rust_task, map: *c_void); + #[rust_stack] + fn rust_try_get_task() -> *rust_task; + fn rust_dbg_breakpoint(); } } @@ -84,26 +86,32 @@ struct BorrowRecord { fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> { unsafe { - let cur_task = rust_get_task(); - let ptr = rustrt::rust_take_task_borrow_list(cur_task); - if ptr.is_null() { - None + let cur_task: *rust_task = rustrt::rust_try_get_task(); + if cur_task.is_not_null() { + let ptr = rustrt::rust_take_task_borrow_list(cur_task); + if ptr.is_null() { + None + } else { + let v: ~[BorrowRecord] = transmute(ptr); + Some(v) + } } else { - let v: ~[BorrowRecord] = transmute(ptr); - Some(v) + None } } } fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) { unsafe { - let cur_task = rust_get_task(); - let mut borrow_list: ~[BorrowRecord] = { - let ptr = rustrt::rust_take_task_borrow_list(cur_task); - if ptr.is_null() { ~[] } else { transmute(ptr) } - }; - borrow_list = f(borrow_list); - rustrt::rust_set_task_borrow_list(cur_task, transmute(borrow_list)); + let cur_task: *rust_task = rustrt::rust_try_get_task(); + if cur_task.is_not_null() { + let mut borrow_list: ~[BorrowRecord] = { + let ptr = rustrt::rust_take_task_borrow_list(cur_task); + if ptr.is_null() { ~[] } else { transmute(ptr) } + }; + borrow_list = f(borrow_list); + rustrt::rust_set_task_borrow_list(cur_task, transmute(borrow_list)); + } } } @@ -128,9 +136,7 @@ unsafe fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { for borrow_list.each_reverse |entry| { if entry.box == box { str::push_str(&mut msg, sep); - let filename = unsafe { - str::raw::from_c_str(entry.file) - }; + let filename = str::raw::from_c_str(entry.file); str::push_str(&mut msg, filename); str::push_str(&mut msg, fmt!(":%u", entry.line as uint)); sep = " and at "; @@ -351,25 +357,21 @@ pub unsafe fn record_borrow(a: *u8, old_ref_count: uint, pub unsafe fn unrecord_borrow(a: *u8, old_ref_count: uint, file: *c_char, line: size_t) { if (old_ref_count & ALL_BITS) == 0 { - // was not borrowed before + // was not borrowed before, so we should find the record at + // the end of the list let a: *mut BoxRepr = transmute(a); debug_borrow("unrecord_borrow:", a, old_ref_count, 0, file, line); do swap_task_borrow_list |borrow_list| { let mut borrow_list = borrow_list; - let br = BorrowRecord {box: a, file: file, line: line}; - match borrow_list.rposition_elem(&br) { - Some(idx) => { - borrow_list.remove(idx); - borrow_list - } - None => { - let err = fmt!("no borrow found, br=%?, borrow_list=%?", - br, borrow_list); - do str::as_buf(err) |msg_p, _| { - fail_(msg_p as *c_char, file, line) - } + assert!(!borrow_list.is_empty()); + let br = borrow_list.pop(); + if br.box != a || br.file != file || br.line != line { + let err = fmt!("wrong borrow found, br=%?", br); + do str::as_buf(err) |msg_p, _| { + fail_(msg_p as *c_char, file, line) } } + borrow_list } } } From 0ef4e860da1fb755b9fff5d1b30bee3974514ea2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 May 2013 14:02:28 -0400 Subject: [PATCH 212/215] Replace NOTE with FIXME --- src/librustc/middle/borrowck/check_loans.rs | 4 ++-- .../middle/borrowck/gather_loans/mod.rs | 2 +- src/librustc/middle/borrowck/mod.rs | 2 +- src/librustc/middle/dataflow.rs | 2 +- src/librustc/middle/region.rs | 3 +-- src/librustc/middle/trans/base.rs | 2 +- src/librustc/middle/trans/expr.rs | 3 ++- src/librustc/middle/trans/reachable.rs | 12 ++++++------ src/librustc/middle/typeck/check/mod.rs | 11 +++++------ src/librustc/middle/typeck/check/regionck.rs | 19 +++++++++++-------- 10 files changed, 31 insertions(+), 29 deletions(-) diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index b9a3f4bd6fcbb..ba719fe34d719 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -579,7 +579,7 @@ pub impl<'self> CheckLoanCtxt<'self> { } } - // NOTE inadequare if/when we permit `move a.b` + // FIXME(#4384) inadequare if/when we permit `move a.b` // check for a conflicting loan: for opt_loan_path(cmt).each |&lp| { @@ -604,7 +604,7 @@ pub impl<'self> CheckLoanCtxt<'self> { // However, I added it for consistency and lest the system // should change in the future. // - // FIXME(#5074) nested method calls + // FIXME(#6268) nested method calls // self.check_for_conflicting_loans(callee_id); } } diff --git a/src/librustc/middle/borrowck/gather_loans/mod.rs b/src/librustc/middle/borrowck/gather_loans/mod.rs index 922af0cadec6c..5f3c5d977fef5 100644 --- a/src/librustc/middle/borrowck/gather_loans/mod.rs +++ b/src/librustc/middle/borrowck/gather_loans/mod.rs @@ -389,7 +389,7 @@ pub impl GatherLoanCtxt { self.all_loans.push(loan); // if loan_gen_scope != borrow_id { - // NOTE handle case where gen_scope is not borrow_id + // FIXME(#6268) Nested method calls // // Typically, the scope of the loan includes the point at // which the loan is originated. This diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index c9a4de3830719..68e70d245f779 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -516,7 +516,7 @@ pub impl BorrowckCtxt { fmt!("%s in an aliasable location", prefix)); } mc::AliasableManaged(ast::m_mutbl) => { - // FIXME(#5074) we should prob do this borrow + // FIXME(#6269) reborrow @mut to &mut self.tcx.sess.span_err( span, fmt!("%s in a `@mut` pointer; \ diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 9d032a1839e23..ccb34851046bd 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -808,7 +808,7 @@ impl<'self, O:DataFlowOperator> PropagationContext<'self, O> { self.walk_expr(arg0, in_out, loop_scopes); self.walk_exprs(args, in_out, loop_scopes); - // FIXME(#5074) nested method calls + // FIXME(#6268) nested method calls // self.merge_with_entry_set(callee_id, in_out); // self.dfcx.apply_gen_kill(callee_id, in_out); diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index 5834ae1d78055..cdc3aa9fedb7e 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -393,7 +393,7 @@ pub fn resolve_expr(expr: @ast::expr, cx: Context, visitor: visit::vt) match expr.node { ast::expr_assign_op(*) | ast::expr_index(*) | ast::expr_binary(*) | ast::expr_unary(*) | ast::expr_call(*) | ast::expr_method_call(*) => { - // FIXME(#5074) Nested method calls + // FIXME(#6268) Nested method calls // // The lifetimes for a call or method call look as follows: // @@ -949,7 +949,6 @@ pub fn determine_rp_in_crate(sess: Session, while cx.worklist.len() != 0 { let c_id = cx.worklist.pop(); let c_variance = cx.region_paramd_items.get_copy(&c_id); - // NOTE cleanup scopes cause an exaggerated lock here debug!("popped %d from worklist", c_id); match cx.dep_map.find(&c_id) { None => {} diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 90dd9103011d5..34f798ec7a631 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -998,7 +998,7 @@ pub fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block { return bcx_sid } - // NOTE This is messier than it ought to be and not really right + // FIXME(#6268, #6248) hacky cleanup for nested method calls Some(NodeInfo { callee_id: Some(id), _ }) if id == scope_id => { return bcx_sid } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 6f1dbd8c2fec4..0e8b2e0474661 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -250,7 +250,8 @@ pub fn trans_to_datum(bcx: block, expr: @ast::expr) -> DatumBlock { let tcx = bcx.tcx(); let unit_ty = ty::sequence_element_type(tcx, datum.ty); - // NOTE prob need to distinguish "auto-slice" from explicit index? + + // FIXME(#6272) need to distinguish "auto-slice" from explicit index? let (bcx, base, len) = datum.get_vec_base_and_len(bcx, expr.span, expr.id); diff --git a/src/librustc/middle/trans/reachable.rs b/src/librustc/middle/trans/reachable.rs index 1dd73f76da735..9bbf50397c35a 100644 --- a/src/librustc/middle/trans/reachable.rs +++ b/src/librustc/middle/trans/reachable.rs @@ -75,11 +75,11 @@ fn traverse_def_id(cx: @mut ctx, did: def_id) { Some(&ast_map::node_item(item, _)) => traverse_public_item(cx, item), Some(&ast_map::node_method(_, impl_id, _)) => traverse_def_id(cx, impl_id), Some(&ast_map::node_foreign_item(item, _, _, _)) => { - let cx = &mut *cx; // NOTE reborrow @mut + let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut cx.rmap.insert(item.id); } Some(&ast_map::node_variant(ref v, _, _)) => { - let cx = &mut *cx; // NOTE reborrow @mut + let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut cx.rmap.insert(v.node.id); } _ => () @@ -109,7 +109,7 @@ fn traverse_public_item(cx: @mut ctx, item: @item) { item_foreign_mod(ref nm) => { if !traverse_exports(cx, item.id) { for nm.items.each |item| { - let cx = &mut *cx; // NOTE reborrow @mut + let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut cx.rmap.insert(item.id); } } @@ -127,7 +127,7 @@ fn traverse_public_item(cx: @mut ctx, item: @item) { attr::find_inline_attr(m.attrs) != attr::ia_none { { - let cx = &mut *cx; // NOTE reborrow @mut + let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut cx.rmap.insert(m.id); } traverse_inline_body(cx, &m.body); @@ -136,7 +136,7 @@ fn traverse_public_item(cx: @mut ctx, item: @item) { } item_struct(ref struct_def, _) => { for struct_def.ctor_id.each |&ctor_id| { - let cx = &mut *cx; // NOTE reborrow @mut + let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut cx.rmap.insert(ctor_id); } } @@ -153,7 +153,7 @@ fn traverse_public_item(cx: @mut ctx, item: @item) { fn traverse_ty<'a>(ty: @Ty, cx: @mut ctx<'a>, v: visit::vt<@mut ctx<'a>>) { { - let cx = &mut *cx; // NOTE reborrow @mut + let cx = &mut *cx; // FIXME(#6269) reborrow @mut to &mut if cx.rmap.contains(&ty.id) { return; } cx.rmap.insert(ty.id); } diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 7e63db89edbcc..e171765ef6c4e 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1301,12 +1301,11 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt, // Store the type of `f` as the type of the callee let fn_ty = fcx.expr_ty(f); - // NOTE here we write the callee type before regions have been - // substituted; in the method case, we write the type after - // regions have been substituted. Methods are correct, but it - // is awkward to deal with this now. Best thing would I think - // be to just have a separate "callee table" that contains the - // FnSig and not a general purpose ty::t + // FIXME(#6273) should write callee type AFTER regions have + // been subst'd. However, it is awkward to deal with this + // now. Best thing would I think be to just have a separate + // "callee table" that contains the FnSig and not a general + // purpose ty::t fcx.write_ty(call_expr.callee_id, fn_ty); // Extract the function signature from `in_fty`. diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 03dd32353db6a..491c7fadb18bd 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -157,14 +157,17 @@ pub fn regionck_fn(fcx: @mut FnCtxt, blk: &ast::blk) { } fn regionck_visitor() -> rvt { + // FIXME(#3238) should use visit_pat, not visit_arm/visit_local, + // However, right now we run into an issue whereby some free + // regions are not properly related if they appear within the + // types of arguments that must be inferred. This could be + // addressed by deferring the construction of the region + // hierarchy, and in particular the relationships between free + // regions, until regionck, as described in #3238. visit::mk_vt(@visit::Visitor {visit_item: visit_item, visit_expr: visit_expr, - // NOTE this should be visit_pat - // but causes errors in formal - // arguments in closures due to - // #XYZ! - //visit_pat: visit_pat, + //visit_pat: visit_pat, // (*) see FIXME above visit_arm: visit_arm, visit_local: visit_local, @@ -294,7 +297,7 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { // Require that the resulting region encompasses // the current node. // - // FIXME(#5074) remove to support nested method calls + // FIXME(#6268) remove to support nested method calls constrain_regions_in_type_of_node( rcx, expr.id, ty::re_scope(expr.id), expr.span); } @@ -374,7 +377,7 @@ fn visit_expr(expr: @ast::expr, rcx: @mut Rcx, v: rvt) { // the type of the node expr.id here *before applying // adjustments*. // - // FIXME(#5074) nested method calls requires that this rule change + // FIXME(#6268) nested method calls requires that this rule change let ty0 = rcx.resolve_node_type(expr.id); constrain_regions_in_type(rcx, ty::re_scope(expr.id), expr.span, ty0); } @@ -462,7 +465,7 @@ fn constrain_call(rcx: @mut Rcx, // `callee_region` is the scope representing the time in which the // call occurs. // - // FIXME(#5074) to support nested method calls, should be callee_id + // FIXME(#6268) to support nested method calls, should be callee_id let callee_scope = call_expr.id; let callee_region = ty::re_scope(callee_scope); From 8b32bde408bb6fdf6fcf4e7c2727fff3a31dd8b1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 May 2013 20:10:11 -0400 Subject: [PATCH 213/215] add rust_take_task_borrow_list and rust_set_task_borrow_list to rustrt.def.in --- src/rt/rustrt.def.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 3ca05b94711e8..1c3f6370deda4 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -233,3 +233,5 @@ rust_boxed_region_malloc rust_boxed_region_free rust_try rust_begin_unwind +rust_take_task_borrow_list +rust_set_task_borrow_list From ce45f390dd55fbd8ebaf1be07ad1b3b3bb5d2f4d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 May 2013 20:14:54 -0400 Subject: [PATCH 214/215] Remove debug_mem since @graydon said it conflicted with GC changes --- src/libcore/cleanup.rs | 10 +--------- src/libcore/unstable/lang.rs | 22 +--------------------- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/src/libcore/cleanup.rs b/src/libcore/cleanup.rs index 06f6185586d85..424cc3483092d 100644 --- a/src/libcore/cleanup.rs +++ b/src/libcore/cleanup.rs @@ -167,8 +167,7 @@ fn debug_mem() -> bool { #[cfg(notest)] #[lang="annihilate"] pub unsafe fn annihilate() { - use unstable::lang::{local_free}; - use unstable::lang; + use unstable::lang::local_free; use io::WriterUtil; use io; use libc; @@ -192,10 +191,8 @@ pub unsafe fn annihilate() { for each_live_alloc(true) |box, uniq| { stats.n_total_boxes += 1; if uniq { - lang::debug_mem("Managed-uniq: ", &*box); stats.n_unique_boxes += 1; } else { - lang::debug_mem("Immortalizing: ", &*box); (*box).header.ref_count = managed::raw::RC_IMMORTAL; } } @@ -207,13 +204,9 @@ pub unsafe fn annihilate() { // callback, as the original value may have been freed. for each_live_alloc(false) |box, uniq| { if !uniq { - lang::debug_mem("Invoking tydesc/glue on: ", &*box); let tydesc: *TypeDesc = transmute(copy (*box).header.type_desc); let drop_glue: DropGlue = transmute(((*tydesc).drop_glue, 0)); - lang::debug_mem("Box data: ", &(*box).data); - lang::debug_mem("Type descriptor: ", tydesc); drop_glue(to_unsafe_ptr(&tydesc), transmute(&(*box).data)); - lang::debug_mem("Dropped ", &*box); } } @@ -225,7 +218,6 @@ pub unsafe fn annihilate() { // not be valid after. for each_live_alloc(true) |box, uniq| { if !uniq { - lang::debug_mem("About to free: ", &*box); stats.n_bytes_freed += (*((*box).header.type_desc)).size + sys::size_of::(); diff --git a/src/libcore/unstable/lang.rs b/src/libcore/unstable/lang.rs index 934874968d716..8153c2d43d998 100644 --- a/src/libcore/unstable/lang.rs +++ b/src/libcore/unstable/lang.rs @@ -153,32 +153,13 @@ unsafe fn fail_borrowed(box: *mut BoxRepr, file: *c_char, line: size_t) { #[lang="exchange_malloc"] #[inline(always)] pub unsafe fn exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char { - let result = transmute(exchange_alloc::malloc(transmute(td), transmute(size))); - debug_mem("exchange_malloc: ", result); - return result; + transmute(exchange_alloc::malloc(transmute(td), transmute(size))) } /// Because this code is so perf. sensitive, use a static constant so that /// debug printouts are compiled out most of the time. static ENABLE_DEBUG: bool = false; -#[inline] -pub fn debug_mem(tag: &'static str, p: *const T) { - //! A useful debugging function that prints a pointer + tag + newline - //! without allocating memory. - - if ENABLE_DEBUG && ::rt::env::get().debug_mem { - debug_mem_slow(tag, p); - } - - fn debug_mem_slow(tag: &'static str, p: *const T) { - let dbg = STDERR_FILENO as io::fd_t; - dbg.write_str(tag); - dbg.write_hex(p as uint); - dbg.write_str("\n"); - } -} - #[inline] unsafe fn debug_borrow(tag: &'static str, p: *const T, @@ -252,7 +233,6 @@ impl DebugPrints for io::fd_t { #[lang="exchange_free"] #[inline(always)] pub unsafe fn exchange_free(ptr: *c_char) { - debug_mem("exchange_free: ", ptr); exchange_alloc::free(transmute(ptr)) } From 39a119074aa27234a68bcf57899c8c4e015cd478 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 6 May 2013 20:27:59 -0400 Subject: [PATCH 215/215] appease the tidy gods with respect to a FIXME --- src/librustc/middle/typeck/check/regionck.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc/middle/typeck/check/regionck.rs b/src/librustc/middle/typeck/check/regionck.rs index 491c7fadb18bd..6db6b7556aee4 100644 --- a/src/librustc/middle/typeck/check/regionck.rs +++ b/src/librustc/middle/typeck/check/regionck.rs @@ -157,7 +157,7 @@ pub fn regionck_fn(fcx: @mut FnCtxt, blk: &ast::blk) { } fn regionck_visitor() -> rvt { - // FIXME(#3238) should use visit_pat, not visit_arm/visit_local, + // (*) FIXME(#3238) should use visit_pat, not visit_arm/visit_local, // However, right now we run into an issue whereby some free // regions are not properly related if they appear within the // types of arguments that must be inferred. This could be @@ -167,7 +167,7 @@ fn regionck_visitor() -> rvt { visit::mk_vt(@visit::Visitor {visit_item: visit_item, visit_expr: visit_expr, - //visit_pat: visit_pat, // (*) see FIXME above + //visit_pat: visit_pat, // (*) see above visit_arm: visit_arm, visit_local: visit_local,