about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in2
-rw-r--r--doc/guide-container.md8
-rw-r--r--doc/guide-ffi.md2
-rw-r--r--doc/tutorial.md3
-rw-r--r--man/rustc.14
-rw-r--r--src/etc/gedit/share/gtksourceview-3.0/language-specs/rust.lang2
-rw-r--r--src/etc/gedit/share/mime/packages/rust.xml1
-rw-r--r--src/etc/kate/rust.xml2
-rw-r--r--src/etc/vim/ftdetect/rust.vim2
-rw-r--r--src/libextra/bitv.rs8
-rw-r--r--src/libextra/c_vec.rs2
-rw-r--r--src/libextra/dlist.rs14
-rw-r--r--src/libextra/flate.rs4
-rw-r--r--src/libextra/ringbuf.rs10
-rw-r--r--src/libextra/smallintmap.rs10
-rw-r--r--src/libnative/bookkeeping.rs1
-rw-r--r--src/libnative/io/file.rs6
-rw-r--r--src/libnative/io/mod.rs18
-rw-r--r--src/libnative/io/process.rs2
-rw-r--r--src/libnative/io/timer_helper.rs143
-rw-r--r--src/libnative/io/timer_other.rs328
-rw-r--r--src/libnative/io/timer_timerfd.rs304
-rw-r--r--src/libnative/io/timer_win32.rs203
-rw-r--r--src/librustc/driver/driver.rs2
-rw-r--r--src/librustc/driver/session.rs3
-rw-r--r--src/librustc/lib/llvm.rs4
-rw-r--r--src/librustc/metadata/csearch.rs5
-rw-r--r--src/librustc/middle/borrowck/check_loans.rs41
-rw-r--r--src/librustc/middle/borrowck/mod.rs4
-rw-r--r--src/librustc/middle/trans/cleanup.rs14
-rw-r--r--src/librustpkg/api.rs36
-rw-r--r--src/librustpkg/conditions.rs2
-rw-r--r--src/librustpkg/crate_id.rs150
-rw-r--r--src/librustpkg/installed_packages.rs8
-rw-r--r--src/librustpkg/lib.rs38
-rw-r--r--src/librustpkg/package_source.rs80
-rw-r--r--src/librustpkg/path_util.rs198
-rw-r--r--src/librustpkg/source_control.rs11
-rw-r--r--src/librustpkg/tests.rs627
-rw-r--r--src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs4
-rw-r--r--src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs4
-rw-r--r--src/librustpkg/util.rs51
-rw-r--r--src/librustpkg/version.rs187
-rw-r--r--src/librustpkg/workspace.rs8
-rw-r--r--src/librustuv/uvll.rs4
-rw-r--r--src/libstd/c_str.rs4
-rw-r--r--src/libstd/cleanup.rs5
-rw-r--r--src/libstd/fmt/mod.rs30
-rw-r--r--src/libstd/hashmap.rs50
-rw-r--r--src/libstd/io/test.rs1
-rw-r--r--src/libstd/io/timer.rs174
-rw-r--r--src/libstd/iter.rs54
-rw-r--r--src/libstd/lib.rs1
-rw-r--r--src/libstd/libc.rs3
-rw-r--r--src/libstd/local_data.rs11
-rw-r--r--src/libstd/num/f32.rs78
-rw-r--r--src/libstd/num/f64.rs78
-rw-r--r--src/libstd/num/strconv.rs70
-rw-r--r--src/libstd/os.rs64
-rw-r--r--src/libstd/path/windows.rs10
-rw-r--r--src/libstd/rc.rs4
-rw-r--r--src/libstd/reflect.rs7
-rw-r--r--src/libstd/repr.rs27
-rw-r--r--src/libstd/rt/at_exit_imp.rs72
-rw-r--r--src/libstd/rt/global_heap.rs32
-rw-r--r--src/libstd/rt/local_heap.rs12
-rw-r--r--src/libstd/rt/local_ptr.rs74
-rw-r--r--src/libstd/rt/mod.rs22
-rw-r--r--src/libstd/rt/thread.rs2
-rw-r--r--src/libstd/rt/thread_local_storage.rs17
-rw-r--r--src/libstd/rt/unwind.rs13
-rw-r--r--src/libstd/rt/util.rs1
-rw-r--r--src/libstd/run.rs8
-rw-r--r--src/libstd/str.rs24
-rw-r--r--src/libstd/sync/atomics.rs3
-rw-r--r--src/libstd/sync/deque.rs2
-rw-r--r--src/libstd/trie.rs6
-rw-r--r--src/libstd/unstable/dynamic_lib.rs39
-rw-r--r--src/libstd/unstable/lang.rs13
-rw-r--r--src/libstd/unstable/mutex.rs78
-rw-r--r--src/libstd/vec.rs43
-rw-r--r--src/libstd/vec_ng.rs231
-rw-r--r--src/libsyntax/codemap.rs4
-rw-r--r--src/libsyntax/crateid.rs10
-rw-r--r--src/libsyntax/diagnostic.rs88
-rw-r--r--src/libsyntax/ext/base.rs4
-rw-r--r--src/libsyntax/ext/format.rs2
-rw-r--r--src/libsyntax/parse/parser.rs5
m---------src/llvm0
-rw-r--r--src/rustllvm/llvm-auto-clean-trigger2
-rw-r--r--src/test/bench/core-map.rs4
-rw-r--r--src/test/bench/shootout-meteor.rs2
-rw-r--r--src/test/compile-fail/borrowck-borrow-mut-object-twice.rs2
-rw-r--r--src/test/compile-fail/borrowck-report-with-custom-diagnostic.rs31
-rw-r--r--src/test/compile-fail/mut-cant-alias.rs2
-rw-r--r--src/test/compile-fail/vec-mut-iter-borrow.rs2
-rw-r--r--src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs1
-rw-r--r--src/test/run-pass/exponential-notation.rs34
-rw-r--r--src/test/run-pass/ifmt.rs10
-rw-r--r--src/test/run-pass/trailing-comma.rs16
100 files changed, 2730 insertions, 1412 deletions
diff --git a/Makefile.in b/Makefile.in
index 7f1a6945d8a..aab1e2ff556 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -367,7 +367,7 @@ LLVM_COMPONENTS=x86 arm mips ipo bitreader bitwriter linker asmparser jit mcjit
                 interpreter instrumentation
 
 # Only build these LLVM tools
-LLVM_TOOLS=bugpoint llc llvm-ar llvm-as llvm-dis llvm-mc opt
+LLVM_TOOLS=bugpoint llc llvm-ar llvm-as llvm-dis llvm-mc opt llvm-extract
 
 define DEF_LLVM_VARS
 # The configure script defines these variables with the target triples
diff --git a/doc/guide-container.md b/doc/guide-container.md
index 668e263697c..628e4f223b4 100644
--- a/doc/guide-container.md
+++ b/doc/guide-container.md
@@ -336,8 +336,8 @@ The `DoubleEndedIterator` trait represents an iterator able to yield elements
 from either end of a range. It inherits from the `Iterator` trait and extends
 it with the `next_back` function.
 
-A `DoubleEndedIterator` can be flipped with the `invert` adaptor, returning
-another `DoubleEndedIterator` with `next` and `next_back` exchanged.
+A `DoubleEndedIterator` can have its direction changed with the `rev` adaptor,
+returning another `DoubleEndedIterator` with `next` and `next_back` exchanged.
 
 ~~~
 let xs = [1, 2, 3, 4, 5, 6];
@@ -347,7 +347,7 @@ println!("{:?}", it.next()); // prints `Some(&2)`
 println!("{:?}", it.next_back()); // prints `Some(&6)`
 
 // prints `5`, `4` and `3`
-for &x in it.invert() {
+for &x in it.rev() {
     println!("{}", x)
 }
 ~~~
@@ -366,7 +366,7 @@ let mut it = xs.iter().chain(ys.iter()).map(|&x| x * 2);
 println!("{:?}", it.next()); // prints `Some(2)`
 
 // prints `16`, `14`, `12`, `10`, `8`, `6`, `4`
-for x in it.invert() {
+for x in it.rev() {
     println!("{}", x);
 }
 ~~~
diff --git a/doc/guide-ffi.md b/doc/guide-ffi.md
index 236da56588e..217eab52758 100644
--- a/doc/guide-ffi.md
+++ b/doc/guide-ffi.md
@@ -230,7 +230,7 @@ impl<T: Send> Drop for Unique<T> {
             // We need to move the object out of the box, so that
             // the destructor is called (at the end of this scope.)
             ptr::replace_ptr(self.ptr, x);
-            free(self.ptr as *c_void)
+            free(self.ptr as *mut c_void)
         }
     }
 }
diff --git a/doc/tutorial.md b/doc/tutorial.md
index 057944484ba..cc8dd6edd3f 100644
--- a/doc/tutorial.md
+++ b/doc/tutorial.md
@@ -3071,7 +3071,8 @@ The effect it has on your module hierarchy mirrors aspects of both `mod` and `us
   The linkage information the binary needs to use the library `foo`.
 
 - But like `use`, all `extern mod` statements that refer to the same library are interchangeable,
-  as each one really just presents an alias to an external module (the crate root of the library your linking against).
+  as each one really just presents an alias to an external module (the crate root of the library
+  you're linking against).
 
 Remember how `use`-statements have to go before local declarations because the latter shadows the former?
 Well, `extern mod` statements also have their own rules in that regard:
diff --git a/man/rustc.1 b/man/rustc.1
index e4cfab7747f..6f84d0f8f71 100644
--- a/man/rustc.1
+++ b/man/rustc.1
@@ -122,8 +122,8 @@ To build an executable from a source file with a main function:
 To build a library from a source file:
     $ rustc --lib hello-lib.rs
 
-To build either with a crate (.rc) file:
-    $ rustc hello.rc
+To build either with a crate (.rs) file:
+    $ rustc hello.rs
 
 To build an executable with debug info (experimental):
     $ rustc -Z debug-info -o hello hello.rs
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 b8841ebe568..43700c02b75 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
@@ -5,7 +5,7 @@
 <language id="rust" _name="Rust" version="2.0" _section="Sources">
   <metadata>
     <property name="mimetypes">text/x-rust</property>
-    <property name="globs">*.rs;*.rc</property>
+    <property name="globs">*.rs</property>
     <property name="line-comment-start">//</property>
     <property name="block-comment-start">/*</property>
     <property name="block-comment-end">*/</property>
diff --git a/src/etc/gedit/share/mime/packages/rust.xml b/src/etc/gedit/share/mime/packages/rust.xml
index d75cffe9600..ede1c14907c 100644
--- a/src/etc/gedit/share/mime/packages/rust.xml
+++ b/src/etc/gedit/share/mime/packages/rust.xml
@@ -2,6 +2,5 @@
   <mime-type type="text/x-rust">
     <comment>Rust Source</comment>
     <glob pattern="*.rs"/>
-    <glob pattern="*.rc"/>
   </mime-type>
 </mime-info>
diff --git a/src/etc/kate/rust.xml b/src/etc/kate/rust.xml
index db479e468d5..c1c5215ac0f 100644
--- a/src/etc/kate/rust.xml
+++ b/src/etc/kate/rust.xml
@@ -7,7 +7,7 @@
 	<!ENTITY rustIdent "[a-zA-Z_][a-zA-Z_0-9]*">
 	<!ENTITY rustIntSuf "([iu](8|16|32|64)?)?">
 ]>
-<language name="Rust" version="0.10-pre" kateversion="2.4" section="Sources" extensions="*.rs;*.rc" mimetype="text/x-rust" priority="15">
+<language name="Rust" version="0.10-pre" kateversion="2.4" section="Sources" extensions="*.rs" mimetype="text/x-rust" priority="15">
 <highlighting>
 	<list name="fn">
 		<item> fn </item>
diff --git a/src/etc/vim/ftdetect/rust.vim b/src/etc/vim/ftdetect/rust.vim
index 10b616277c8..bf685d43243 100644
--- a/src/etc/vim/ftdetect/rust.vim
+++ b/src/etc/vim/ftdetect/rust.vim
@@ -1 +1 @@
-au BufRead,BufNewFile *.rs,*.rc set filetype=rust
+au BufRead,BufNewFile *.rs set filetype=rust
diff --git a/src/libextra/bitv.rs b/src/libextra/bitv.rs
index 305c9702001..9df75ff044a 100644
--- a/src/libextra/bitv.rs
+++ b/src/libextra/bitv.rs
@@ -13,7 +13,7 @@
 
 use std::cmp;
 use std::iter::RandomAccessIterator;
-use std::iter::{Invert, Enumerate, Repeat, Map, Zip};
+use std::iter::{Rev, Enumerate, Repeat, Map, Zip};
 use std::num;
 use std::ops;
 use std::uint;
@@ -387,7 +387,7 @@ impl Bitv {
         }
     }
 
-    /// Invert all bits
+    /// Flip all bits
     #[inline]
     pub fn negate(&mut self) {
         match self.rep {
@@ -428,8 +428,8 @@ impl Bitv {
     }
 
     #[inline]
-    pub fn rev_iter<'a>(&'a self) -> Invert<Bits<'a>> {
-        self.iter().invert()
+    pub fn rev_iter<'a>(&'a self) -> Rev<Bits<'a>> {
+        self.iter().rev()
     }
 
     /// Returns `true` if all bits are 0
diff --git a/src/libextra/c_vec.rs b/src/libextra/c_vec.rs
index fc2caa13584..35a6ccaa708 100644
--- a/src/libextra/c_vec.rs
+++ b/src/libextra/c_vec.rs
@@ -172,7 +172,7 @@ mod tests {
             let mem = malloc_raw(n);
 
             CVec::new_with_dtor(mem as *mut u8, n,
-                proc() { libc::free(mem as *c_void); })
+                proc() { libc::free(mem as *mut c_void); })
         }
     }
 
diff --git a/src/libextra/dlist.rs b/src/libextra/dlist.rs
index 115700e7408..fa6e7c15ee0 100644
--- a/src/libextra/dlist.rs
+++ b/src/libextra/dlist.rs
@@ -25,7 +25,7 @@
 use std::cast;
 use std::ptr;
 use std::util;
-use std::iter::Invert;
+use std::iter::Rev;
 use std::iter;
 
 use container::Deque;
@@ -368,8 +368,8 @@ impl<T> DList<T> {
 
     /// Provide a reverse iterator
     #[inline]
-    pub fn rev_iter<'a>(&'a self) -> Invert<Items<'a, T>> {
-        self.iter().invert()
+    pub fn rev_iter<'a>(&'a self) -> Rev<Items<'a, T>> {
+        self.iter().rev()
     }
 
     /// Provide a forward iterator with mutable references
@@ -388,8 +388,8 @@ impl<T> DList<T> {
     }
     /// Provide a reverse iterator with mutable references
     #[inline]
-    pub fn mut_rev_iter<'a>(&'a mut self) -> Invert<MutItems<'a, T>> {
-        self.mut_iter().invert()
+    pub fn mut_rev_iter<'a>(&'a mut self) -> Rev<MutItems<'a, T>> {
+        self.mut_iter().rev()
     }
 
 
@@ -401,8 +401,8 @@ impl<T> DList<T> {
 
     /// Consume the list into an iterator yielding elements by value, in reverse
     #[inline]
-    pub fn move_rev_iter(self) -> Invert<MoveItems<T>> {
-        self.move_iter().invert()
+    pub fn move_rev_iter(self) -> Rev<MoveItems<T>> {
+        self.move_iter().rev()
     }
 }
 
diff --git a/src/libextra/flate.rs b/src/libextra/flate.rs
index 1153c3a6ef3..faceb17af47 100644
--- a/src/libextra/flate.rs
+++ b/src/libextra/flate.rs
@@ -53,7 +53,7 @@ fn deflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
         assert!(res as int != 0);
             let out = vec::raw::from_buf_raw(res as *u8,
                                              outsz as uint);
-        libc::free(res);
+        libc::free(res as *mut c_void);
         out
     }
 }
@@ -76,7 +76,7 @@ fn inflate_bytes_internal(bytes: &[u8], flags: c_int) -> ~[u8] {
         assert!(res as int != 0);
         let out = vec::raw::from_buf_raw(res as *u8,
                                          outsz as uint);
-        libc::free(res);
+        libc::free(res as *mut c_void);
         out
     }
 }
diff --git a/src/libextra/ringbuf.rs b/src/libextra/ringbuf.rs
index c5c8f69dc65..684aafd2500 100644
--- a/src/libextra/ringbuf.rs
+++ b/src/libextra/ringbuf.rs
@@ -15,7 +15,7 @@
 
 use std::num;
 use std::vec;
-use std::iter::{Invert, RandomAccessIterator};
+use std::iter::{Rev, RandomAccessIterator};
 
 use container::Deque;
 
@@ -192,8 +192,8 @@ impl<T> RingBuf<T> {
     }
 
     /// Back-to-front iterator.
-    pub fn rev_iter<'a>(&'a self) -> Invert<Items<'a, T>> {
-        self.iter().invert()
+    pub fn rev_iter<'a>(&'a self) -> Rev<Items<'a, T>> {
+        self.iter().rev()
     }
 
     /// Front-to-back iterator which returns mutable values.
@@ -223,8 +223,8 @@ impl<T> RingBuf<T> {
     }
 
     /// Back-to-front iterator which returns mutable values.
-    pub fn mut_rev_iter<'a>(&'a mut self) -> Invert<MutItems<'a, T>> {
-        self.mut_iter().invert()
+    pub fn mut_rev_iter<'a>(&'a mut self) -> Rev<MutItems<'a, T>> {
+        self.mut_iter().rev()
     }
 }
 
diff --git a/src/libextra/smallintmap.rs b/src/libextra/smallintmap.rs
index 93d138a9d46..abbd987a9c4 100644
--- a/src/libextra/smallintmap.rs
+++ b/src/libextra/smallintmap.rs
@@ -15,7 +15,7 @@
 
 #[allow(missing_doc)];
 
-use std::iter::{Enumerate, FilterMap, Invert};
+use std::iter::{Enumerate, FilterMap, Rev};
 use std::util::replace;
 use std::vec;
 
@@ -140,14 +140,14 @@ impl<V> SmallIntMap<V> {
     /// An iterator visiting all key-value pairs in descending order by the keys.
     /// Iterator element type is (uint, &'r V)
     pub fn rev_iter<'r>(&'r self) -> RevEntries<'r, V> {
-        self.iter().invert()
+        self.iter().rev()
     }
 
     /// An iterator visiting all key-value pairs in descending order by the keys,
     /// with mutable references to the values
     /// Iterator element type is (uint, &'r mut V)
     pub fn mut_rev_iter<'r>(&'r mut self) -> RevMutEntries <'r, V> {
-        self.mut_iter().invert()
+        self.mut_iter().rev()
     }
 
     /// Empties the hash map, moving all values into the specified closure
@@ -241,7 +241,7 @@ pub struct Entries<'a, T> {
 
 iterator!(impl Entries -> (uint, &'a T), get_ref)
 double_ended_iterator!(impl Entries -> (uint, &'a T), get_ref)
-pub type RevEntries<'a, T> = Invert<Entries<'a, T>>;
+pub type RevEntries<'a, T> = Rev<Entries<'a, T>>;
 
 pub struct MutEntries<'a, T> {
     priv front: uint,
@@ -251,7 +251,7 @@ pub struct MutEntries<'a, T> {
 
 iterator!(impl MutEntries -> (uint, &'a mut T), get_mut_ref)
 double_ended_iterator!(impl MutEntries -> (uint, &'a mut T), get_mut_ref)
-pub type RevMutEntries<'a, T> = Invert<MutEntries<'a, T>>;
+pub type RevMutEntries<'a, T> = Rev<MutEntries<'a, T>>;
 
 #[cfg(test)]
 mod test_map {
diff --git a/src/libnative/bookkeeping.rs b/src/libnative/bookkeeping.rs
index 6c5f555f401..b07e4271ee4 100644
--- a/src/libnative/bookkeeping.rs
+++ b/src/libnative/bookkeeping.rs
@@ -45,5 +45,6 @@ pub fn wait_for_other_tasks() {
             TASK_LOCK.wait();
         }
         TASK_LOCK.unlock();
+        TASK_LOCK.destroy();
     }
 }
diff --git a/src/libnative/io/file.rs b/src/libnative/io/file.rs
index af6ed51729e..af06533d44b 100644
--- a/src/libnative/io/file.rs
+++ b/src/libnative/io/file.rs
@@ -548,13 +548,13 @@ pub fn readdir(p: &CString) -> IoResult<~[Path]> {
             let p = Path::new(p);
             let star = p.join("*");
             as_utf16_p(star.as_str().unwrap(), |path_ptr| {
-                let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint) as *c_void;
+                let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint);
                 let find_handle = FindFirstFileW(path_ptr, wfd_ptr as HANDLE);
                 if find_handle as libc::c_int != INVALID_HANDLE_VALUE {
                     let mut paths = ~[];
                     let mut more_files = 1 as libc::c_int;
                     while more_files != 0 {
-                        let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr);
+                        let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr as *c_void);
                         if fp_buf as uint == 0 {
                             fail!("os::list_dir() failure: got null ptr from wfd");
                         }
@@ -567,7 +567,7 @@ pub fn readdir(p: &CString) -> IoResult<~[Path]> {
                         more_files = FindNextFileW(find_handle, wfd_ptr as HANDLE);
                     }
                     FindClose(find_handle);
-                    free(wfd_ptr);
+                    free(wfd_ptr as *mut c_void);
                     Ok(paths)
                 } else {
                     Err(super::last_error())
diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs
index f1bec440547..f3aca7820a5 100644
--- a/src/libnative/io/mod.rs
+++ b/src/libnative/io/mod.rs
@@ -46,6 +46,22 @@ pub mod file;
 pub mod process;
 pub mod net;
 
+#[cfg(target_os = "macos")]
+#[cfg(target_os = "freebsd")]
+#[path = "timer_other.rs"]
+pub mod timer;
+
+#[cfg(target_os = "linux")]
+#[cfg(target_os = "android")]
+#[path = "timer_timerfd.rs"]
+pub mod timer;
+
+#[cfg(target_os = "win32")]
+#[path = "timer_win32.rs"]
+pub mod timer;
+
+mod timer_helper;
+
 type IoResult<T> = Result<T, IoError>;
 
 fn unimpl() -> IoError {
@@ -249,7 +265,7 @@ impl rtio::IoFactory for IoFactory {
 
     // misc
     fn timer_init(&mut self) -> IoResult<~RtioTimer> {
-        Err(unimpl())
+        timer::Timer::new().map(|t| ~t as ~RtioTimer)
     }
     fn spawn(&mut self, config: ProcessConfig)
             -> IoResult<(~RtioProcess, ~[Option<~RtioPipe>])> {
diff --git a/src/libnative/io/process.rs b/src/libnative/io/process.rs
index 0569c45f6de..ee4ee295055 100644
--- a/src/libnative/io/process.rs
+++ b/src/libnative/io/process.rs
@@ -460,7 +460,7 @@ fn spawn_process_os(prog: &str, args: &[~str],
             fail!("failure in dup3(err_fd, 2): {}", os::last_os_error());
         }
         // close all other fds
-        for fd in range(3, getdtablesize()).invert() {
+        for fd in range(3, getdtablesize()).rev() {
             if fd != output.fd() {
                 close(fd as c_int);
             }
diff --git a/src/libnative/io/timer_helper.rs b/src/libnative/io/timer_helper.rs
new file mode 100644
index 00000000000..3c20d073f29
--- /dev/null
+++ b/src/libnative/io/timer_helper.rs
@@ -0,0 +1,143 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Implementation of the helper thread for the timer module
+//!
+//! This module contains the management necessary for the timer worker thread.
+//! This thread is responsible for performing the send()s on channels for timers
+//! that are using channels instead of a blocking call.
+//!
+//! The timer thread is lazily initialized, and it's shut down via the
+//! `shutdown` function provided. It must be maintained as an invariant that
+//! `shutdown` is only called when the entire program is finished. No new timers
+//! can be created in the future and there must be no active timers at that
+//! time.
+
+use std::cast;
+use std::rt;
+use std::unstable::mutex::{Once, ONCE_INIT};
+
+use bookkeeping;
+use io::timer::{Req, Shutdown};
+use task;
+
+// You'll note that these variables are *not* protected by a lock. These
+// variables are initialized with a Once before any Timer is created and are
+// only torn down after everything else has exited. This means that these
+// variables are read-only during use (after initialization) and both of which
+// are safe to use concurrently.
+static mut HELPER_CHAN: *mut SharedChan<Req> = 0 as *mut SharedChan<Req>;
+static mut HELPER_SIGNAL: imp::signal = 0 as imp::signal;
+
+pub fn boot(helper: fn(imp::signal, Port<Req>)) {
+    static mut INIT: Once = ONCE_INIT;
+
+    unsafe {
+        INIT.doit(|| {
+            let (msgp, msgc) = SharedChan::new();
+            HELPER_CHAN = cast::transmute(~msgc);
+            let (receive, send) = imp::new();
+            HELPER_SIGNAL = send;
+
+            do task::spawn {
+                bookkeeping::decrement();
+                helper(receive, msgp);
+            }
+
+            rt::at_exit(proc() { shutdown() });
+        })
+    }
+}
+
+pub fn send(req: Req) {
+    unsafe {
+        assert!(!HELPER_CHAN.is_null());
+        (*HELPER_CHAN).send(req);
+        imp::signal(HELPER_SIGNAL);
+    }
+}
+
+fn shutdown() {
+    // We want to wait for the entire helper task to exit, and in doing so it
+    // will attempt to decrement the global task count. When the helper was
+    // created, it decremented the count so it wouldn't count towards preventing
+    // the program to exit, so here we pair that manual decrement with a manual
+    // increment. We will then wait for the helper thread to exit by calling
+    // wait_for_other_tasks.
+    bookkeeping::increment();
+
+    // Request a shutdown, and then wait for the task to exit
+    send(Shutdown);
+    bookkeeping::wait_for_other_tasks();
+
+    // Clean up after ther helper thread
+    unsafe {
+        imp::close(HELPER_SIGNAL);
+        let _chan: ~SharedChan<Req> = cast::transmute(HELPER_CHAN);
+        HELPER_CHAN = 0 as *mut SharedChan<Req>;
+        HELPER_SIGNAL = 0 as imp::signal;
+    }
+}
+
+#[cfg(unix)]
+mod imp {
+    use std::libc;
+    use std::os;
+
+    use io::file::FileDesc;
+
+    pub type signal = libc::c_int;
+
+    pub fn new() -> (signal, signal) {
+        let pipe = os::pipe();
+        (pipe.input, pipe.out)
+    }
+
+    pub fn signal(fd: libc::c_int) {
+        FileDesc::new(fd, false).inner_write([0]);
+    }
+
+    pub fn close(fd: libc::c_int) {
+        let _fd = FileDesc::new(fd, true);
+    }
+}
+
+#[cfg(windows)]
+mod imp {
+    use std::libc::{BOOL, LPCSTR, HANDLE, LPSECURITY_ATTRIBUTES, CloseHandle};
+    use std::ptr;
+    use std::libc;
+
+    pub type signal = HANDLE;
+
+    pub fn new() -> (HANDLE, HANDLE) {
+        unsafe {
+            let handle = CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
+                                      ptr::null());
+            (handle, handle)
+        }
+    }
+
+    pub fn signal(handle: HANDLE) {
+        unsafe { SetEvent(handle); }
+    }
+
+    pub fn close(handle: HANDLE) {
+        unsafe { CloseHandle(handle); }
+    }
+
+    extern "system" {
+        fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
+                        bManualReset: BOOL,
+                        bInitialState: BOOL,
+                        lpName: LPCSTR) -> HANDLE;
+        fn SetEvent(hEvent: HANDLE) -> BOOL;
+    }
+}
diff --git a/src/libnative/io/timer_other.rs b/src/libnative/io/timer_other.rs
new file mode 100644
index 00000000000..24ffd7a4147
--- /dev/null
+++ b/src/libnative/io/timer_other.rs
@@ -0,0 +1,328 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Timers for non-linux/non-windows OSes
+//!
+//! This module implements timers with a worker thread, select(), and a lot of
+//! witchcraft that turns out to be horribly inaccurate timers. The unfortunate
+//! part is that I'm at a loss of what else to do one these OSes. This is also
+//! why linux has a specialized timerfd implementation and windows has its own
+//! implementation (they're more accurate than this one).
+//!
+//! The basic idea is that there is a worker thread that's communicated to via a
+//! channel and a pipe, the pipe is used by the worker thread in a select()
+//! syscall with a timeout. The timeout is the "next timer timeout" while the
+//! channel is used to send data over to the worker thread.
+//!
+//! Whenever the call to select() times out, then a channel receives a message.
+//! Whenever the call returns that the file descriptor has information, then the
+//! channel from timers is drained, enqueueing all incoming requests.
+//!
+//! The actual implementation of the helper thread is a sorted array of
+//! timers in terms of target firing date. The target is the absolute time at
+//! which the timer should fire. Timers are then re-enqueued after a firing if
+//! the repeat boolean is set.
+//!
+//! Naturally, all this logic of adding times and keeping track of
+//! relative/absolute time is a little lossy and not quite exact. I've done the
+//! best I could to reduce the amount of calls to 'now()', but there's likely
+//! still inaccuracies trickling in here and there.
+//!
+//! One of the tricky parts of this implementation is that whenever a timer is
+//! acted upon, it must cancel whatever the previous action was (if one is
+//! active) in order to act like the other implementations of this timer. In
+//! order to do this, the timer's inner pointer is transferred to the worker
+//! thread. Whenever the timer is modified, it first takes ownership back from
+//! the worker thread in order to modify the same data structure. This has the
+//! side effect of "cancelling" the previous requests while allowing a
+//! re-enqueueing later on.
+//!
+//! Note that all time units in this file are in *milliseconds*.
+
+use std::comm::Data;
+use std::hashmap::HashMap;
+use std::libc;
+use std::os;
+use std::ptr;
+use std::rt::rtio;
+use std::sync::atomics;
+use std::unstable::intrinsics;
+
+use io::file::FileDesc;
+use io::IoResult;
+use io::timer_helper;
+
+pub struct Timer {
+    priv id: uint,
+    priv inner: Option<~Inner>,
+}
+
+struct Inner {
+    chan: Option<Chan<()>>,
+    interval: u64,
+    repeat: bool,
+    target: u64,
+    id: uint,
+}
+
+pub enum Req {
+    // Add a new timer to the helper thread.
+    NewTimer(~Inner),
+
+    // Remove a timer based on its id and then send it back on the channel
+    // provided
+    RemoveTimer(uint, Chan<~Inner>),
+
+    // Shut down the loop and then ACK this channel once it's shut down
+    Shutdown,
+}
+
+// returns the current time (in milliseconds)
+fn now() -> u64 {
+    unsafe {
+        let mut now: libc::timeval = intrinsics::init();
+        assert_eq!(imp::gettimeofday(&mut now, ptr::null()), 0);
+        return (now.tv_sec as u64) * 1000 + (now.tv_usec as u64) / 1000;
+    }
+}
+
+fn helper(input: libc::c_int, messages: Port<Req>) {
+    let mut set: imp::fd_set = unsafe { intrinsics::init() };
+
+    let mut fd = FileDesc::new(input, true);
+    let mut timeout: libc::timeval = unsafe { intrinsics::init() };
+
+    // active timers are those which are able to be selected upon (and it's a
+    // sorted list, and dead timers are those which have expired, but ownership
+    // hasn't yet been transferred back to the timer itself.
+    let mut active: ~[~Inner] = ~[];
+    let mut dead = HashMap::new();
+
+    // inserts a timer into an array of timers (sorted by firing time)
+    fn insert(t: ~Inner, active: &mut ~[~Inner]) {
+        match active.iter().position(|tm| tm.target > t.target) {
+            Some(pos) => { active.insert(pos, t); }
+            None => { active.push(t); }
+        }
+    }
+
+    // signals the first requests in the queue, possible re-enqueueing it.
+    fn signal(active: &mut ~[~Inner], dead: &mut HashMap<uint, ~Inner>) {
+        let mut timer = match active.shift() {
+            Some(timer) => timer, None => return
+        };
+        let chan = timer.chan.take_unwrap();
+        if chan.try_send(()) && timer.repeat {
+            timer.chan = Some(chan);
+            timer.target += timer.interval;
+            insert(timer, active);
+        } else {
+            drop(chan);
+            dead.insert(timer.id, timer);
+        }
+    }
+
+    'outer: loop {
+        let timeout = match active {
+            // Empty array? no timeout (wait forever for the next request)
+            [] => ptr::null(),
+
+            [~Inner { target, .. }, ..] => {
+                let now = now();
+                // If this request has already expired, then signal it and go
+                // through another iteration
+                if target <= now {
+                    signal(&mut active, &mut dead);
+                    continue;
+                }
+
+                // The actual timeout listed in the requests array is an
+                // absolute date, so here we translate the absolute time to a
+                // relative time.
+                let tm = target - now;
+                timeout.tv_sec = (tm / 1000) as libc::time_t;
+                timeout.tv_usec = ((tm % 1000) * 1000) as libc::suseconds_t;
+                &timeout as *libc::timeval
+            }
+        };
+
+        imp::fd_set(&mut set, input);
+        match unsafe {
+            imp::select(input + 1, &set, ptr::null(), ptr::null(), timeout)
+        } {
+            // timed out
+            0 => signal(&mut active, &mut dead),
+
+            // file descriptor write woke us up, we've got some new requests
+            1 => {
+                loop {
+                    match messages.try_recv() {
+                        Data(Shutdown) => {
+                            assert!(active.len() == 0);
+                            break 'outer;
+                        }
+
+                        Data(NewTimer(timer)) => insert(timer, &mut active),
+
+                        Data(RemoveTimer(id, ack)) => {
+                            match dead.pop(&id) {
+                                Some(i) => { ack.send(i); continue }
+                                None => {}
+                            }
+                            let i = active.iter().position(|i| i.id == id);
+                            let i = i.expect("no timer found");
+                            let t = active.remove(i).unwrap();
+                            ack.send(t);
+                        }
+                        _ => break
+                    }
+                }
+
+                // drain the file descriptor
+                let mut buf = [0];
+                fd.inner_read(buf);
+            }
+
+            -1 if os::errno() == libc::EINTR as int => {}
+            n => fail!("helper thread failed in select() with error: {} ({})",
+                       n, os::last_os_error())
+        }
+    }
+}
+
+impl Timer {
+    pub fn new() -> IoResult<Timer> {
+        timer_helper::boot(helper);
+
+        static mut ID: atomics::AtomicUint = atomics::INIT_ATOMIC_UINT;
+        let id = unsafe { ID.fetch_add(1, atomics::Relaxed) };
+        Ok(Timer {
+            id: id,
+            inner: Some(~Inner {
+                chan: None,
+                interval: 0,
+                target: 0,
+                repeat: false,
+                id: id,
+            })
+        })
+    }
+
+    pub fn sleep(ms: u64) {
+        unsafe { libc::usleep((ms * 1000) as libc::c_uint); }
+    }
+
+    fn inner(&mut self) -> ~Inner {
+        match self.inner.take() {
+            Some(i) => i,
+            None => {
+                let (p, c) = Chan::new();
+                timer_helper::send(RemoveTimer(self.id, c));
+                p.recv()
+            }
+        }
+    }
+}
+
+impl rtio::RtioTimer for Timer {
+    fn sleep(&mut self, msecs: u64) {
+        let mut inner = self.inner();
+        inner.chan = None; // cancel any previous request
+        self.inner = Some(inner);
+
+        Timer::sleep(msecs);
+    }
+
+    fn oneshot(&mut self, msecs: u64) -> Port<()> {
+        let now = now();
+        let mut inner = self.inner();
+
+        let (p, c) = Chan::new();
+        inner.repeat = false;
+        inner.chan = Some(c);
+        inner.interval = msecs;
+        inner.target = now + msecs;
+
+        timer_helper::send(NewTimer(inner));
+        return p;
+    }
+
+    fn period(&mut self, msecs: u64) -> Port<()> {
+        let now = now();
+        let mut inner = self.inner();
+
+        let (p, c) = Chan::new();
+        inner.repeat = true;
+        inner.chan = Some(c);
+        inner.interval = msecs;
+        inner.target = now + msecs;
+
+        timer_helper::send(NewTimer(inner));
+        return p;
+    }
+}
+
+impl Drop for Timer {
+    fn drop(&mut self) {
+        self.inner = Some(self.inner());
+    }
+}
+
+#[cfg(target_os = "macos")]
+mod imp {
+    use std::libc;
+
+    pub static FD_SETSIZE: uint = 1024;
+
+    pub struct fd_set {
+        fds_bits: [i32, ..(FD_SETSIZE / 32)]
+    }
+
+    pub fn fd_set(set: &mut fd_set, fd: i32) {
+        set.fds_bits[fd / 32] |= 1 << (fd % 32);
+    }
+
+    extern {
+        pub fn select(nfds: libc::c_int,
+                      readfds: *fd_set,
+                      writefds: *fd_set,
+                      errorfds: *fd_set,
+                      timeout: *libc::timeval) -> libc::c_int;
+
+        pub fn gettimeofday(timeval: *mut libc::timeval,
+                            tzp: *libc::c_void) -> libc::c_int;
+    }
+}
+
+#[cfg(target_os = "freebsd")]
+mod imp {
+    use std::libc;
+
+    pub static FD_SETSIZE: uint = 1024;
+
+    pub struct fd_set {
+        fds_bits: [u64, ..(FD_SETSIZE / 64)]
+    }
+
+    pub fn fd_set(set: &mut fd_set, fd: i32) {
+        set.fds_bits[fd / 64] |= (1 << (fd % 64)) as u64;
+    }
+
+    extern {
+        pub fn select(nfds: libc::c_int,
+                      readfds: *fd_set,
+                      writefds: *fd_set,
+                      errorfds: *fd_set,
+                      timeout: *libc::timeval) -> libc::c_int;
+
+        pub fn gettimeofday(timeval: *mut libc::timeval,
+                            tzp: *libc::c_void) -> libc::c_int;
+    }
+}
diff --git a/src/libnative/io/timer_timerfd.rs b/src/libnative/io/timer_timerfd.rs
new file mode 100644
index 00000000000..0556b0c2599
--- /dev/null
+++ b/src/libnative/io/timer_timerfd.rs
@@ -0,0 +1,304 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Timers based on timerfd_create(2)
+//!
+//! On OSes which support timerfd_create, we can use these much more accurate
+//! timers over select() + a timeout (see timer_other.rs). This strategy still
+//! employs a worker thread which does the waiting on the timer fds (to send
+//! messages away).
+//!
+//! The worker thread in this implementation uses epoll(7) to block. It
+//! maintains a working set of *all* native timers in the process, along with a
+//! pipe file descriptor used to communicate that there is data available on the
+//! incoming channel to the worker thread. Timers send requests to update their
+//! timerfd settings to the worker thread (see the comment above 'oneshot' for
+//! why).
+//!
+//! As with timer_other, timers just using sleep() do not use the timerfd at
+//! all. They remove the timerfd from the worker thread and then invoke usleep()
+//! to block the calling thread.
+//!
+//! As with timer_other, all units in this file are in units of millseconds.
+
+use std::comm::Data;
+use std::libc;
+use std::ptr;
+use std::os;
+use std::rt::rtio;
+use std::hashmap::HashMap;
+use std::unstable::intrinsics;
+
+use io::file::FileDesc;
+use io::IoResult;
+use io::timer_helper;
+
+pub struct Timer {
+    priv fd: FileDesc,
+    priv on_worker: bool,
+}
+
+pub enum Req {
+    NewTimer(libc::c_int, Chan<()>, bool, imp::itimerspec),
+    RemoveTimer(libc::c_int, Chan<()>),
+    Shutdown,
+}
+
+fn helper(input: libc::c_int, messages: Port<Req>) {
+    let efd = unsafe { imp::epoll_create(10) };
+    let _fd1 = FileDesc::new(input, true);
+    let _fd2 = FileDesc::new(efd, true);
+
+    fn add(efd: libc::c_int, fd: libc::c_int) {
+        let event = imp::epoll_event {
+            events: imp::EPOLLIN as u32,
+            data: imp::epoll_data_t { fd: fd, pad: 0, }
+        };
+        let ret = unsafe {
+            imp::epoll_ctl(efd, imp::EPOLL_CTL_ADD, fd, &event)
+        };
+        assert_eq!(ret, 0);
+    }
+    fn del(efd: libc::c_int, fd: libc::c_int) {
+        let event = imp::epoll_event {
+            events: 0, data: imp::epoll_data_t { fd: 0, pad: 0, }
+        };
+        let ret = unsafe {
+            imp::epoll_ctl(efd, imp::EPOLL_CTL_DEL, fd, &event)
+        };
+        assert_eq!(ret, 0);
+    }
+
+    add(efd, input);
+    let events: [imp::epoll_event, ..16] = unsafe { intrinsics::init() };
+    let mut map: HashMap<libc::c_int, (Chan<()>, bool)> = HashMap::new();
+    'outer: loop {
+        let n = match unsafe {
+            imp::epoll_wait(efd, events.as_ptr(),
+                            events.len() as libc::c_int, -1)
+        } {
+            0 => fail!("epoll_wait returned immediately!"),
+            -1 if os::errno() == libc::EINTR as int => { continue }
+            -1 => fail!("epoll wait failed: {}", os::last_os_error()),
+            n => n
+        };
+
+        let mut incoming = false;
+        debug!("{} events to process", n);
+        for event in events.slice_to(n as uint).iter() {
+            let fd = event.data.fd;
+            debug!("data on fd {} (input = {})", fd, input);
+            if fd == input {
+                let mut buf = [0, ..1];
+                // drain the input file descriptor of its input
+                FileDesc::new(fd, false).inner_read(buf);
+                incoming = true;
+            } else {
+                let mut bits = [0, ..8];
+                // drain the timerfd of how many times its fired
+                //
+                // XXX: should this perform a send() this number of
+                //      times?
+                FileDesc::new(fd, false).inner_read(bits);
+                let remove = {
+                    match map.find(&fd).expect("fd unregistered") {
+                        &(ref c, oneshot) => !c.try_send(()) || oneshot
+                    }
+                };
+                if remove {
+                    map.remove(&fd);
+                    del(efd, fd);
+                }
+            }
+        }
+
+        while incoming {
+            match messages.try_recv() {
+                Data(NewTimer(fd, chan, one, timeval)) => {
+                    // acknowledge we have the new channel, we will never send
+                    // another message to the old channel
+                    chan.send(());
+
+                    // If we haven't previously seen the file descriptor, then
+                    // we need to add it to the epoll set.
+                    if map.insert(fd, (chan, one)) {
+                        add(efd, fd);
+                    }
+
+                    // Update the timerfd's time value now that we have control
+                    // of the timerfd
+                    let ret = unsafe {
+                        imp::timerfd_settime(fd, 0, &timeval, ptr::null())
+                    };
+                    assert_eq!(ret, 0);
+                }
+
+                Data(RemoveTimer(fd, chan)) => {
+                    if map.remove(&fd) {
+                        del(efd, fd);
+                    }
+                    chan.send(());
+                }
+
+                Data(Shutdown) => {
+                    assert!(map.len() == 0);
+                    break 'outer;
+                }
+
+                _ => break,
+            }
+        }
+    }
+}
+
+impl Timer {
+    pub fn new() -> IoResult<Timer> {
+        timer_helper::boot(helper);
+        match unsafe { imp::timerfd_create(imp::CLOCK_MONOTONIC, 0) } {
+            -1 => Err(super::last_error()),
+            n => Ok(Timer { fd: FileDesc::new(n, true), on_worker: false, }),
+        }
+    }
+
+    pub fn sleep(ms: u64) {
+        unsafe { libc::usleep((ms * 1000) as libc::c_uint); }
+    }
+
+    fn remove(&mut self) {
+        if !self.on_worker { return }
+
+        let (p, c) = Chan::new();
+        timer_helper::send(RemoveTimer(self.fd.fd(), c));
+        p.recv();
+        self.on_worker = false;
+    }
+}
+
+impl rtio::RtioTimer for Timer {
+    fn sleep(&mut self, msecs: u64) {
+        self.remove();
+        Timer::sleep(msecs);
+    }
+
+    // Periodic and oneshot channels are updated by updating the settings on the
+    // corresopnding timerfd. The update is not performed on the thread calling
+    // oneshot or period, but rather the helper epoll thread. The reason for
+    // this is to avoid losing messages and avoid leaking messages across ports.
+    //
+    // By updating the timerfd on the helper thread, we're guaranteed that all
+    // messages for a particular setting of the timer will be received by the
+    // new channel/port pair rather than leaking old messages onto the new port
+    // or leaking new messages onto the old port.
+    //
+    // We also wait for the remote thread to actually receive the new settings
+    // before returning to guarantee the invariant that when oneshot() and
+    // period() return that the old port will never receive any more messages.
+
+    fn oneshot(&mut self, msecs: u64) -> Port<()> {
+        let (p, c) = Chan::new();
+
+        let new_value = imp::itimerspec {
+            it_interval: imp::timespec { tv_sec: 0, tv_nsec: 0 },
+            it_value: imp::timespec {
+                tv_sec: (msecs / 1000) as libc::time_t,
+                tv_nsec: ((msecs % 1000) * 1000000) as libc::c_long,
+            }
+        };
+        timer_helper::send(NewTimer(self.fd.fd(), c, true, new_value));
+        p.recv();
+        self.on_worker = true;
+
+        return p;
+    }
+
+    fn period(&mut self, msecs: u64) -> Port<()> {
+        let (p, c) = Chan::new();
+
+        let spec = imp::timespec {
+            tv_sec: (msecs / 1000) as libc::time_t,
+            tv_nsec: ((msecs % 1000) * 1000000) as libc::c_long,
+        };
+        let new_value = imp::itimerspec { it_interval: spec, it_value: spec, };
+        timer_helper::send(NewTimer(self.fd.fd(), c, false, new_value));
+        p.recv();
+        self.on_worker = true;
+
+        return p;
+    }
+}
+
+impl Drop for Timer {
+    fn drop(&mut self) {
+        // When the timerfd file descriptor is closed, it will be automatically
+        // removed from the epoll set of the worker thread, but we want to make
+        // sure that the associated channel is also removed from the worker's
+        // hash map.
+        self.remove();
+    }
+}
+
+#[allow(dead_code)]
+mod imp {
+    use std::libc;
+
+    pub static CLOCK_MONOTONIC: libc::c_int = 1;
+    pub static EPOLL_CTL_ADD: libc::c_int = 1;
+    pub static EPOLL_CTL_DEL: libc::c_int = 2;
+    pub static EPOLL_CTL_MOD: libc::c_int = 3;
+    pub static EPOLLIN: libc::c_int = 0x001;
+    pub static EPOLLOUT: libc::c_int = 0x004;
+    pub static EPOLLPRI: libc::c_int = 0x002;
+    pub static EPOLLERR: libc::c_int = 0x008;
+    pub static EPOLLRDHUP: libc::c_int = 0x2000;
+    pub static EPOLLET: libc::c_int = 1 << 31;
+    pub static EPOLLHUP: libc::c_int = 0x010;
+    pub static EPOLLONESHOT: libc::c_int = 1 << 30;
+
+    pub struct epoll_event {
+        events: u32,
+        data: epoll_data_t,
+    }
+
+    pub struct epoll_data_t {
+        fd: i32,
+        pad: u32,
+    }
+
+    pub struct timespec {
+        tv_sec: libc::time_t,
+        tv_nsec: libc::c_long,
+    }
+
+    pub struct itimerspec {
+        it_interval: timespec,
+        it_value: timespec,
+    }
+
+    extern {
+        pub fn timerfd_create(clockid: libc::c_int,
+                              flags: libc::c_int) -> libc::c_int;
+        pub fn timerfd_settime(fd: libc::c_int,
+                               flags: libc::c_int,
+                               new_value: *itimerspec,
+                               old_value: *itimerspec) -> libc::c_int;
+        pub fn timerfd_gettime(fd: libc::c_int,
+                               curr_value: *itimerspec) -> libc::c_int;
+
+        pub fn epoll_create(size: libc::c_int) -> libc::c_int;
+        pub fn epoll_ctl(epfd: libc::c_int,
+                         op: libc::c_int,
+                         fd: libc::c_int,
+                         event: *epoll_event) -> libc::c_int;
+        pub fn epoll_wait(epfd: libc::c_int,
+                          events: *epoll_event,
+                          maxevents: libc::c_int,
+                          timeout: libc::c_int) -> libc::c_int;
+    }
+}
diff --git a/src/libnative/io/timer_win32.rs b/src/libnative/io/timer_win32.rs
new file mode 100644
index 00000000000..e359d99eedf
--- /dev/null
+++ b/src/libnative/io/timer_win32.rs
@@ -0,0 +1,203 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Timers based on win32 WaitableTimers
+//!
+//! This implementation is meant to be used solely on windows. As with other
+//! implementations, there is a worker thread which is doing all the waiting on
+//! a large number of timers for all active timers in the system. This worker
+//! thread uses the select() equivalent, WaitForMultipleObjects. One of the
+//! objects being waited on is a signal into the worker thread to notify that
+//! the incoming channel should be looked at.
+//!
+//! Other than that, the implementation is pretty straightforward in terms of
+//! the other two implementations of timers with nothing *that* new showing up.
+
+use std::comm::Data;
+use std::libc;
+use std::ptr;
+use std::rt::rtio;
+
+use io::timer_helper;
+use io::IoResult;
+
+pub struct Timer {
+    priv obj: libc::HANDLE,
+    priv on_worker: bool,
+}
+
+pub enum Req {
+    NewTimer(libc::HANDLE, Chan<()>, bool),
+    RemoveTimer(libc::HANDLE, Chan<()>),
+    Shutdown,
+}
+
+fn helper(input: libc::HANDLE, messages: Port<Req>) {
+    let mut objs = ~[input];
+    let mut chans = ~[];
+
+    'outer: loop {
+        let idx = unsafe {
+            imp::WaitForMultipleObjects(objs.len() as libc::DWORD,
+                                        objs.as_ptr(),
+                                        0 as libc::BOOL,
+                                        libc::INFINITE)
+        };
+
+        if idx == 0 {
+            loop {
+                match messages.try_recv() {
+                    Data(NewTimer(obj, c, one)) => {
+                        objs.push(obj);
+                        chans.push((c, one));
+                    }
+                    Data(RemoveTimer(obj, c)) => {
+                        c.send(());
+                        match objs.iter().position(|&o| o == obj) {
+                            Some(i) => {
+                                objs.remove(i);
+                                chans.remove(i - 1);
+                            }
+                            None => {}
+                        }
+                    }
+                    Data(Shutdown) => {
+                        assert_eq!(objs.len(), 1);
+                        assert_eq!(chans.len(), 0);
+                        break 'outer;
+                    }
+                    _ => break
+                }
+            }
+        } else {
+            let remove = {
+                match &chans[idx - 1] {
+                    &(ref c, oneshot) => !c.try_send(()) || oneshot
+                }
+            };
+            if remove {
+                objs.remove(idx as uint);
+                chans.remove(idx as uint - 1);
+            }
+        }
+    }
+}
+
+impl Timer {
+    pub fn new() -> IoResult<Timer> {
+        timer_helper::boot(helper);
+
+        let obj = unsafe {
+            imp::CreateWaitableTimerA(ptr::mut_null(), 0, ptr::null())
+        };
+        if obj.is_null() {
+            Err(super::last_error())
+        } else {
+            Ok(Timer { obj: obj, on_worker: false, })
+        }
+    }
+
+    pub fn sleep(ms: u64) {
+        use std::rt::rtio::RtioTimer;
+        let mut t = Timer::new().ok().expect("must allocate a timer!");
+        t.sleep(ms);
+    }
+
+    fn remove(&mut self) {
+        if !self.on_worker { return }
+
+        let (p, c) = Chan::new();
+        timer_helper::send(RemoveTimer(self.obj, c));
+        p.recv();
+
+        self.on_worker = false;
+    }
+}
+
+impl rtio::RtioTimer for Timer {
+    fn sleep(&mut self, msecs: u64) {
+        self.remove();
+
+        // there are 10^6 nanoseconds in a millisecond, and the parameter is in
+        // 100ns intervals, so we multiply by 10^4.
+        let due = -(msecs * 10000) as libc::LARGE_INTEGER;
+        assert_eq!(unsafe {
+            imp::SetWaitableTimer(self.obj, &due, 0, ptr::null(),
+                                  ptr::mut_null(), 0)
+        }, 1);
+
+        unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE); }
+    }
+
+    fn oneshot(&mut self, msecs: u64) -> Port<()> {
+        self.remove();
+        let (p, c) = Chan::new();
+
+        // see above for the calculation
+        let due = -(msecs * 10000) as libc::LARGE_INTEGER;
+        assert_eq!(unsafe {
+            imp::SetWaitableTimer(self.obj, &due, 0, ptr::null(),
+                                  ptr::mut_null(), 0)
+        }, 1);
+
+        timer_helper::send(NewTimer(self.obj, c, true));
+        self.on_worker = true;
+        return p;
+    }
+
+    fn period(&mut self, msecs: u64) -> Port<()> {
+        self.remove();
+        let (p, c) = Chan::new();
+
+        // see above for the calculation
+        let due = -(msecs * 10000) as libc::LARGE_INTEGER;
+        assert_eq!(unsafe {
+            imp::SetWaitableTimer(self.obj, &due, msecs as libc::LONG,
+                                  ptr::null(), ptr::mut_null(), 0)
+        }, 1);
+
+        timer_helper::send(NewTimer(self.obj, c, false));
+        self.on_worker = true;
+
+        return p;
+    }
+}
+
+impl Drop for Timer {
+    fn drop(&mut self) {
+        self.remove();
+        unsafe { libc::CloseHandle(self.obj); }
+    }
+}
+
+mod imp {
+    use std::libc::{LPSECURITY_ATTRIBUTES, BOOL, LPCSTR, HANDLE, LARGE_INTEGER,
+                    LONG, LPVOID, DWORD, c_void};
+
+    pub type PTIMERAPCROUTINE = *c_void;
+
+    extern "system" {
+        pub fn CreateWaitableTimerA(lpTimerAttributes: LPSECURITY_ATTRIBUTES,
+                                    bManualReset: BOOL,
+                                    lpTimerName: LPCSTR) -> HANDLE;
+        pub fn SetWaitableTimer(hTimer: HANDLE,
+                                pDueTime: *LARGE_INTEGER,
+                                lPeriod: LONG,
+                                pfnCompletionRoutine: PTIMERAPCROUTINE,
+                                lpArgToCompletionRoutine: LPVOID,
+                                fResume: BOOL) -> BOOL;
+        pub fn WaitForMultipleObjects(nCount: DWORD,
+                                      lpHandles: *HANDLE,
+                                      bWaitAll: BOOL,
+                                      dwMilliseconds: DWORD) -> DWORD;
+        pub fn WaitForSingleObject(hHandle: HANDLE,
+                                   dwMilliseconds: DWORD) -> DWORD;
+    }
+}
diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs
index 9cc12caa478..301a49d8aec 100644
--- a/src/librustc/driver/driver.rs
+++ b/src/librustc/driver/driver.rs
@@ -1134,7 +1134,7 @@ pub fn build_output_filenames(input: &Input,
 
 pub fn early_error(emitter: &diagnostic::Emitter, msg: &str) -> ! {
     emitter.emit(None, msg, diagnostic::Fatal);
-    fail!();
+    fail!(diagnostic::FatalError);
 }
 
 pub fn list_metadata(sess: Session, path: &Path, out: &mut io::Writer) {
diff --git a/src/librustc/driver/session.rs b/src/librustc/driver/session.rs
index 75094bc8084..42b716e8cdf 100644
--- a/src/librustc/driver/session.rs
+++ b/src/librustc/driver/session.rs
@@ -250,6 +250,9 @@ impl Session_ {
     pub fn span_note(&self, sp: Span, msg: &str) {
         self.span_diagnostic.span_note(sp, msg)
     }
+    pub fn span_end_note(&self, sp: Span, msg: &str) {
+        self.span_diagnostic.span_end_note(sp, msg)
+    }
     pub fn note(&self, msg: &str) {
         self.span_diagnostic.handler().note(msg)
     }
diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs
index c259fa6a618..3693b00951b 100644
--- a/src/librustc/lib/llvm.rs
+++ b/src/librustc/lib/llvm.rs
@@ -1836,7 +1836,7 @@ impl TypeNames {
         unsafe {
             let s = llvm::LLVMTypeToString(ty.to_ref());
             let ret = from_c_str(s);
-            free(s as *c_void);
+            free(s as *mut c_void);
             ret
         }
     }
@@ -1850,7 +1850,7 @@ impl TypeNames {
         unsafe {
             let s = llvm::LLVMValueToString(val);
             let ret = from_c_str(s);
-            free(s as *c_void);
+            free(s as *mut c_void);
             ret
         }
     }
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index 3985527232c..8d5be0cfb82 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -211,17 +211,14 @@ pub fn get_field_type(tcx: ty::ctxt, class_id: ast::DefId,
     let cstore = tcx.cstore;
     let cdata = cstore.get_crate_data(class_id.crate);
     let all_items = reader::get_doc(reader::Doc(cdata.data()), tag_items);
-    debug!("Looking up {:?}", class_id);
     let class_doc = expect(tcx.diag,
                            decoder::maybe_find_item(class_id.node, all_items),
                            || format!("get_field_type: class ID {:?} not found",
                                    class_id) );
-    debug!("looking up {:?} : {:?}", def, class_doc);
     let the_field = expect(tcx.diag,
         decoder::maybe_find_item(def.node, class_doc),
         || format!("get_field_type: in class {:?}, field ID {:?} not found",
                  class_id, def) );
-    debug!("got field data {:?}", the_field);
     let ty = decoder::item_type(def, the_field, tcx, cdata);
     ty::ty_param_bounds_and_ty {
         generics: ty::Generics {type_param_defs: @~[],
diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs
index fe9371af1fe..0fd92079489 100644
--- a/src/librustc/middle/borrowck/check_loans.rs
+++ b/src/librustc/middle/borrowck/check_loans.rs
@@ -231,34 +231,47 @@ impl<'a> CheckLoanCtxt<'a> {
             if restr.loan_path != loan2.loan_path { continue; }
 
             match (new_loan.mutbl, old_loan.mutbl) {
-                (MutableMutability, MutableMutability) => {
+                (_, MutableMutability) => {
+                    let var = self.bccx.loan_path_to_str(new_loan.loan_path);
                     self.bccx.span_err(
                         new_loan.span,
-                        format!("cannot borrow `{}` as mutable \
-                              more than once at a time",
-                             self.bccx.loan_path_to_str(new_loan.loan_path)));
+                        format!("cannot borrow `{}` because it is already \
+                                 borrowed as mutable", var));
                     self.bccx.span_note(
                         old_loan.span,
-                        format!("previous borrow of `{}` as mutable occurs here",
-                             self.bccx.loan_path_to_str(new_loan.loan_path)));
-                    return false;
+                        format!("previous borrow of `{0}` as mutable occurs \
+                                 here; the mutable borrow prevents subsequent \
+                                 moves, borrows, or modification of `{0}` \
+                                 until the borrow ends", var));
                 }
 
-                _ => {
+                (_, mutability) => {
                     self.bccx.span_err(
                         new_loan.span,
                         format!("cannot borrow `{}` as {} because \
-                              it is also borrowed as {}",
+                              it is already borrowed as {}",
                              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,
-                        format!("previous borrow of `{}` occurs here",
-                             self.bccx.loan_path_to_str(new_loan.loan_path)));
-                    return false;
+
+                    let var = self.bccx.loan_path_to_str(new_loan.loan_path);
+                    let mut note = format!("previous borrow of `{}` occurs \
+                                            here", var);
+                    if mutability == ImmutableMutability {
+                        note.push_str(format!("; the immutable borrow prevents \
+                                               subsequent moves or mutable
+                                               borrows of `{}` until the
+                                               borrow ends", var));
+                    }
+                    self.bccx.span_note(old_loan.span, note);
                 }
             }
+
+            let old_loan_span = ast_map::node_span(self.tcx().items,
+                                                   old_loan.kill_scope);
+            self.bccx.span_end_note(old_loan_span,
+                                    "previous borrow ends here");
+            return false;
         }
 
         true
diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs
index 74845878907..f1cccab1239 100644
--- a/src/librustc/middle/borrowck/mod.rs
+++ b/src/librustc/middle/borrowck/mod.rs
@@ -631,6 +631,10 @@ impl BorrowckCtxt {
         self.tcx.sess.span_note(s, m);
     }
 
+    pub fn span_end_note(&self, s: Span, m: &str) {
+        self.tcx.sess.span_end_note(s, m);
+    }
+
     pub fn bckerr_to_str(&self, err: BckError) -> ~str {
         match err.code {
             err_mutbl(lk) => {
diff --git a/src/librustc/middle/trans/cleanup.rs b/src/librustc/middle/trans/cleanup.rs
index 1f0e99de264..020b840e5b2 100644
--- a/src/librustc/middle/trans/cleanup.rs
+++ b/src/librustc/middle/trans/cleanup.rs
@@ -203,7 +203,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
          */
 
         let scopes = self.scopes.borrow();
-        for scope in scopes.get().iter().invert() {
+        for scope in scopes.get().iter().rev() {
             match scope.kind {
                 LoopScopeKind(id, _) => {
                     return id;
@@ -325,7 +325,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
                cleanup_scope);
 
         let mut scopes = self.scopes.borrow_mut();
-        for scope in scopes.get().mut_iter().invert() {
+        for scope in scopes.get().mut_iter().rev() {
             if scope.kind.is_ast_with_id(cleanup_scope) {
                 scope.cleanups.push(cleanup);
                 scope.clear_cached_exits();
@@ -368,7 +368,7 @@ impl<'a> CleanupMethods<'a> for FunctionContext<'a> {
          */
 
         let scopes = self.scopes.borrow();
-        scopes.get().iter().invert().any(|s| s.needs_invoke())
+        scopes.get().iter().rev().any(|s| s.needs_invoke())
     }
 
     fn get_landing_pad(&self) -> BasicBlockRef {
@@ -415,7 +415,7 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> {
          * Returns the id of the current top-most AST scope, if any.
          */
         let scopes = self.scopes.borrow();
-        for scope in scopes.get().iter().invert() {
+        for scope in scopes.get().iter().rev() {
             match scope.kind {
                 CustomScopeKind | LoopScopeKind(..) => {}
                 AstScopeKind(i) => {
@@ -428,7 +428,7 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> {
 
     fn top_nonempty_cleanup_scope(&self) -> Option<uint> {
         let scopes = self.scopes.borrow();
-        scopes.get().iter().invert().position(|s| !s.cleanups.is_empty())
+        scopes.get().iter().rev().position(|s| !s.cleanups.is_empty())
     }
 
     fn is_valid_to_pop_custom_scope(&self, custom_scope: CustomScopeIndex) -> bool {
@@ -450,7 +450,7 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> {
 
         let mut bcx = bcx;
         if !bcx.unreachable.get() {
-            for cleanup in scope.cleanups.iter().invert() {
+            for cleanup in scope.cleanups.iter().rev() {
                 bcx = cleanup.trans(bcx);
             }
         }
@@ -619,7 +619,7 @@ impl<'a> CleanupHelperMethods<'a> for FunctionContext<'a> {
                 debug!("generating cleanups for {}", name);
                 let bcx_in = self.new_block(label.is_unwind(), name, None);
                 let mut bcx_out = bcx_in;
-                for cleanup in scope.cleanups.iter().invert() {
+                for cleanup in scope.cleanups.iter().rev() {
                     if cleanup_is_suitable_for(*cleanup, label) {
                         bcx_out = cleanup.trans(bcx_out);
                     }
diff --git a/src/librustpkg/api.rs b/src/librustpkg/api.rs
index 19586ac48b0..13d5a117704 100644
--- a/src/librustpkg/api.rs
+++ b/src/librustpkg/api.rs
@@ -11,11 +11,9 @@
 use CtxMethods;
 use context::*;
 use crate::*;
-use crate_id::*;
 use package_source::*;
 use path_util::{platform_library_name, target_build_dir};
 use target::*;
-use version::Version;
 use workspace::pkg_parent_workspaces;
 use workcache_support::*;
 pub use path_util::default_workspace;
@@ -27,6 +25,7 @@ use extra::arc::{Arc,RWArc};
 use extra::workcache;
 use extra::workcache::{Database, FreshnessMap};
 use extra::treemap::TreeMap;
+use syntax::crateid::CrateId;
 
 // A little sad -- duplicated from rustc::back::*
 #[cfg(target_arch = "arm")]
@@ -79,20 +78,19 @@ pub fn new_workcache_context(p: &Path) -> workcache::Context {
     workcache::Context::new_with_freshness(db, cfg, Arc::new(freshness))
 }
 
-pub fn build_lib(sysroot: Path, root: Path, name: ~str, version: Version,
-                 lib: Path) {
-    build_lib_with_cfgs(sysroot, root, name, version, lib, ~[])
+pub fn build_lib(sysroot: Path, root: Path, name: ~str, lib: Path) {
+    build_lib_with_cfgs(sysroot, root, name, lib, ~[])
 }
 
-pub fn build_lib_with_cfgs(sysroot: Path, root: Path, name: ~str,
-                           version: Version, lib: Path, cfgs: ~[~str]) {
+pub fn build_lib_with_cfgs(sysroot: Path, root: Path, name: ~str, lib: Path, cfgs: ~[~str]) {
     let cx = default_context(sysroot, root.clone());
+    let crate_id: CrateId = from_str(name).expect("valid crate id");
     let pkg_src = PkgSrc {
         source_workspace: root.clone(),
         build_in_destination: false,
         destination_workspace: root.clone(),
         start_dir: root.join_many(["src", name.as_slice()]),
-        id: CrateId{ version: version, ..CrateId::new(name)},
+        id: crate_id,
         // n.b. This assumes the package only has one crate
         libs: ~[mk_crate(lib)],
         mains: ~[],
@@ -102,20 +100,19 @@ pub fn build_lib_with_cfgs(sysroot: Path, root: Path, name: ~str,
     pkg_src.build(&cx, cfgs, []);
 }
 
-pub fn build_exe(sysroot: Path, root: Path, name: ~str, version: Version,
-                 main: Path) {
-    build_exe_with_cfgs(sysroot, root, name, version, main, ~[])
+pub fn build_exe(sysroot: Path, root: Path, name: ~str, main: Path) {
+    build_exe_with_cfgs(sysroot, root, name, main, ~[])
 }
 
-pub fn build_exe_with_cfgs(sysroot: Path, root: Path, name: ~str,
-                           version: Version, main: Path, cfgs: ~[~str]) {
+pub fn build_exe_with_cfgs(sysroot: Path, root: Path, name: ~str, main: Path, cfgs: ~[~str]) {
     let cx = default_context(sysroot, root.clone());
+    let crate_id: CrateId = from_str(name).expect("valid crate id");
     let pkg_src = PkgSrc {
         source_workspace: root.clone(),
         build_in_destination: false,
         destination_workspace: root.clone(),
         start_dir: root.join_many(["src", name.as_slice()]),
-        id: CrateId{ version: version, ..CrateId::new(name)},
+        id: crate_id,
         libs: ~[],
         // n.b. This assumes the package only has one crate
         mains: ~[mk_crate(main)],
@@ -129,11 +126,10 @@ pub fn build_exe_with_cfgs(sysroot: Path, root: Path, name: ~str,
 pub fn install_pkg(cx: &BuildContext,
                    workspace: Path,
                    name: ~str,
-                   version: Version,
                    // For now, these inputs are assumed to be inputs to each of the crates
                    more_inputs: ~[(~str, Path)]) { // pairs of Kind and Path
-    let crateid = CrateId{ version: version, ..CrateId::new(name)};
-    cx.install(PkgSrc::new(workspace.clone(), workspace, false, crateid),
+    let crate_id: CrateId = from_str(name).expect("valid crate id");
+    cx.install(PkgSrc::new(workspace.clone(), workspace, false, crate_id),
                &WhatToBuild{ build_type: Inferred,
                              inputs_to_discover: more_inputs,
                              sources: Everything });
@@ -157,10 +153,10 @@ pub fn build_library_in_workspace(exec: &mut workcache::Exec,
     let out_name = workspace_build_dir.join_many([package_name.to_str(),
                                                   platform_library_name(output)]);
     // make paths absolute
-    let crateid = CrateId::new(package_name);
+    let crateid: CrateId = from_str(package_name).expect("valid crate id");
     let absolute_paths = paths.map(|s| {
             let whatever = workspace.join_many([~"src",
-                                crateid.to_str(),
+                                crateid.short_name_with_version(),
                                 s.to_owned()]);
             whatever.as_str().unwrap().to_owned()
         });
@@ -190,7 +186,7 @@ pub fn my_workspace(context: &Context, package_name: &str) -> Path {
     use bad_pkg_id     = conditions::bad_pkg_id::cond;
 
     // (this assumes no particular version is requested)
-    let crateid = CrateId::new(package_name);
+    let crateid = from_str(package_name).expect("valid crate id");
     let workspaces = pkg_parent_workspaces(context, &crateid);
     if workspaces.is_empty() {
         bad_pkg_id.raise((Path::new(package_name), package_name.to_owned()));
diff --git a/src/librustpkg/conditions.rs b/src/librustpkg/conditions.rs
index 6c38d63a518..d18161d7c4a 100644
--- a/src/librustpkg/conditions.rs
+++ b/src/librustpkg/conditions.rs
@@ -10,7 +10,7 @@
 
 // Useful conditions
 
-pub use crate_id::CrateId;
+pub use syntax::crateid::CrateId;
 pub use std::io::FileStat;
 pub use std::io::process::ProcessExit;
 pub use std::path::Path;
diff --git a/src/librustpkg/crate_id.rs b/src/librustpkg/crate_id.rs
deleted file mode 100644
index 239abbe546f..00000000000
--- a/src/librustpkg/crate_id.rs
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use version::{try_getting_version, try_getting_local_version,
-              Version, NoVersion, ExactRevision};
-use std::hash::Streaming;
-use std::hash;
-use syntax::crateid;
-
-/// Path-fragment identifier of a package such as
-/// 'github.com/graydon/test'; path must be a relative
-/// path with >=1 component.
-#[deriving(Clone)]
-pub struct CrateId {
-    /// This is a path, on the local filesystem, referring to where the
-    /// files for this package live. For example:
-    /// github.com/mozilla/quux-whatever (it's assumed that if we're
-    /// working with a package ID of this form, rustpkg has already cloned
-    /// the sources into a local directory in the RUST_PATH).
-    path: Path,
-    /// Short name. This is the path's filestem, but we store it
-    /// redundantly so as to not call get() everywhere (filestem() returns an
-    /// option)
-    /// The short name does not need to be a valid Rust identifier.
-    /// Users can write: `extern mod foo = "...";` to get around the issue
-    /// of package IDs whose short names aren't valid Rust identifiers.
-    short_name: ~str,
-    /// The requested package version.
-    version: Version
-}
-
-impl Eq for CrateId {
-    fn eq(&self, other: &CrateId) -> bool {
-        self.path == other.path && self.version == other.version
-    }
-}
-
-impl CrateId {
-    pub fn new(s: &str) -> CrateId {
-        use conditions::bad_pkg_id::cond;
-
-        let raw_crateid: Option<crateid::CrateId> = from_str(s);
-        if raw_crateid.is_none() {
-            return cond.raise((Path::new(s), ~"bad crateid"))
-        }
-        let raw_crateid = raw_crateid.unwrap();
-        let crateid::CrateId { path, name, version } = raw_crateid;
-        let path = Path::new(path);
-        let given_version = version.map(|v| ExactRevision(v));
-
-        let version = match given_version {
-            Some(v) => v,
-            None => match try_getting_local_version(&path) {
-                Some(v) => v,
-                None => match try_getting_version(&path) {
-                    Some(v) => v,
-                    None => NoVersion
-                }
-            }
-        };
-
-        CrateId {
-            path: path,
-            short_name: name,
-            version: version
-        }
-    }
-
-    pub fn hash(&self) -> ~str {
-        // FIXME (#9639): hash should take a &[u8] so we can hash the real path
-        self.path.display().with_str(|s| {
-            let vers = self.version.to_str();
-            format!("{}-{}-{}", s, hash(s + vers), vers)
-        })
-    }
-
-    pub fn short_name_with_version(&self) -> ~str {
-        format!("{}{}", self.short_name, self.version.to_str())
-    }
-
-    /// True if the ID has multiple components
-    pub fn is_complex(&self) -> bool {
-        self.short_name.as_bytes() != self.path.as_vec()
-    }
-
-    pub fn prefixes(&self) -> Prefixes {
-        prefixes(&self.path)
-    }
-
-    // This is the workcache function name for the *installed*
-    // binaries for this package (as opposed to the built ones,
-    // which are per-crate).
-    pub fn install_tag(&self) -> ~str {
-        format!("install({})", self.to_str())
-    }
-}
-
-pub fn prefixes(p: &Path) -> Prefixes {
-    Prefixes {
-        components: p.str_components().map(|x|x.unwrap().to_owned()).to_owned_vec(),
-        remaining: ~[]
-    }
-}
-
-struct Prefixes {
-    priv components: ~[~str],
-    priv remaining: ~[~str]
-}
-
-impl Iterator<(Path, Path)> for Prefixes {
-    #[inline]
-    fn next(&mut self) -> Option<(Path, Path)> {
-        if self.components.len() <= 1 {
-            None
-        }
-        else {
-            let last = self.components.pop().unwrap();
-            self.remaining.unshift(last);
-            // converting to str and then back is a little unfortunate
-            Some((Path::new(self.components.connect("/")),
-                  Path::new(self.remaining.connect("/"))))
-        }
-    }
-}
-
-impl ToStr for CrateId {
-    fn to_str(&self) -> ~str {
-        // should probably use the filestem and not the whole path
-        format!("{}-{}", self.path.as_str().unwrap(), self.version.to_str())
-    }
-}
-
-
-pub fn write<W: Writer>(writer: &mut W, string: &str) {
-    writer.write(string.as_bytes());
-}
-
-pub fn hash(data: ~str) -> ~str {
-    let hasher = &mut hash::default_state();
-    write(hasher, data);
-    hasher.result_str()
-}
-
diff --git a/src/librustpkg/installed_packages.rs b/src/librustpkg/installed_packages.rs
index 67ba5d2b8e8..c7900181a77 100644
--- a/src/librustpkg/installed_packages.rs
+++ b/src/librustpkg/installed_packages.rs
@@ -11,10 +11,10 @@
 // Listing installed packages
 
 use rustc::metadata::filesearch::rust_path;
-use path_util::*;
 use std::os;
 use std::io;
 use std::io::fs;
+use syntax::crateid::CrateId;
 
 pub fn list_installed_packages(f: |&CrateId| -> bool) -> bool  {
     let workspaces = rust_path();
@@ -28,7 +28,8 @@ pub fn list_installed_packages(f: |&CrateId| -> bool) -> bool  {
             match exec.filestem_str() {
                 None => (),
                 Some(exec_path) => {
-                    if !f(&CrateId::new(exec_path)) {
+                    let crate_id = from_str(exec_path).expect("valid crate id");
+                    if !f(&crate_id) {
                         return false;
                     }
                 }
@@ -50,7 +51,8 @@ pub fn list_installed_packages(f: |&CrateId| -> bool) -> bool  {
                     let rel_path = rel_p.join(basename);
                     rel_path.display().with_str(|s| {
                         debug!("Rel name: {}", s);
-                        f(&CrateId::new(s));
+                        let crate_id = from_str(s).expect("valid crate id");
+                        f(&crate_id);
                     });
                 }
                 None => ()
diff --git a/src/librustpkg/lib.rs b/src/librustpkg/lib.rs
index c9db8af0b8a..e5e494e9b5f 100644
--- a/src/librustpkg/lib.rs
+++ b/src/librustpkg/lib.rs
@@ -33,6 +33,7 @@ use rustc::metadata::filesearch;
 use rustc::metadata::filesearch::rust_path;
 use rustc::util::sha2;
 use syntax::{ast, diagnostic};
+use syntax::crateid::CrateId;
 use messages::{error, warn, note};
 use parse_args::{ParseResult, parse_args};
 use path_util::{build_pkg_id_in_workspace, built_test_in_workspace};
@@ -46,7 +47,6 @@ use context::{BuildContext, Trans, Nothing, Pretty, Analysis,
               LLVMAssemble, LLVMCompileBitcode};
 use context::{Command, BuildCmd, CleanCmd, DoCmd, HelpCmd, InfoCmd, InstallCmd, ListCmd,
     PreferCmd, TestCmd, InitCmd, UninstallCmd, UnpreferCmd};
-use crate_id::CrateId;
 use package_source::PkgSrc;
 use target::{WhatToBuild, Everything, is_lib, is_main, is_test, is_bench};
 use target::{Main, Tests, MaybeCustom, Inferred, JustOne};
@@ -60,7 +60,6 @@ mod crate;
 pub mod exit_codes;
 mod installed_packages;
 mod messages;
-pub mod crate_id;
 pub mod package_source;
 mod parse_args;
 mod path_util;
@@ -103,7 +102,7 @@ impl<'a> PkgScript<'a> {
                  workspace: &Path,
                  id: &'a CrateId) -> PkgScript<'a> {
         // Get the executable name that was invoked
-        let binary = os::args()[0].to_owned();
+        let binary = os::args()[0];
         // Build the rustc session data structures to pass
         // to the compiler
         debug!("pkgscript parse: {}", sysroot.display());
@@ -163,7 +162,6 @@ impl<'a> PkgScript<'a> {
         exe.as_str().unwrap().to_owned()
     }
 
-
     /// Run the contents of this package script, where <what>
     /// is the command to pass to it (e.g., "build", "clean", "install")
     /// Returns a pair of an exit code and list of configs (obtained by
@@ -243,9 +241,9 @@ impl CtxMethods for BuildContext {
 
         if args.len() < 1 {
             match cwd_to_workspace() {
-                None  if dir_has_crate_file(&cwd) => {
+                None if dir_has_crate_file(&cwd) => {
                     // FIXME (#9639): This needs to handle non-utf8 paths
-                    let crateid = CrateId::new(cwd.filename_str().unwrap());
+                    let crateid = from_str(cwd.filename_str().unwrap()).expect("valid crate id");
                     let mut pkg_src = PkgSrc::new(cwd, default_workspace(), true, crateid);
                     self.build(&mut pkg_src, what);
                     match pkg_src {
@@ -270,7 +268,7 @@ impl CtxMethods for BuildContext {
         } else {
             // The package id is presumed to be the first command-line
             // argument
-            let crateid = CrateId::new(args[0].clone());
+            let crateid = from_str(args[0]).expect("valid crate id");
             let mut dest_ws = default_workspace();
             each_pkg_parent_workspace(&self.context, &crateid, |workspace| {
                 debug!("found pkg {} in workspace {}, trying to build",
@@ -289,6 +287,7 @@ impl CtxMethods for BuildContext {
             Some((crateid, dest_ws))
         }
     }
+
     fn run(&self, cmd: Command, args: ~[~str]) {
         let cwd = os::getcwd();
         match cmd {
@@ -308,7 +307,7 @@ impl CtxMethods for BuildContext {
                 else {
                     // The package id is presumed to be the first command-line
                     // argument
-                    let crateid = CrateId::new(args[0].clone());
+                    let crateid = from_str(args[0]).expect("valid crate id");
                     self.clean(&cwd, &crateid); // tjc: should use workspace, not cwd
                 }
             }
@@ -341,7 +340,7 @@ impl CtxMethods for BuildContext {
                             // FIXME (#9639): This needs to handle non-utf8 paths
 
                             let inferred_crateid =
-                                CrateId::new(cwd.filename_str().unwrap());
+                                from_str(cwd.filename_str().unwrap()).expect("valid crate id");
                             self.install(PkgSrc::new(cwd, default_workspace(),
                                                      true, inferred_crateid),
                                          &WhatToBuild::new(MaybeCustom, Everything));
@@ -357,7 +356,7 @@ impl CtxMethods for BuildContext {
                 else {
                     // The package id is presumed to be the first command-line
                     // argument
-                    let crateid = CrateId::new(args[0]);
+                    let crateid = from_str(args[0]).expect("valid crate id");
                     let workspaces = pkg_parent_workspaces(&self.context, &crateid);
                     debug!("package ID = {}, found it in {:?} workspaces",
                            crateid.to_str(), workspaces.len());
@@ -383,7 +382,7 @@ impl CtxMethods for BuildContext {
             ListCmd => {
                 println!("Installed packages:");
                 installed_packages::list_installed_packages(|pkg_id| {
-                    pkg_id.path.display().with_str(|s| println!("{}", s));
+                    println!("{}", pkg_id.path);
                     true
                 });
             }
@@ -420,7 +419,7 @@ impl CtxMethods for BuildContext {
                     return usage::uninstall();
                 }
 
-                let crateid = CrateId::new(args[0]);
+                let crateid = from_str(args[0]).expect("valid crate id");
                 if !installed_packages::package_is_installed(&crateid) {
                     warn(format!("Package {} doesn't seem to be installed! \
                                   Doing nothing.", args[0]));
@@ -458,24 +457,24 @@ impl CtxMethods for BuildContext {
         let workspace = pkg_src.source_workspace.clone();
         let crateid = pkg_src.id.clone();
 
+        let path = crateid.path.as_slice();
         debug!("build: workspace = {} (in Rust path? {:?} is git dir? {:?} \
                 crateid = {} pkgsrc start_dir = {}", workspace.display(),
-               in_rust_path(&workspace), is_git_dir(&workspace.join(&crateid.path)),
+               in_rust_path(&workspace), is_git_dir(&workspace.join(path)),
                crateid.to_str(), pkg_src.start_dir.display());
         debug!("build: what to build = {:?}", what_to_build);
 
         // If workspace isn't in the RUST_PATH, and it's a git repo,
         // then clone it into the first entry in RUST_PATH, and repeat
-        if !in_rust_path(&workspace) && is_git_dir(&workspace.join(&crateid.path)) {
+        if !in_rust_path(&workspace) && is_git_dir(&workspace.join(path)) {
             let mut out_dir = default_workspace().join("src");
-            out_dir.push(&crateid.path);
-            let git_result = source_control::safe_git_clone(&workspace.join(&crateid.path),
+            out_dir.push(path);
+            let git_result = source_control::safe_git_clone(&workspace.join(path),
                                                             &crateid.version,
                                                             &out_dir);
             match git_result {
                 CheckedOutSources => make_read_only(&out_dir),
-                // FIXME (#9639): This needs to handle non-utf8 paths
-                _ => cond.raise((crateid.path.as_str().unwrap().to_owned(), out_dir.clone()))
+                _ => cond.raise((path.to_owned(), out_dir.clone()))
             };
             let default_ws = default_workspace();
             debug!("Calling build recursively with {:?} and {:?}", default_ws.display(),
@@ -652,7 +651,8 @@ impl CtxMethods for BuildContext {
                target_exec.display(), target_lib,
                maybe_executable, maybe_library);
 
-        self.workcache_context.with_prep(id.install_tag(), |prep| {
+        let install_tag = format!("install({}-{})", id.path, id.version_or_default());
+        self.workcache_context.with_prep(install_tag, |prep| {
             for ee in maybe_executable.iter() {
                 // FIXME (#9639): This needs to handle non-utf8 paths
                 prep.declare_input("binary",
diff --git a/src/librustpkg/package_source.rs b/src/librustpkg/package_source.rs
index 651d64aa9d3..5ac62c5284e 100644
--- a/src/librustpkg/package_source.rs
+++ b/src/librustpkg/package_source.rs
@@ -11,7 +11,6 @@
 extern mod extra;
 
 use target::*;
-use crate_id::CrateId;
 use std::io;
 use std::io::fs;
 use std::os;
@@ -27,7 +26,7 @@ use workcache_support;
 use workcache_support::{digest_only_date, digest_file_with_date, crate_tag};
 use extra::workcache;
 use extra::treemap::TreeMap;
-
+use syntax::crateid::CrateId;
 use rustc::driver::session;
 
 // An enumeration of the unpacked source of a package workspace.
@@ -68,12 +67,38 @@ impl ToStr for PkgSrc {
     }
 }
 condition! {
-    // #6009: should this be pub or not, when #8215 is fixed?
     build_err: (~str) -> ~str;
 }
 
-impl PkgSrc {
+fn prefixes(p: &Path) -> Prefixes {
+    Prefixes {
+        components: p.str_components().map(|x|x.unwrap().to_owned()).to_owned_vec(),
+        remaining: ~[]
+    }
+}
+
+struct Prefixes {
+    priv components: ~[~str],
+    priv remaining: ~[~str]
+}
+
+impl Iterator<(Path, Path)> for Prefixes {
+    #[inline]
+    fn next(&mut self) -> Option<(Path, Path)> {
+        if self.components.len() <= 1 {
+            None
+        }
+        else {
+            let last = self.components.pop().unwrap();
+            self.remaining.unshift(last);
+            // converting to str and then back is a little unfortunate
+            Some((Path::new(self.components.connect("/")),
+                  Path::new(self.remaining.connect("/"))))
+        }
+    }
+}
 
+impl PkgSrc {
     pub fn new(mut source_workspace: Path,
                destination_workspace: Path,
                use_rust_path_hack: bool,
@@ -98,21 +123,22 @@ impl PkgSrc {
         } else {
             // We search for sources under both src/ and build/ , because build/ is where
             // automatically-checked-out sources go.
+            let path = Path::new(id.path.as_slice());
             let mut result = source_workspace.join("src");
-            result.push(&id.path.dir_path());
-            result.push(format!("{}-{}", id.short_name, id.version.to_str()));
+            result.push(&path.dir_path());
+            result.push(id.short_name_with_version());
             to_try.push(result);
             let mut result = source_workspace.join("src");
-            result.push(&id.path);
+            result.push(&path);
             to_try.push(result);
 
             let mut result = build_dir.join("src");
-            result.push(&id.path.dir_path());
-            result.push(format!("{}-{}", id.short_name, id.version.to_str()));
+            result.push(&path.dir_path());
+            result.push(id.short_name_with_version());
             to_try.push(result.clone());
             output_names.push(result);
             let mut other_result = build_dir.join("src");
-            other_result.push(&id.path);
+            other_result.push(&path);
             to_try.push(other_result.clone());
             output_names.push(other_result);
 
@@ -132,9 +158,10 @@ impl PkgSrc {
             None => {
                 // See if any of the prefixes of this package ID form a valid package ID
                 // That is, is this a package ID that points into the middle of a workspace?
-                for (prefix, suffix) in id.prefixes() {
-                    let crate_id = CrateId::new(prefix.as_str().unwrap());
-                    let path = build_dir.join(&crate_id.path);
+                for (prefix, suffix) in prefixes(&Path::new(id.path.as_slice())) {
+                    let crate_id: Option<CrateId> = from_str(prefix.as_str().unwrap());
+                    let crate_id = crate_id.expect("valid crate id");
+                    let path = build_dir.join(crate_id.path.as_slice());
                     debug!("in loop: checking if {} is a directory", path.display());
                     if path.is_dir() {
                         let ps = PkgSrc::new(source_workspace,
@@ -163,7 +190,7 @@ impl PkgSrc {
                             }
                         }
 
-                    };
+                    }
                 }
 
                 // Ok, no prefixes work, so try fetching from git
@@ -179,11 +206,12 @@ impl PkgSrc {
                     }
                     match ok_d {
                         Some(ref d) => {
-                            if d.is_ancestor_of(&id.path)
-                                || d.is_ancestor_of(&versionize(&id.path, &id.version)) {
+                            let path = Path::new(id.path.as_slice());
+                            if d.is_ancestor_of(&path)
+                                || d.is_ancestor_of(&versionize(id.path, &id.version)) {
                                 // Strip off the package ID
                                 source_workspace = d.clone();
-                                for _ in id.path.components() {
+                                for _ in path.components() {
                                     source_workspace.pop();
                                 }
                                 // Strip off the src/ part
@@ -226,8 +254,7 @@ impl PkgSrc {
                                         exist, and couldn't interpret it as a URL fragment"))
                                 }
                             }
-                        }
-                        else {
+                        } else {
                             cond.raise((id.clone(),
                                 ~"supplied path for package dir does not \
                                 exist, and couldn't interpret it as a URL fragment"))
@@ -268,26 +295,27 @@ impl PkgSrc {
         use conditions::git_checkout_failed::cond;
 
         let cwd = os::getcwd();
+        let path = Path::new(crateid.path.as_slice());
         debug!("Checking whether {} (path = {}) exists locally. Cwd = {}, does it? {:?}",
-                crateid.to_str(), crateid.path.display(),
+                crateid.to_str(), crateid.path,
                 cwd.display(),
-                crateid.path.exists());
+                path.exists());
 
-        match safe_git_clone(&crateid.path, &crateid.version, local) {
+        match safe_git_clone(&path, &crateid.version, local) {
             CheckedOutSources => {
                 make_read_only(local);
                 Some(local.clone())
             }
             DirToUse(clone_target) => {
-                if crateid.path.components().nth(1).is_none() {
+                if path.components().nth(1).is_none() {
                     // If a non-URL, don't bother trying to fetch
                     return None;
                 }
 
                 // FIXME (#9639): This needs to handle non-utf8 paths
-                let url = format!("https://{}", crateid.path.as_str().unwrap());
+                let url = format!("https://{}", path.as_str().unwrap());
                 debug!("Fetching package: git clone {} {} [version={}]",
-                        url, clone_target.display(), crateid.version.to_str());
+                        url, clone_target.display(), crateid.version_or_default());
 
                 let mut failed = false;
 
@@ -345,7 +373,7 @@ impl PkgSrc {
         use conditions::missing_pkg_files::cond;
 
         let prefix = self.start_dir.components().len();
-        debug!("Matching against {}", self.id.short_name);
+        debug!("Matching against {}", self.id.name);
         for pth in fs::walk_dir(&self.start_dir) {
             let maybe_known_crate_set = match pth.filename_str() {
                 Some(filename) if filter(filename) => match filename {
diff --git a/src/librustpkg/path_util.rs b/src/librustpkg/path_util.rs
index 3c91e660784..a0d49e7565f 100644
--- a/src/librustpkg/path_util.rs
+++ b/src/librustpkg/path_util.rs
@@ -12,19 +12,20 @@
 
 #[allow(dead_code)];
 
-pub use crate_id::CrateId;
 pub use target::{OutputType, Main, Lib, Test, Bench, Target, Build, Install};
-pub use version::{Version, ExactRevision, NoVersion, split_version, split_version_general,
-    try_parsing_version};
+pub use version::{Version, split_version_general};
 pub use rustc::metadata::filesearch::rust_path;
-use rustc::metadata::filesearch::{libdir, relative_target_lib_path};
-use rustc::driver::driver::host_triple;
 
 use std::libc;
 use std::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
 use std::os;
 use std::io;
 use std::io::fs;
+use extra::hex::ToHex;
+use syntax::crateid::CrateId;
+use rustc::util::sha2::{Digest, Sha256};
+use rustc::metadata::filesearch::{libdir, relative_target_lib_path};
+use rustc::driver::driver::host_triple;
 use messages::*;
 
 pub fn default_workspace() -> Path {
@@ -78,14 +79,14 @@ pub fn workspace_contains_crate_id_(crateid: &CrateId, workspace: &Path,
     let mut found = None;
     for p in fs::walk_dir(&src_dir) {
         if p.is_dir() {
-            if p == src_dir.join(&crateid.path) || {
+            if p == src_dir.join(crateid.path.as_slice()) || {
                 let pf = p.filename_str();
                 pf.iter().any(|&g| {
                     match split_version_general(g, '-') {
                         None => false,
                         Some((ref might_match, ref vers)) => {
-                            *might_match == crateid.short_name
-                                && (crateid.version == *vers || crateid.version == NoVersion)
+                            *might_match == crateid.name
+                                && (crateid.version == *vers || crateid.version == None)
                         }
                     }
                 })
@@ -173,151 +174,63 @@ fn output_in_workspace(crateid: &CrateId, workspace: &Path, what: OutputType) ->
 /// Figure out what the library name for <crateid> in <workspace>'s build
 /// directory is, and if the file exists, return it.
 pub fn built_library_in_workspace(crateid: &CrateId, workspace: &Path) -> Option<Path> {
-    library_in_workspace(&crateid.path, crateid.short_name, Build, workspace, "build",
-                         &crateid.version)
+    library_in_workspace(crateid, Build, workspace)
 }
 
 /// Does the actual searching stuff
-pub fn installed_library_in_workspace(pkg_path: &Path, workspace: &Path) -> Option<Path> {
+pub fn installed_library_in_workspace(crate_id: &CrateId, workspace: &Path) -> Option<Path> {
     // This could break once we're handling multiple versions better -- I should add a test for it
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    match pkg_path.filename_str() {
+    let path = Path::new(crate_id.path.as_slice());
+    match path.filename_str() {
         None => None,
-        Some(short_name) => library_in_workspace(pkg_path,
-                                                 short_name,
-                                                 Install,
-                                                 workspace,
-                                                 libdir(),
-                                                 &NoVersion)
+        Some(_short_name) => library_in_workspace(crate_id, Install, workspace)
     }
 }
 
 /// `workspace` is used to figure out the directory to search.
-/// `short_name` is taken as the link name of the library.
-pub fn library_in_workspace(path: &Path, short_name: &str, where: Target,
-                        workspace: &Path, prefix: &str, version: &Version) -> Option<Path> {
+/// `name` is taken as the link name of the library.
+pub fn library_in_workspace(crate_id: &CrateId, where: Target, workspace: &Path) -> Option<Path> {
     debug!("library_in_workspace: checking whether a library named {} exists",
-           short_name);
-
-    // We don't know what the hash is, so we have to search through the directory
-    // contents
-
-    debug!("short_name = {} where = {:?} workspace = {} \
-            prefix = {}", short_name, where, workspace.display(), prefix);
+           crate_id.name);
 
     let dir_to_search = match where {
-        Build => target_build_dir(workspace).join(path),
+        Build => target_build_dir(workspace).join(crate_id.path.as_slice()),
         Install => target_lib_dir(workspace)
     };
 
-    library_in(short_name, version, &dir_to_search)
+    library_in(crate_id, &dir_to_search)
 }
 
-pub fn system_library(sysroot: &Path, crate_id: &str) -> Option<Path> {
-    let (lib_name, version) = split_crate_id(crate_id);
-    library_in(lib_name, &version, &sysroot.join(relative_target_lib_path(host_triple())))
+pub fn system_library(sysroot: &Path, crate_id: &CrateId) -> Option<Path> {
+    library_in(crate_id, &sysroot.join(relative_target_lib_path(host_triple())))
 }
 
-fn library_in(short_name: &str, version: &Version, dir_to_search: &Path) -> Option<Path> {
-    debug!("Listing directory {}", dir_to_search.display());
-    let dir_contents = {
-        let _guard = io::ignore_io_error();
-        fs::readdir(dir_to_search)
-    };
-    debug!("dir has {:?} entries", dir_contents.len());
-
-    let dll_prefix = format!("{}{}", os::consts::DLL_PREFIX, short_name);
-    let dll_filetype = os::consts::DLL_EXTENSION;
-    let rlib_prefix = format!("{}{}", "lib", short_name);
-    let rlib_filetype = "rlib";
-
-    debug!("dll_prefix = {} and dll_filetype = {}", dll_prefix, dll_filetype);
-    debug!("rlib_prefix = {} and rlib_filetype = {}", rlib_prefix, rlib_filetype);
-
-    // Find a filename that matches the pattern:
-    // (lib_prefix)-hash-(version)(lib_suffix)
-    let mut libraries = dir_contents.iter().filter(|p| {
-        let extension = p.extension_str();
-        debug!("p = {}, p's extension is {:?}", p.display(), extension);
-        match extension {
-            None => false,
-            Some(ref s) => dll_filetype == *s || rlib_filetype == *s,
-        }
-    });
-
-    let mut result_filename = None;
-    for p_path in libraries {
-        // Find a filename that matches the pattern: (lib_prefix)-hash-(version)(lib_suffix)
-        // and remember what the hash was
-        let mut f_name = match p_path.filestem_str() {
-            Some(s) => s, None => continue
-        };
-        // Already checked the filetype above
-
-         // This is complicated because library names and versions can both contain dashes
-         loop {
-            if f_name.is_empty() { break; }
-            match f_name.rfind('-') {
-                Some(i) => {
-                    debug!("Maybe {} is a version", f_name.slice(i + 1, f_name.len()));
-                    match try_parsing_version(f_name.slice(i + 1, f_name.len())) {
-                        Some(ref found_vers) if version == found_vers => {
-                            match f_name.slice(0, i).rfind('-') {
-                                Some(j) => {
-                                    let lib_prefix = match p_path.extension_str() {
-                                        Some(ref s) if dll_filetype == *s => &dll_prefix,
-                                        _ => &rlib_prefix,
-                                    };
-                                    debug!("Maybe {} equals {}", f_name.slice(0, j), *lib_prefix);
-                                    if f_name.slice(0, j) == *lib_prefix {
-                                        result_filename = Some(p_path.clone());
-                                    }
-                                    break;
-                                }
-                                None => break
-                            }
-
-                       }
-                       _ => { f_name = f_name.slice(0, i); }
-                 }
-               }
-               None => break
-         } // match
-       } // loop
-    } // for
-
-    if result_filename.is_none() {
-        debug!("warning: library_in_workspace didn't find a library in {} for {}",
-                  dir_to_search.display(), short_name);
-    }
+fn library_in(crate_id: &CrateId, dir_to_search: &Path) -> Option<Path> {
+    let mut hasher = Sha256::new();
+    hasher.reset();
+    hasher.input_str(crate_id.to_str());
+    let hash = hasher.result_bytes().to_hex();
+    let hash = hash.slice_chars(0, 8);
+
+    let lib_name = format!("{}-{}-{}", crate_id.name, hash, crate_id.version_or_default());
+    let filenames = [
+        format!("{}{}.{}", "lib", lib_name, "rlib"),
+        format!("{}{}{}", os::consts::DLL_PREFIX, lib_name, os::consts::DLL_SUFFIX),
+    ];
 
-    // Return the filename that matches, which we now know exists
-    // (if result_filename != None)
-    let abs_path = result_filename.map(|result_filename| {
-        let absolute_path = dir_to_search.join(&result_filename);
-        debug!("result_filename = {}", absolute_path.display());
-        absolute_path
-    });
-
-    abs_path
-}
-
-fn split_crate_id<'a>(crate_id: &'a str) -> (&'a str, Version) {
-    match split_version(crate_id) {
-        Some((name, vers)) =>
-            match vers {
-                ExactRevision(ref v) => match v.find('-') {
-                    Some(pos) => (name, ExactRevision(v.slice(0, pos).to_owned())),
-                    None => (name, ExactRevision(v.to_owned()))
-                },
-                _ => (name, vers)
-            },
-        None => (crate_id, NoVersion)
+    for filename in filenames.iter() {
+        debug!("filename = {}", filename.as_slice());
+        let path = dir_to_search.join(filename.as_slice());
+        if path.exists() {
+            debug!("found: {}", path.display());
+            return Some(path);
+        }
     }
+    debug!("warning: library_in_workspace didn't find a library in {} for {}",
+           dir_to_search.display(), crate_id.to_str());
+    return None;
 }
 
-
-
 /// Returns the executable that would be installed for <crateid>
 /// in <workspace>
 /// As a side effect, creates the bin-dir if it doesn't exist
@@ -366,7 +279,7 @@ fn target_file_in_workspace(crateid: &CrateId, workspace: &Path,
     // Artifacts in the build directory live in a package-ID-specific subdirectory,
     // but installed ones don't.
     let result = match (where, what) {
-                (Build, _)      => target_build_dir(workspace).join(&crateid.path),
+                (Build, _)      => target_build_dir(workspace).join(crateid.path.as_slice()),
                 (Install, Lib)  => target_lib_dir(workspace),
                 (Install, _)    => target_bin_dir(workspace)
     };
@@ -382,7 +295,7 @@ fn target_file_in_workspace(crateid: &CrateId, workspace: &Path,
 /// Creates it if it doesn't exist.
 pub fn build_pkg_id_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
     let mut result = target_build_dir(workspace);
-    result.push(&crateid.path);
+    result.push(crateid.path.as_slice());
     debug!("Creating build dir {} for package id {}", result.display(),
            crateid.to_str());
     fs::mkdir_recursive(&result, io::UserRWX);
@@ -392,25 +305,24 @@ pub fn build_pkg_id_in_workspace(crateid: &CrateId, workspace: &Path) -> Path {
 /// Return the output file for a given directory name,
 /// given whether we're building a library and whether we're building tests
 pub fn mk_output_path(what: OutputType, where: Target,
-                      pkg_id: &CrateId, workspace: Path) -> Path {
-    let short_name_with_version = format!("{}-{}", pkg_id.short_name,
-                                          pkg_id.version.to_str());
+                      crate_id: &CrateId, workspace: Path) -> Path {
+    let short_name_with_version = crate_id.short_name_with_version();
     // Not local_path.dir_path()! For package foo/bar/blat/, we want
     // the executable blat-0.5 to live under blat/
     let dir = match where {
         // If we're installing, it just goes under <workspace>...
         Install => workspace,
         // and if we're just building, it goes in a package-specific subdir
-        Build => workspace.join(&pkg_id.path)
+        Build => workspace.join(crate_id.path.as_slice())
     };
-    debug!("[{:?}:{:?}] mk_output_path: short_name = {}, path = {}", what, where,
-           if what == Lib { short_name_with_version.clone() } else { pkg_id.short_name.clone() },
+    debug!("[{:?}:{:?}] mk_output_path: name = {}, path = {}", what, where,
+           if what == Lib { short_name_with_version.clone() } else { crate_id.name.clone() },
            dir.display());
     let mut output_path = match what {
         // this code is duplicated from elsewhere; fix this
         Lib => dir.join(os::dll_filename(short_name_with_version)),
         // executable names *aren't* versioned
-        _ => dir.join(format!("{}{}{}", pkg_id.short_name,
+        _ => dir.join(format!("{}{}{}", crate_id.name,
                            match what {
                                Test => "test",
                                Bench => "bench",
@@ -457,11 +369,12 @@ fn dir_has_file(dir: &Path, file: &str) -> bool {
 
 pub fn find_dir_using_rust_path_hack(p: &CrateId) -> Option<Path> {
     let rp = rust_path();
+    let path = Path::new(p.path.as_slice());
     for dir in rp.iter() {
         // Require that the parent directory match the package ID
         // Note that this only matches if the package ID being searched for
         // has a name that's a single component
-        if dir.ends_with_path(&p.path) || dir.ends_with_path(&versionize(&p.path, &p.version)) {
+        if dir.ends_with_path(&path) || dir.ends_with_path(&versionize(p.path, &p.version)) {
             debug!("In find_dir_using_rust_path_hack: checking dir {}", dir.display());
             if dir_has_crate_file(dir) {
                 debug!("Did find id {} in dir {}", p.to_str(), dir.display());
@@ -483,11 +396,12 @@ pub fn user_set_rust_path() -> bool {
 }
 
 /// Append the version string onto the end of the path's filename
-pub fn versionize(p: &Path, v: &Version) -> Path {
+pub fn versionize(p: &str, v: &Version) -> Path {
+    let p = Path::new(p);
     let q = p.filename().expect("path is a directory");
     let mut q = q.to_owned();
     q.push('-' as u8);
-    let vs = v.to_str();
+    let vs = match v { &Some(ref s) => s.to_owned(), &None => ~"0.0" };
     q.push_all(vs.as_bytes());
     p.with_filename(q)
 }
diff --git a/src/librustpkg/source_control.rs b/src/librustpkg/source_control.rs
index 4b7aaf7e340..2346749feb5 100644
--- a/src/librustpkg/source_control.rs
+++ b/src/librustpkg/source_control.rs
@@ -14,7 +14,6 @@ use std::{run, str};
 use std::run::{ProcessOutput, ProcessOptions, Process};
 use std::io::fs;
 use extra::tempfile::TempDir;
-use version::*;
 use path_util::chmod_read_only;
 
 /// Attempts to clone `source`, a local git repository, into `target`, a local
@@ -22,7 +21,7 @@ use path_util::chmod_read_only;
 /// Returns `DirToUse(p)` if the clone fails, where `p` is a newly created temporary
 /// directory (that the callee may use, for example, to check out remote sources into).
 /// Returns `CheckedOutSources` if the clone succeeded.
-pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult {
+pub fn safe_git_clone(source: &Path, v: &Option<~str>, target: &Path) -> CloneResult {
     if source.exists() {
         debug!("{} exists locally! Cloning it into {}",
                 source.display(), target.display());
@@ -44,7 +43,7 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult
             }
             else {
                 match v {
-                    &ExactRevision(ref s) => {
+                    &Some(ref s) => {
                         let git_dir = target.join(".git");
                         debug!("`Running: git --work-tree={} --git-dir={} checkout {}",
                                 *s, target.display(), git_dir.display());
@@ -65,7 +64,7 @@ pub fn safe_git_clone(source: &Path, v: &Version, target: &Path) -> CloneResult
         } else {
             // Check that no version was specified. There's no reason to not handle the
             // case where a version was requested, but I haven't implemented it.
-            assert!(*v == NoVersion);
+            assert!(*v == None);
             let git_dir = target.join(".git");
             debug!("Running: git --work-tree={} --git-dir={} pull --no-edit {}",
                     target.display(), git_dir.display(), source.display());
@@ -106,7 +105,7 @@ pub fn make_read_only(target: &Path) {
 }
 
 /// Source can be either a URL or a local file path.
-pub fn git_clone_url(source: &str, target: &Path, v: &Version) {
+pub fn git_clone_url(source: &str, target: &Path, v: &Option<~str>) {
     use conditions::git_checkout_failed::cond;
 
     // FIXME (#9639): This needs to handle non-utf8 paths
@@ -120,7 +119,7 @@ pub fn git_clone_url(source: &str, target: &Path, v: &Version) {
     }
     else {
         match v {
-            &ExactRevision(ref s) | &Tagged(ref s) => {
+            &Some(ref s) => {
                     let opt_outp = process_output_in_cwd("git", [~"checkout", s.to_owned()],
                                                          target);
                     let outp = opt_outp.expect("Failed to exec `git`");
diff --git a/src/librustpkg/tests.rs b/src/librustpkg/tests.rs
index c0b4a246d35..bf8ec1e738c 100644
--- a/src/librustpkg/tests.rs
+++ b/src/librustpkg/tests.rs
@@ -20,13 +20,12 @@ use extra::arc::Arc;
 use extra::arc::RWArc;
 use extra::tempfile::TempDir;
 use extra::workcache;
-use extra::workcache::{Database};
+use extra::workcache::Database;
 use extra::treemap::TreeMap;
 use extra::getopts::groups::getopts;
 use std::run::ProcessOutput;
 use installed_packages::list_installed_packages;
-use crate_id::{CrateId};
-use version::{ExactRevision, NoVersion, Version};
+use syntax::crateid::CrateId;
 use path_util::{target_executable_in_workspace, target_test_in_workspace,
                target_bench_in_workspace, make_dir_rwx,
                library_in_workspace, installed_library_in_workspace,
@@ -59,19 +58,18 @@ fn fake_ctxt(sysroot: Path, workspace: &Path) -> BuildContext {
 }
 
 fn fake_pkg() -> CrateId {
-    let sn = ~"bogus";
     CrateId {
-        path: Path::new(sn.as_slice()),
-        short_name: sn,
-        version: NoVersion
+        path: ~"bogus",
+        name: ~"bogus",
+        version: None
     }
 }
 
 fn git_repo_pkg() -> CrateId {
     CrateId {
-        path: Path::new("mockgithub.com/catamorphism/test-pkg"),
-        short_name: ~"test-pkg",
-        version: NoVersion
+        path: ~"mockgithub.com/catamorphism/test-pkg",
+        name: ~"test-pkg",
+        version: None
     }
 }
 
@@ -88,28 +86,24 @@ fn mk_emptier_workspace(tag: &str) -> TempDir {
     workspace
 }
 
-fn mk_empty_workspace(short_name: &Path, version: &Version, tag: &str) -> TempDir {
+fn mk_empty_workspace(crate_id: &CrateId, tag: &str) -> TempDir {
     let workspace_dir = TempDir::new(tag).expect("couldn't create temp dir");
-    mk_workspace(workspace_dir.path(), short_name, version);
+    mk_workspace(workspace_dir.path(), crate_id);
     workspace_dir
 }
 
-fn mk_workspace(workspace: &Path, short_name: &Path, version: &Version) -> Path {
+fn mk_workspace(workspace: &Path, crate_id: &CrateId) -> Path {
     // include version number in directory name
     // FIXME (#9639): This needs to handle non-utf8 paths
-    let package_dir = workspace.join_many([~"src", format!("{}-{}",
-                                           short_name.as_str().unwrap(), version.to_str())]);
+    let package_dir = workspace.join_many([~"src", crate_id.short_name_with_version()]);
     fs::mkdir_recursive(&package_dir, io::UserRWX);
     package_dir
 }
 
-fn mk_temp_workspace(short_name: &Path, version: &Version) -> (TempDir, Path) {
-    let workspace_dir = mk_empty_workspace(short_name, version, "temp_workspace");
+fn mk_temp_workspace(crate_id: &CrateId) -> (TempDir, Path) {
+    let workspace_dir = mk_empty_workspace(crate_id, "temp_workspace");
     // FIXME (#9639): This needs to handle non-utf8 paths
-    let package_dir = workspace_dir.path().join_many([~"src",
-                                                      format!("{}-{}",
-                                                              short_name.as_str().unwrap(),
-                                                              version.to_str())]);
+    let package_dir = workspace_dir.path().join_many([~"src", crate_id.short_name_with_version()]);
 
     debug!("Created {} and does it exist? {:?}", package_dir.display(),
            package_dir.is_dir());
@@ -278,14 +272,11 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s
         err_fd: None
     }).expect(format!("failed to exec `{}`", cmd));
     let output = prog.finish_with_output();
-    debug!("Output from command {} with args {:?} was {} \\{{}\\}[{:?}]",
+    debug!("Output from command {} with args {:?} was --- {} \\{{}\\} --- [{:?}]",
            cmd, args, str::from_utf8(output.output).unwrap(),
            str::from_utf8(output.error).unwrap(),
            output.status);
     if !output.status.success() {
-        debug!("Command {} {:?} failed with exit code {:?}; its output was --- {} {} ---",
-              cmd, args, output.status,
-              str::from_utf8(output.output).unwrap(), str::from_utf8(output.error).unwrap());
         Fail(output)
     }
     else {
@@ -294,7 +285,7 @@ fn command_line_test_with_env(args: &[~str], cwd: &Path, env: Option<~[(~str, ~s
 }
 
 fn create_local_package(crateid: &CrateId) -> TempDir {
-    let (workspace, parent_dir) = mk_temp_workspace(&crateid.path, &crateid.version);
+    let (workspace, parent_dir) = mk_temp_workspace(crateid);
     debug!("Created empty package dir for {}, returning {}", crateid.to_str(),
            parent_dir.display());
     workspace
@@ -302,7 +293,7 @@ fn create_local_package(crateid: &CrateId) -> TempDir {
 
 fn create_local_package_in(crateid: &CrateId, pkgdir: &Path) -> Path {
 
-    let package_dir = pkgdir.join_many([~"src", crateid.to_str()]);
+    let package_dir = pkgdir.join_many([~"src", crateid.short_name_with_version()]);
 
     // Create main, lib, test, and bench files
     fs::mkdir_recursive(&package_dir, io::UserRWX);
@@ -330,11 +321,15 @@ fn create_local_package_with_dep(crateid: &CrateId, subord_crateid: &CrateId) ->
     let package_dir = create_local_package(crateid);
     create_local_package_in(subord_crateid, package_dir.path());
     // Write a main.rs file into crateid that references subord_crateid
-    writeFile(&package_dir.path().join_many([~"src", crateid.to_str(), ~"main.rs"]),
+    writeFile(&package_dir.path().join_many([~"src",
+                                             crateid.short_name_with_version(),
+                                             ~"main.rs"]),
               format!("extern mod {};\nfn main() \\{\\}",
-                   subord_crateid.short_name));
+                   subord_crateid.name));
     // Write a lib.rs file into subord_crateid that has something in it
-    writeFile(&package_dir.path().join_many([~"src", subord_crateid.to_str(), ~"lib.rs"]),
+    writeFile(&package_dir.path().join_many([~"src",
+                                             subord_crateid.short_name_with_version(),
+                                             ~"lib.rs"]),
               "pub fn f() {}");
     package_dir
 }
@@ -348,13 +343,13 @@ fn create_local_package_with_custom_build_hook(crateid: &CrateId,
 
 }
 
-fn assert_lib_exists(repo: &Path, pkg_path: &Path, v: Version) {
-    assert!(lib_exists(repo, pkg_path, v));
+fn assert_lib_exists(repo: &Path, crate_id: &CrateId) {
+    assert!(lib_exists(repo, crate_id));
 }
 
-fn lib_exists(repo: &Path, pkg_path: &Path, _v: Version) -> bool { // ??? version?
-    debug!("assert_lib_exists: repo = {}, pkg_path = {}", repo.display(), pkg_path.display());
-    let lib = installed_library_in_workspace(pkg_path, repo);
+fn lib_exists(repo: &Path, crate_id: &CrateId) -> bool {
+    debug!("assert_lib_exists: repo = {}, crate_id = {}", repo.display(), crate_id.to_str());
+    let lib = installed_library_in_workspace(crate_id, repo);
     debug!("assert_lib_exists: checking whether {:?} exists", lib);
     lib.is_some() && {
         let libname = lib.get_ref();
@@ -367,19 +362,21 @@ fn assert_executable_exists(repo: &Path, short_name: &str) {
 }
 
 fn executable_exists(repo: &Path, short_name: &str) -> bool {
+    let crate_id = from_str(short_name).expect("valid crate id");
     debug!("executable_exists: repo = {}, short_name = {}", repo.display(), short_name);
-    let exec = target_executable_in_workspace(&CrateId::new(short_name), repo);
+    let exec = target_executable_in_workspace(&crate_id, repo);
     exec.exists() && is_rwx(&exec)
 }
 
 fn test_executable_exists(repo: &Path, short_name: &str) -> bool {
+    let crate_id = from_str(short_name).expect("valid crate id");
     debug!("test_executable_exists: repo = {}, short_name = {}", repo.display(), short_name);
-    let exec = built_test_in_workspace(&CrateId::new(short_name), repo);
+    let exec = built_test_in_workspace(&crate_id, repo);
     exec.map_or(false, |exec| exec.exists() && is_rwx(&exec))
 }
 
 fn remove_executable_file(p: &CrateId, workspace: &Path) {
-    let exec = target_executable_in_workspace(&CrateId::new(p.short_name), workspace);
+    let exec = target_executable_in_workspace(p, workspace);
     if exec.exists() {
         fs::unlink(&exec);
     }
@@ -392,7 +389,8 @@ fn assert_built_executable_exists(repo: &Path, short_name: &str) {
 fn built_executable_exists(repo: &Path, short_name: &str) -> bool {
     debug!("assert_built_executable_exists: repo = {}, short_name = {}",
             repo.display(), short_name);
-    let exec = built_executable_in_workspace(&CrateId::new(short_name), repo);
+    let crate_id = from_str(short_name).expect("valid crate id");
+    let exec = built_executable_in_workspace(&crate_id, repo);
     exec.is_some() && {
        let execname = exec.get_ref();
        execname.exists() && is_rwx(execname)
@@ -400,7 +398,7 @@ fn built_executable_exists(repo: &Path, short_name: &str) -> bool {
 }
 
 fn remove_built_executable_file(p: &CrateId, workspace: &Path) {
-    let exec = built_executable_in_workspace(&CrateId::new(p.short_name), workspace);
+    let exec = built_executable_in_workspace(p, workspace);
     match exec {
         Some(r) => fs::unlink(&r),
         None    => ()
@@ -435,7 +433,8 @@ fn assert_built_library_exists(repo: &Path, short_name: &str) {
 
 fn built_library_exists(repo: &Path, short_name: &str) -> bool {
     debug!("assert_built_library_exists: repo = {}, short_name = {}", repo.display(), short_name);
-    let lib = built_library_in_workspace(&CrateId::new(short_name), repo);
+    let crate_id = from_str(short_name).expect("valid crate id");
+    let lib = built_library_in_workspace(&crate_id, repo);
     lib.is_some() && {
         let libname = lib.get_ref();
         libname.exists() && is_rwx(libname)
@@ -470,18 +469,16 @@ fn command_line_test_output_with_env(args: &[~str], env: ~[(~str, ~str)]) -> ~[~
 fn lib_output_file_name(workspace: &Path, short_name: &str) -> Path {
     debug!("lib_output_file_name: given {} and short name {}",
            workspace.display(), short_name);
-    library_in_workspace(&Path::new(short_name),
-                         short_name,
+    let crate_id = from_str(short_name).expect("valid crate id");
+    library_in_workspace(&crate_id,
                          Build,
-                         workspace,
-                         "build",
-                         &NoVersion).expect("lib_output_file_name")
+                         workspace).expect("lib_output_file_name")
 }
 
 #[cfg(target_os = "linux")]
 fn touch_source_file(workspace: &Path, crateid: &CrateId) {
     use conditions::bad_path::cond;
-    let pkg_src_dir = workspace.join_many([~"src", crateid.to_str()]);
+    let pkg_src_dir = workspace.join_many([~"src", crateid.short_name_with_version()]);
     let contents = fs::readdir(&pkg_src_dir);
     for p in contents.iter() {
         if p.extension_str() == Some("rs") {
@@ -501,7 +498,7 @@ fn touch_source_file(workspace: &Path, crateid: &CrateId) {
 #[cfg(not(target_os = "linux"))]
 fn touch_source_file(workspace: &Path, crateid: &CrateId) {
     use conditions::bad_path::cond;
-    let pkg_src_dir = workspace.join_many([~"src", crateid.to_str()]);
+    let pkg_src_dir = workspace.join_many([~"src", crateid.short_name_with_version()]);
     let contents = fs::readdir(&pkg_src_dir);
     for p in contents.iter() {
         if p.extension_str() == Some("rs") {
@@ -520,7 +517,7 @@ fn touch_source_file(workspace: &Path, crateid: &CrateId) {
 /// Add a comment at the end
 fn frob_source_file(workspace: &Path, crateid: &CrateId, filename: &str) {
     use conditions::bad_path::cond;
-    let pkg_src_dir = workspace.join_many([~"src", crateid.to_str()]);
+    let pkg_src_dir = workspace.join_many([~"src", crateid.short_name_with_version()]);
     let mut maybe_p = None;
     let maybe_file = pkg_src_dir.join(filename);
     debug!("Trying to frob {} -- {}", pkg_src_dir.display(), filename);
@@ -567,7 +564,7 @@ fn test_install_valid() {
     let sysroot = test_sysroot();
     debug!("sysroot = {}", sysroot.display());
     let temp_pkg_id = fake_pkg();
-    let (temp_workspace, _pkg_dir) = mk_temp_workspace(&temp_pkg_id.path, &NoVersion);
+    let (temp_workspace, _pkg_dir) = mk_temp_workspace(&temp_pkg_id);
     let temp_workspace = temp_workspace.path();
     let ctxt = fake_ctxt(sysroot, temp_workspace);
     debug!("temp_workspace = {}", temp_workspace.display());
@@ -583,7 +580,7 @@ fn test_install_valid() {
     assert!(exec.exists());
     assert!(is_rwx(&exec));
 
-    let lib = installed_library_in_workspace(&temp_pkg_id.path, temp_workspace);
+    let lib = installed_library_in_workspace(&temp_pkg_id, temp_workspace);
     debug!("lib = {:?}", lib);
     assert!(lib.as_ref().map_or(false, |l| l.exists()));
     assert!(lib.as_ref().map_or(false, |l| is_rwx(l)));
@@ -623,9 +620,8 @@ fn test_install_invalid() {
 
 #[test]
 fn test_install_valid_external() {
-    let temp_pkg_id = CrateId::new("foo");
-    let (tempdir, _) = mk_temp_workspace(&temp_pkg_id.path,
-                                         &temp_pkg_id.version);
+    let temp_pkg_id: CrateId = from_str("foo").unwrap();
+    let (tempdir, _) = mk_temp_workspace(&temp_pkg_id);
     let temp_workspace = tempdir.path();
     command_line_test([~"install", ~"foo"], temp_workspace);
 
@@ -635,7 +631,7 @@ fn test_install_valid_external() {
     assert!(exec.exists());
     assert!(is_rwx(&exec));
 
-    let lib = installed_library_in_workspace(&temp_pkg_id.path, temp_workspace);
+    let lib = installed_library_in_workspace(&temp_pkg_id, temp_workspace);
     debug!("lib = {:?}", lib);
     assert!(lib.as_ref().map_or(false, |l| l.exists()));
     assert!(lib.as_ref().map_or(false, |l| is_rwx(l)));
@@ -662,7 +658,8 @@ fn test_install_invalid_external() {
 #[test]
 fn test_install_git() {
     let temp_pkg_id = git_repo_pkg();
-    let repo = init_git_repo(&temp_pkg_id.path);
+    let path = Path::new(temp_pkg_id.path.as_slice());
+    let repo = init_git_repo(&path);
     let repo = repo.path();
     debug!("repo = {}", repo.display());
     let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]);
@@ -679,10 +676,9 @@ fn test_install_git() {
     add_git_tag(&repo_subdir, ~"0.1"); // this has the effect of committing the files
 
     debug!("test_install_git: calling rustpkg install {} in {}",
-           temp_pkg_id.path.display(), repo.display());
+           temp_pkg_id.path, repo.display());
     // should have test, bench, lib, and main
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    command_line_test([~"install", temp_pkg_id.path.as_str().unwrap().to_owned()], repo);
+    command_line_test([~"install", temp_pkg_id.path.to_owned()], repo);
     let ws = repo.join(".rust");
     // Check that all files exist
     debug!("Checking for files in {}", ws.display());
@@ -693,7 +689,7 @@ fn test_install_git() {
     let _built_lib =
         built_library_in_workspace(&temp_pkg_id,
                                    &ws).expect("test_install_git: built lib should exist");
-    assert_lib_exists(&ws, &temp_pkg_id.path, temp_pkg_id.version.clone());
+    assert_lib_exists(&ws, &temp_pkg_id);
     let built_test = built_test_in_workspace(&temp_pkg_id,
                          &ws).expect("test_install_git: built test should exist");
     assert!(built_test.exists());
@@ -711,8 +707,6 @@ fn test_install_git() {
 
 #[test]
 fn test_crate_ids_must_be_relative_path_like() {
-    use conditions::bad_pkg_id::cond;
-
     /*
     Okay:
     - One identifier, with no slashes
@@ -724,72 +718,16 @@ fn test_crate_ids_must_be_relative_path_like() {
 
     */
 
-    let whatever = CrateId::new("foo");
+    let foo: CrateId = from_str("foo").unwrap();
+    assert_eq!(~"foo#0.0", foo.to_str());
+    let test_pkg: CrateId = from_str("github.com/catamorphism/test-pkg").unwrap();
+    assert_eq!(~"github.com/catamorphism/test-pkg#0.0", test_pkg.to_str());
 
-    assert_eq!(~"foo-0.0", whatever.to_str());
-    assert!("github.com/catamorphism/test-pkg-0.0" ==
-            CrateId::new("github.com/catamorphism/test-pkg").to_str());
-
-    cond.trap(|(p, e)| {
-        assert!(p.filename().is_none());
-        assert!("bad crateid" == e);
-        whatever.clone()
-    }).inside(|| {
-        let x = CrateId::new("");
-        assert_eq!(~"foo-0.0", x.to_str());
-    });
+    let x: Option<CrateId> = from_str("");
+    assert_eq!(x, None);
 
-    cond.trap(|(p, e)| {
-        let abs = os::make_absolute(&Path::new("foo/bar/quux"));
-        assert_eq!(p, abs);
-        assert!("bad crateid" == e);
-        whatever.clone()
-    }).inside(|| {
-        let zp = os::make_absolute(&Path::new("foo/bar/quux"));
-        // FIXME (#9639): This needs to handle non-utf8 paths
-        let z = CrateId::new(zp.as_str().unwrap());
-        assert_eq!(~"foo-0.0", z.to_str());
-    })
-}
-
-#[test]
-fn test_package_version() {
-    let local_path = "mockgithub.com/catamorphism/test_pkg_version";
-    let repo = init_git_repo(&Path::new(local_path));
-    let repo = repo.path();
-    let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test_pkg_version"]);
-    debug!("Writing files in: {}", repo_subdir.display());
-    fs::mkdir_recursive(&repo_subdir, io::UserRWX);
-    writeFile(&repo_subdir.join("main.rs"),
-              "fn main() { let _x = (); }");
-    writeFile(&repo_subdir.join("lib.rs"),
-              "pub fn f() { let _x = (); }");
-    writeFile(&repo_subdir.join("test.rs"),
-              "#[test] pub fn f() { (); }");
-    writeFile(&repo_subdir.join("bench.rs"),
-              "#[bench] pub fn f() { (); }");
-    add_git_tag(&repo_subdir, ~"0.4");
-
-    // It won't pick up the 0.4 version because the dir isn't in the RUST_PATH, but...
-    let temp_pkg_id = CrateId::new("mockgithub.com/catamorphism/test_pkg_version");
-    // This should look at the prefix, clone into a workspace, then build.
-    command_line_test([~"install", ~"mockgithub.com/catamorphism/test_pkg_version"],
-                      repo);
-    let ws = repo.join(".rust");
-    // we can still match on the filename to make sure it contains the 0.4 version
-    assert!(match built_library_in_workspace(&temp_pkg_id,
-                                             &ws) {
-        Some(p) => {
-            let suffix = format!("0.4{}", os::consts::DLL_SUFFIX);
-            p.as_vec().ends_with(suffix.as_bytes())
-        }
-        None    => false
-    });
-    assert!(built_executable_in_workspace(&temp_pkg_id, &ws)
-            == Some(target_build_dir(&ws).join_many(["mockgithub.com",
-                                                     "catamorphism",
-                                                     "test_pkg_version",
-                                                     "test_pkg_version"])));
+    let z: Option<CrateId> = from_str("/foo/bar/quux");
+    assert_eq!(z, None);
 }
 
 #[test]
@@ -814,7 +752,8 @@ fn test_package_request_version() {
 
     command_line_test([~"install", format!("{}\\#0.3", local_path)], repo);
 
-    assert!(match installed_library_in_workspace(&Path::new("test_pkg_version"),
+    let crate_id = from_str(format!("{}\\#0.3", local_path)).unwrap();
+    assert!(match installed_library_in_workspace(&crate_id,
                                                  &repo.join(".rust")) {
         Some(p) => {
             debug!("installed: {}", p.display());
@@ -823,7 +762,7 @@ fn test_package_request_version() {
         }
         None    => false
     });
-    let temp_pkg_id = CrateId::new("mockgithub.com/catamorphism/test_pkg_version#0.3");
+    let temp_pkg_id = from_str("mockgithub.com/catamorphism/test_pkg_version#0.3").unwrap();
     assert!(target_executable_in_workspace(&temp_pkg_id, &repo.join(".rust"))
             == repo.join_many([".rust", "bin", "test_pkg_version"]));
 
@@ -858,15 +797,17 @@ fn rustpkg_library_target() {
               "#[test] pub fn f() { (); }");
     writeFile(&package_dir.join("bench.rs"),
               "#[bench] pub fn f() { (); }");
+    add_git_tag(&package_dir, ~"0.0");
 
-    add_git_tag(&package_dir, ~"1.0");
     command_line_test([~"install", ~"foo"], foo_repo);
-    assert_lib_exists(&foo_repo.join(".rust"), &Path::new("foo"), ExactRevision(~"1.0"));
+    let crate_id: CrateId = from_str("foo").unwrap();
+    assert_lib_exists(&foo_repo.join(".rust"), &crate_id);
 }
 
 #[test]
 fn rustpkg_local_pkg() {
-    let dir = create_local_package(&CrateId::new("foo"));
+    let crate_id: CrateId = from_str("foo").unwrap();
+    let dir = create_local_package(&crate_id);
     command_line_test([~"install", ~"foo"], dir.path());
     assert_executable_exists(dir.path(), "foo");
 }
@@ -874,7 +815,8 @@ fn rustpkg_local_pkg() {
 #[test]
 #[ignore(reason="busted")]
 fn package_script_with_default_build() {
-    let dir = create_local_package(&CrateId::new("fancy-lib"));
+    let crate_id: CrateId = from_str("fancy-lib").unwrap();
+    let dir = create_local_package(&crate_id);
     let dir = dir.path();
     debug!("dir = {}", dir.display());
     let mut source = test_sysroot().dir_path();
@@ -884,7 +826,7 @@ fn package_script_with_default_build() {
     debug!("package_script_with_default_build: {}", source.display());
     fs::copy(&source, &dir.join_many(["src", "fancy-lib-0.0", "pkg.rs"]));
     command_line_test([~"install", ~"fancy-lib"], dir);
-    assert_lib_exists(dir, &Path::new("fancy-lib"), NoVersion);
+    assert_lib_exists(dir, &crate_id);
     assert!(target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]).exists());
     let generated_path = target_build_dir(dir).join_many([~"fancy-lib", ~"generated.rs"]);
     debug!("generated path = {}", generated_path.display());
@@ -915,7 +857,8 @@ fn rustpkg_install_no_arg() {
               "fn main() { let _x = (); }");
     debug!("install_no_arg: dir = {}", package_dir.display());
     command_line_test([~"install"], &package_dir);
-    assert_lib_exists(&tmp, &Path::new("foo"), NoVersion);
+    let crate_id: CrateId = from_str("foo").unwrap();
+    assert_lib_exists(&tmp, &crate_id);
 }
 
 #[test]
@@ -931,14 +874,16 @@ fn rustpkg_clean_no_arg() {
     command_line_test([~"build"], &package_dir);
     assert_built_executable_exists(&tmp, "foo");
     command_line_test([~"clean"], &package_dir);
-    let res = built_executable_in_workspace(&CrateId::new("foo"), &tmp);
+    let crate_id: CrateId = from_str("foo").unwrap();
+    let res = built_executable_in_workspace(&crate_id, &tmp);
     assert!(!res.as_ref().map_or(false, |m| m.exists()));
 }
 
 #[test]
 fn rust_path_test() {
     let dir_for_path = TempDir::new("more_rust").expect("rust_path_test failed");
-    let dir = mk_workspace(dir_for_path.path(), &Path::new("foo"), &NoVersion);
+    let crate_id: CrateId = from_str("foo").unwrap();
+    let dir = mk_workspace(dir_for_path.path(), &crate_id);
     debug!("dir = {}", dir.display());
     writeFile(&dir.join("main.rs"), "fn main() { let _x = (); }");
 
@@ -989,11 +934,11 @@ fn rust_path_parse() {
 fn test_list() {
     let dir = TempDir::new("test_list").expect("test_list failed");
     let dir = dir.path();
-    let foo = CrateId::new("foo");
+    let foo: CrateId = from_str("foo").unwrap();
     create_local_package_in(&foo, dir);
-    let bar = CrateId::new("bar");
+    let bar: CrateId = from_str("bar").unwrap();
     create_local_package_in(&bar, dir);
-    let quux = CrateId::new("quux");
+    let quux: CrateId = from_str("quux").unwrap();
     create_local_package_in(&quux, dir);
 
 // list doesn't output very much right now...
@@ -1019,9 +964,9 @@ fn test_list() {
 fn install_remove() {
     let dir = TempDir::new("install_remove").expect("install_remove");
     let dir = dir.path();
-    let foo = CrateId::new("foo");
-    let bar = CrateId::new("bar");
-    let quux = CrateId::new("quux");
+    let foo: CrateId = from_str("foo").unwrap();
+    let bar: CrateId = from_str("bar").unwrap();
+    let quux: CrateId = from_str("quux").unwrap();
     create_local_package_in(&foo, dir);
     create_local_package_in(&bar, dir);
     create_local_package_in(&quux, dir);
@@ -1048,7 +993,7 @@ fn install_check_duplicates() {
     // check invariant that there are no dups in the pkg database
     let dir = TempDir::new("install_remove").expect("install_remove");
     let dir = dir.path();
-    let foo = CrateId::new("foo");
+    let foo: CrateId = from_str("foo").unwrap();
     create_local_package_in(&foo, dir);
 
     command_line_test([~"install", ~"foo"], dir);
@@ -1056,7 +1001,7 @@ fn install_check_duplicates() {
     let mut contents = ~[];
     let check_dups = |p: &CrateId| {
         if contents.contains(p) {
-            fail!("package {} appears in `list` output more than once", p.path.display());
+            fail!("package {} appears in `list` output more than once", p.path);
         }
         else {
             contents.push((*p).clone());
@@ -1068,7 +1013,7 @@ fn install_check_duplicates() {
 
 #[test]
 fn no_rebuilding() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     command_line_test([~"build", ~"foo"], workspace);
@@ -1089,11 +1034,11 @@ fn no_rebuilding() {
 #[test]
 #[ignore]
 fn no_recopying() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     command_line_test([~"install", ~"foo"], workspace);
-    let foo_lib = installed_library_in_workspace(&p_id.path, workspace);
+    let foo_lib = installed_library_in_workspace(&p_id, workspace);
     assert!(foo_lib.is_some());
     // Now make `foo` read-only so that subsequent attempts to copy to it will fail
     assert!(chmod_read_only(&foo_lib.unwrap()));
@@ -1108,8 +1053,8 @@ fn no_recopying() {
 
 #[test]
 fn no_rebuilding_dep() {
-    let p_id = CrateId::new("foo");
-    let dep_id = CrateId::new("bar");
+    let p_id: CrateId = from_str("foo").unwrap();
+    let dep_id: CrateId = from_str("bar").unwrap();
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     let workspace = workspace.path();
     command_line_test([~"build", ~"foo"], workspace);
@@ -1127,8 +1072,8 @@ fn no_rebuilding_dep() {
 
 #[test]
 fn do_rebuild_dep_dates_change() {
-    let p_id = CrateId::new("foo");
-    let dep_id = CrateId::new("bar");
+    let p_id: CrateId = from_str("foo").unwrap();
+    let dep_id: CrateId = from_str("bar").unwrap();
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     let workspace = workspace.path();
     command_line_test([~"build", ~"foo"], workspace);
@@ -1147,8 +1092,8 @@ fn do_rebuild_dep_dates_change() {
 
 #[test]
 fn do_rebuild_dep_only_contents_change() {
-    let p_id = CrateId::new("foo");
-    let dep_id = CrateId::new("bar");
+    let p_id: CrateId = from_str("foo").unwrap();
+    let dep_id: CrateId = from_str("bar").unwrap();
     let workspace = create_local_package_with_dep(&p_id, &dep_id);
     let workspace = workspace.path();
     command_line_test([~"build", ~"foo"], workspace);
@@ -1168,8 +1113,10 @@ fn do_rebuild_dep_only_contents_change() {
 
 #[test]
 fn test_versions() {
-    let workspace = create_local_package(&CrateId::new("foo#0.1"));
-    let _other_workspace = create_local_package(&CrateId::new("foo#0.2"));
+    let foo_01: CrateId = from_str("foo#0.1").unwrap();
+    let foo_02: CrateId = from_str("foo#0.2").unwrap();
+    let workspace = create_local_package(&foo_01);
+    let _other_workspace = create_local_package(&foo_02);
     command_line_test([~"install", ~"foo#0.1"], workspace.path());
     let output = command_line_test_output([~"list"]);
     // make sure output includes versions
@@ -1179,7 +1126,8 @@ fn test_versions() {
 #[test]
 #[ignore(reason = "do not yet implemented")]
 fn test_build_hooks() {
-    let workspace = create_local_package_with_custom_build_hook(&CrateId::new("foo"),
+    let crate_id: CrateId = from_str("foo").unwrap();
+    let workspace = create_local_package_with_custom_build_hook(&crate_id,
                                                                 "frob");
     command_line_test([~"do", ~"foo", ~"frob"], workspace.path());
 }
@@ -1189,14 +1137,16 @@ fn test_build_hooks() {
 #[ignore(reason = "info not yet implemented")]
 fn test_info() {
     let expected_info = ~"package foo"; // fill in
-    let workspace = create_local_package(&CrateId::new("foo"));
+    let crate_id: CrateId = from_str("foo").unwrap();
+    let workspace = create_local_package(&crate_id);
     let output = command_line_test([~"info", ~"foo"], workspace.path());
     assert_eq!(str::from_utf8_owned(output.output).unwrap(), expected_info);
 }
 
 #[test]
 fn test_uninstall() {
-    let workspace = create_local_package(&CrateId::new("foo"));
+    let crate_id: CrateId = from_str("foo").unwrap();
+    let workspace = create_local_package(&crate_id);
     command_line_test([~"uninstall", ~"foo"], workspace.path());
     let output = command_line_test([~"list"], workspace.path());
     assert!(!str::from_utf8(output.output).unwrap().contains("foo"));
@@ -1205,7 +1155,7 @@ fn test_uninstall() {
 #[test]
 fn test_non_numeric_tag() {
     let temp_pkg_id = git_repo_pkg();
-    let repo = init_git_repo(&temp_pkg_id.path);
+    let repo = init_git_repo(&Path::new(temp_pkg_id.path.as_slice()));
     let repo = repo.path();
     let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]);
     writeFile(&repo_subdir.join("foo"), "foo");
@@ -1217,9 +1167,7 @@ fn test_non_numeric_tag() {
     writeFile(&repo_subdir.join("not_on_testbranch_only"), "bye bye");
     add_all_and_commit(&repo_subdir);
 
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    command_line_test([~"install", format!("{}\\#testbranch",
-                                           temp_pkg_id.path.as_str().unwrap())], repo);
+    command_line_test([~"install", format!("{}\\#testbranch", temp_pkg_id.path)], repo);
     let file1 = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg", "testbranch_only"]);
     let file2 = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg", "master_only"]);
     assert!(file1.exists());
@@ -1332,7 +1280,7 @@ fn test_extern_mod_simpler() {
 
 #[test]
 fn test_import_rustpkg() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     writeFile(&workspace.join_many(["src", "foo-0.0", "pkg.rs"]),
@@ -1345,7 +1293,7 @@ fn test_import_rustpkg() {
 
 #[test]
 fn test_macro_pkg_script() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     writeFile(&workspace.join_many(["src", "foo-0.0", "pkg.rs"]),
@@ -1362,8 +1310,10 @@ fn multiple_workspaces() {
 // Copy the exact same package into directory B and install it
 // Set the RUST_PATH to A:B
 // Make a third package that uses foo, make sure we can build/install it
-    let (a_loc, _pkg_dir) = mk_temp_workspace(&Path::new("foo"), &NoVersion);
-    let (b_loc, _pkg_dir) = mk_temp_workspace(&Path::new("foo"), &NoVersion);
+    let p_id: CrateId = from_str("foo").unwrap();
+    let bar_p_id: CrateId = from_str("bar").unwrap();
+    let (a_loc, _pkg_dir) = mk_temp_workspace(&p_id);
+    let (b_loc, _pkg_dir) = mk_temp_workspace(&p_id);
     let (a_loc, b_loc) = (a_loc.path(), b_loc.path());
     debug!("Trying to install foo in {}", a_loc.display());
     command_line_test([~"install", ~"foo"], a_loc);
@@ -1372,7 +1322,7 @@ fn multiple_workspaces() {
     // FIXME (#9639): This needs to handle non-utf8 paths
     let env = Some(~[(~"RUST_PATH", format!("{}:{}", a_loc.as_str().unwrap(),
                                             b_loc.as_str().unwrap()))]);
-    let c_loc = create_local_package_with_dep(&CrateId::new("bar"), &CrateId::new("foo"));
+    let c_loc = create_local_package_with_dep(&bar_p_id, &p_id);
     command_line_test_with_env([~"install", ~"bar"], c_loc.path(), env);
 }
 
@@ -1385,26 +1335,28 @@ fn rust_path_hack_test(hack_flag: bool) {
       make sure built files for foo are in B
       make sure nothing gets built into A or A/../build[lib,bin]
 */
-   let p_id = CrateId::new("foo");
-   let workspace = create_local_package(&p_id);
-   let workspace = workspace.path();
-   let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace");
-   let dest_workspace = dest_workspace.path();
-   let foo_path = workspace.join_many(["src", "foo-0.0"]);
-   let rust_path = Some(~[(~"RUST_PATH",
-       format!("{}:{}",
-               dest_workspace.as_str().unwrap(),
-               foo_path.as_str().unwrap()))]);
-   command_line_test_with_env(~[~"install"] + if hack_flag { ~[~"--rust-path-hack"] } else { ~[] } +
-                               ~[~"foo"], dest_workspace, rust_path);
-   assert_lib_exists(dest_workspace, &Path::new("foo"), NoVersion);
-   assert_executable_exists(dest_workspace, "foo");
-   assert_built_library_exists(dest_workspace, "foo");
-   assert_built_executable_exists(dest_workspace, "foo");
-   assert!(!lib_exists(workspace, &Path::new("foo"), NoVersion));
-   assert!(!executable_exists(workspace, "foo"));
-   assert!(!built_library_exists(workspace, "foo"));
-   assert!(!built_executable_exists(workspace, "foo"));
+    let p_id: CrateId = from_str("foo").unwrap();
+    let bar_p_id: CrateId = from_str("bar").unwrap();
+    let workspace = create_local_package(&p_id);
+    let workspace = workspace.path();
+    let dest_workspace = mk_empty_workspace(&bar_p_id, "dest_workspace");
+    let dest_workspace = dest_workspace.path();
+    let foo_path = workspace.join_many(["src", "foo-0.0"]);
+    let rust_path = Some(~[(~"RUST_PATH",
+        format!("{}:{}",
+                dest_workspace.as_str().unwrap(),
+                foo_path.as_str().unwrap()))]);
+    command_line_test_with_env(~[~"install"] +
+                               if hack_flag { ~[~"--rust-path-hack"] } else { ~[] } + ~[~"foo"],
+                               dest_workspace, rust_path);
+    assert_lib_exists(dest_workspace, &p_id);
+    assert_executable_exists(dest_workspace, "foo");
+    assert_built_library_exists(dest_workspace, "foo");
+    assert_built_executable_exists(dest_workspace, "foo");
+    assert!(!lib_exists(workspace, &p_id));
+    assert!(!executable_exists(workspace, "foo"));
+    assert!(!built_library_exists(workspace, "foo"));
+    assert!(!built_executable_exists(workspace, "foo"));
 }
 
 // Notice that this is the only test case where the --rust-path-hack
@@ -1430,88 +1382,95 @@ fn test_rust_path_can_contain_package_dirs_without_flag() {
 
 #[test]
 fn rust_path_hack_cwd() {
-   // Same as rust_path_hack_test, but the CWD is the dir to build out of
-   let cwd = TempDir::new("foo").expect("rust_path_hack_cwd");
-   let cwd = cwd.path().join("foo");
-   fs::mkdir_recursive(&cwd, io::UserRWX);
-   writeFile(&cwd.join("lib.rs"), "pub fn f() { }");
-
-   let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace");
-   let dest_workspace = dest_workspace.path();
-   // FIXME (#9639): This needs to handle non-utf8 paths
-   let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
-   command_line_test_with_env([~"install", ~"--rust-path-hack", ~"foo"], &cwd, rust_path);
-   debug!("Checking that foo exists in {}", dest_workspace.display());
-   assert_lib_exists(dest_workspace, &Path::new("foo"), NoVersion);
-   assert_built_library_exists(dest_workspace, "foo");
-   assert!(!lib_exists(&cwd, &Path::new("foo"), NoVersion));
-   assert!(!built_library_exists(&cwd, "foo"));
+    // Same as rust_path_hack_test, but the CWD is the dir to build out of
+    let cwd = TempDir::new("foo").expect("rust_path_hack_cwd");
+    let cwd = cwd.path().join("foo");
+    fs::mkdir_recursive(&cwd, io::UserRWX);
+    writeFile(&cwd.join("lib.rs"), "pub fn f() { }");
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let bar_id: CrateId = from_str("bar").unwrap();
+
+    let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace");
+    let dest_workspace = dest_workspace.path();
+    // FIXME (#9639): This needs to handle non-utf8 paths
+    let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
+    command_line_test_with_env([~"install", ~"--rust-path-hack", ~"foo"], &cwd, rust_path);
+    debug!("Checking that foo exists in {}", dest_workspace.display());
+    assert_lib_exists(dest_workspace, &foo_id);
+    assert_built_library_exists(dest_workspace, "foo");
+    assert!(!lib_exists(&cwd, &foo_id));
+    assert!(!built_library_exists(&cwd, "foo"));
 }
 
 #[test]
 fn rust_path_hack_multi_path() {
-   // Same as rust_path_hack_test, but with a more complex package ID
-   let cwd = TempDir::new("pkg_files").expect("rust_path_hack_cwd");
-   let subdir = cwd.path().join_many(["foo", "bar", "quux"]);
-   fs::mkdir_recursive(&subdir, io::UserRWX);
-   writeFile(&subdir.join("lib.rs"), "pub fn f() { }");
-   let name = ~"foo/bar/quux";
-
-   let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace");
-   let dest_workspace = dest_workspace.path();
-   // FIXME (#9639): This needs to handle non-utf8 paths
-   let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
-   command_line_test_with_env([~"install", ~"--rust-path-hack", name.clone()], &subdir, rust_path);
-   debug!("Checking that {} exists in {}", name, dest_workspace.display());
-   assert_lib_exists(dest_workspace, &Path::new("quux"), NoVersion);
-   assert_built_library_exists(dest_workspace, name);
-   assert!(!lib_exists(&subdir, &Path::new("quux"), NoVersion));
-   assert!(!built_library_exists(&subdir, name));
+    // Same as rust_path_hack_test, but with a more complex package ID
+    let cwd = TempDir::new("pkg_files").expect("rust_path_hack_cwd");
+    let subdir = cwd.path().join_many(["foo", "bar", "quux"]);
+    fs::mkdir_recursive(&subdir, io::UserRWX);
+    writeFile(&subdir.join("lib.rs"), "pub fn f() { }");
+    let name = ~"foo/bar/quux";
+    let foo_id: CrateId = from_str("foo/bar/quux").unwrap();
+    let bar_id: CrateId = from_str("bar").unwrap();
+
+    let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace");
+    let dest_workspace = dest_workspace.path();
+    // FIXME (#9639): This needs to handle non-utf8 paths
+    let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
+    command_line_test_with_env([~"install", ~"--rust-path-hack", name.clone()], &subdir, rust_path);
+    debug!("Checking that {} exists in {}", name, dest_workspace.display());
+    assert_lib_exists(dest_workspace, &foo_id);
+    assert_built_library_exists(dest_workspace, name);
+    assert!(!lib_exists(&subdir, &foo_id));
+    assert!(!built_library_exists(&subdir, name));
 }
 
 #[test]
 fn rust_path_hack_install_no_arg() {
-   // Same as rust_path_hack_cwd, but making rustpkg infer the pkg id
-   let cwd = TempDir::new("pkg_files").expect("rust_path_hack_install_no_arg");
-   let cwd = cwd.path();
-   let source_dir = cwd.join("foo");
-   assert!(make_dir_rwx(&source_dir));
-   writeFile(&source_dir.join("lib.rs"), "pub fn f() { }");
-
-   let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace");
-   let dest_workspace = dest_workspace.path();
-   // FIXME (#9639): This needs to handle non-utf8 paths
-   let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
-   command_line_test_with_env([~"install", ~"--rust-path-hack"], &source_dir, rust_path);
-   debug!("Checking that foo exists in {}", dest_workspace.display());
-   assert_lib_exists(dest_workspace, &Path::new("foo"), NoVersion);
-   assert_built_library_exists(dest_workspace, "foo");
-   assert!(!lib_exists(&source_dir, &Path::new("foo"), NoVersion));
-   assert!(!built_library_exists(cwd, "foo"));
+    // Same as rust_path_hack_cwd, but making rustpkg infer the pkg id
+    let cwd = TempDir::new("pkg_files").expect("rust_path_hack_install_no_arg");
+    let cwd = cwd.path();
+    let source_dir = cwd.join("foo");
+    assert!(make_dir_rwx(&source_dir));
+    writeFile(&source_dir.join("lib.rs"), "pub fn f() { }");
+
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let bar_id: CrateId = from_str("bar").unwrap();
+    let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace");
+    let dest_workspace = dest_workspace.path();
+    // FIXME (#9639): This needs to handle non-utf8 paths
+    let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
+    command_line_test_with_env([~"install", ~"--rust-path-hack"], &source_dir, rust_path);
+    debug!("Checking that foo exists in {}", dest_workspace.display());
+    assert_lib_exists(dest_workspace, &foo_id);
+    assert_built_library_exists(dest_workspace, "foo");
+    assert!(!lib_exists(&source_dir, &foo_id));
+    assert!(!built_library_exists(cwd, "foo"));
 }
 
 #[test]
 fn rust_path_hack_build_no_arg() {
-   // Same as rust_path_hack_install_no_arg, but building instead of installing
-   let cwd = TempDir::new("pkg_files").expect("rust_path_hack_build_no_arg");
-   let source_dir = cwd.path().join("foo");
-   assert!(make_dir_rwx(&source_dir));
-   writeFile(&source_dir.join("lib.rs"), "pub fn f() { }");
-
-   let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace");
-   let dest_workspace = dest_workspace.path();
-   // FIXME (#9639): This needs to handle non-utf8 paths
-   let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
-   command_line_test_with_env([~"build", ~"--rust-path-hack"], &source_dir, rust_path);
-   debug!("Checking that foo exists in {}", dest_workspace.display());
-   assert_built_library_exists(dest_workspace, "foo");
-   assert!(!built_library_exists(&source_dir, "foo"));
+    // Same as rust_path_hack_install_no_arg, but building instead of installing
+    let cwd = TempDir::new("pkg_files").expect("rust_path_hack_build_no_arg");
+    let source_dir = cwd.path().join("foo");
+    assert!(make_dir_rwx(&source_dir));
+    writeFile(&source_dir.join("lib.rs"), "pub fn f() { }");
+
+    let bar_id: CrateId = from_str("bar").unwrap();
+    let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace");
+    let dest_workspace = dest_workspace.path();
+    // FIXME (#9639): This needs to handle non-utf8 paths
+    let rust_path = Some(~[(~"RUST_PATH", dest_workspace.as_str().unwrap().to_owned())]);
+    command_line_test_with_env([~"build", ~"--rust-path-hack"], &source_dir, rust_path);
+    debug!("Checking that foo exists in {}", dest_workspace.display());
+    assert_built_library_exists(dest_workspace, "foo");
+    assert!(!built_library_exists(&source_dir, "foo"));
 }
 
 #[test]
 fn rust_path_hack_build_with_dependency() {
-    let foo_id = CrateId::new("foo");
-    let dep_id = CrateId::new("dep");
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let dep_id: CrateId = from_str("dep").unwrap();
     // Tests that when --rust-path-hack is in effect, dependencies get built
     // into the destination workspace and not the source directory
     let work_dir = create_local_package(&foo_id);
@@ -1536,7 +1495,8 @@ fn rust_path_hack_build_with_dependency() {
 fn rust_path_install_target() {
     let dir_for_path = TempDir::new(
         "source_workspace").expect("rust_path_install_target failed");
-    let mut dir = mk_workspace(dir_for_path.path(), &Path::new("foo"), &NoVersion);
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let mut dir = mk_workspace(dir_for_path.path(), &foo_id);
     debug!("dir = {}", dir.display());
     writeFile(&dir.join("main.rs"), "fn main() { let _x = (); }");
     let dir_to_install_to = TempDir::new(
@@ -1559,7 +1519,7 @@ fn rust_path_install_target() {
 
 #[test]
 fn sysroot_flag() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     // no-op sysroot setting; I'm not sure how else to test this
@@ -1575,7 +1535,7 @@ fn sysroot_flag() {
 
 #[test]
 fn compile_flag_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1592,7 +1552,7 @@ fn compile_flag_build() {
 #[test]
 fn compile_flag_fail() {
     // --no-link shouldn't be accepted for install
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1608,7 +1568,7 @@ fn compile_flag_fail() {
 
 #[test]
 fn notrans_flag_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let flags_to_test = [~"--no-trans", ~"--parse-only",
@@ -1633,7 +1593,7 @@ fn notrans_flag_build() {
 #[test]
 fn notrans_flag_fail() {
     // --no-trans shouldn't be accepted for install
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let flags_to_test = [~"--no-trans", ~"--parse-only",
@@ -1648,13 +1608,13 @@ fn notrans_flag_fail() {
                           workspace, None, BAD_FLAG_CODE);
         assert!(!built_executable_exists(workspace, "foo"));
         assert!(!object_file_exists(workspace, "foo"));
-        assert!(!lib_exists(workspace, &Path::new("foo"), NoVersion));
+        assert!(!lib_exists(workspace, &p_id));
     }
 }
 
 #[test]
 fn dash_S() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1671,7 +1631,7 @@ fn dash_S() {
 
 #[test]
 fn dash_S_fail() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1688,7 +1648,7 @@ fn dash_S_fail() {
 
 #[test]
 fn test_cfg_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     // If the cfg flag gets messed up, this won't compile
@@ -1707,7 +1667,7 @@ fn test_cfg_build() {
 
 #[test]
 fn test_cfg_fail() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     writeFile(&workspace.join_many(["src", "foo-0.0", "main.rs"]),
@@ -1726,7 +1686,7 @@ fn test_cfg_fail() {
 
 #[test]
 fn test_emit_llvm_S_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1744,7 +1704,7 @@ fn test_emit_llvm_S_build() {
 
 #[test]
 fn test_emit_llvm_S_fail() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1764,7 +1724,7 @@ fn test_emit_llvm_S_fail() {
 
 #[test]
 fn test_emit_llvm_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1783,7 +1743,7 @@ fn test_emit_llvm_build() {
 
 #[test]
 fn test_emit_llvm_fail() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1804,7 +1764,7 @@ fn test_emit_llvm_fail() {
 
 #[test]
 fn test_linker_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let matches = getopts([], optgroups());
@@ -1849,7 +1809,7 @@ fn test_build_install_flags_fail() {
 
 #[test]
 fn test_optimized_build() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1879,10 +1839,10 @@ fn crateid_pointing_to_subdir() {
     fs::mkdir_recursive(&foo_dir, io::UserRWX);
     fs::mkdir_recursive(&bar_dir, io::UserRWX);
     writeFile(&foo_dir.join("lib.rs"),
-              "#[crate_id=\"mockgithub.com/mozilla/some_repo/extras/rust-foo#foo:0.0\"];" +
+              "#[crate_id=\"mockgithub.com/mozilla/some_repo/extras/foo\"];" +
               "pub fn f() {}");
     writeFile(&bar_dir.join("lib.rs"),
-              "#[crate_id=\"mockgithub.com/mozilla/some_repo/extras/rust-bar#bar:0.0\"];" +
+              "#[crate_id=\"mockgithub.com/mozilla/some_repo/extras/bar\"];" +
               "pub fn g() {}");
 
     debug!("Creating a file in {}", workspace.display());
@@ -1890,8 +1850,8 @@ fn crateid_pointing_to_subdir() {
     fs::mkdir_recursive(&testpkg_dir, io::UserRWX);
 
     writeFile(&testpkg_dir.join("main.rs"),
-              "extern mod foo = \"mockgithub.com/mozilla/some_repo/extras/foo\";\n
-               extern mod bar = \"mockgithub.com/mozilla/some_repo/extras/bar\";\n
+              "extern mod foo = \"mockgithub.com/mozilla/some_repo/extras/foo#foo:0.0\";\n
+               extern mod bar = \"mockgithub.com/mozilla/some_repo/extras/bar#bar:0.0\";\n
                use foo::f; use bar::g; \n
                fn main() { f(); g(); }");
 
@@ -1901,9 +1861,9 @@ fn crateid_pointing_to_subdir() {
 
 #[test]
 fn test_recursive_deps() {
-    let a_id = CrateId::new("a");
-    let b_id = CrateId::new("b");
-    let c_id = CrateId::new("c");
+    let a_id: CrateId = from_str("a").unwrap();
+    let b_id: CrateId = from_str("b").unwrap();
+    let c_id: CrateId = from_str("c").unwrap();
     let b_workspace = create_local_package_with_dep(&b_id, &c_id);
     let b_workspace = b_workspace.path();
     writeFile(&b_workspace.join_many(["src", "c-0.0", "lib.rs"]),
@@ -1920,17 +1880,18 @@ fn test_recursive_deps() {
     command_line_test_with_env([~"install", ~"a"],
                                a_workspace,
                                environment);
-    assert_lib_exists(a_workspace, &Path::new("a"), NoVersion);
-    assert_lib_exists(b_workspace, &Path::new("b"), NoVersion);
-    assert_lib_exists(b_workspace, &Path::new("c"), NoVersion);
+    assert_lib_exists(a_workspace, &a_id);
+    assert_lib_exists(b_workspace, &b_id);
+    assert_lib_exists(b_workspace, &c_id);
 }
 
 #[test]
 fn test_install_to_rust_path() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let second_workspace = create_local_package(&p_id);
     let second_workspace = second_workspace.path();
-    let first_workspace = mk_empty_workspace(&Path::new("p"), &NoVersion, "dest");
+    let none_id: CrateId = from_str("p").unwrap();
+    let first_workspace = mk_empty_workspace(&none_id, "dest");
     let first_workspace = first_workspace.path();
     // FIXME (#9639): This needs to handle non-utf8 paths
     let rust_path = Some(~[(~"RUST_PATH",
@@ -1951,7 +1912,7 @@ fn test_install_to_rust_path() {
 
 #[test]
 fn test_target_specific_build_dir() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1967,7 +1928,7 @@ fn test_target_specific_build_dir() {
 
 #[test]
 fn test_target_specific_install_dir() {
-    let p_id = CrateId::new("foo");
+    let p_id: CrateId = from_str("foo").unwrap();
     let workspace = create_local_package(&p_id);
     let workspace = workspace.path();
     let test_sys = test_sysroot();
@@ -1977,7 +1938,7 @@ fn test_target_specific_install_dir() {
                        ~"foo"],
                       workspace);
     assert!(workspace.join_many([~"lib", host_triple()]).is_dir());
-    assert_lib_exists(workspace, &Path::new("foo"), NoVersion);
+    assert_lib_exists(workspace, &p_id);
     assert!(fs::readdir(&workspace.join("lib")).len() == 1);
     assert!(workspace.join("bin").is_dir());
     assert_executable_exists(workspace, "foo");
@@ -1986,7 +1947,7 @@ fn test_target_specific_install_dir() {
 #[test]
 #[ignore(reason = "See #7240")]
 fn test_dependencies_terminate() {
-    let b_id = CrateId::new("b");
+    let b_id: CrateId = from_str("b").unwrap();
     let workspace = create_local_package(&b_id);
     let workspace = workspace.path();
     let b_dir = workspace.join_many(["src", "b-0.0"]);
@@ -1999,42 +1960,42 @@ fn test_dependencies_terminate() {
 
 #[test]
 fn install_after_build() {
-    let b_id = CrateId::new("b");
+    let b_id: CrateId = from_str("b").unwrap();
     let workspace = create_local_package(&b_id);
     let workspace = workspace.path();
     command_line_test([~"build", ~"b"], workspace);
     command_line_test([~"install", ~"b"], workspace);
-    assert_executable_exists(workspace, b_id.short_name);
-    assert_lib_exists(workspace, &b_id.path, NoVersion);
+    assert_executable_exists(workspace, b_id.name);
+    assert_lib_exists(workspace, &b_id);
 }
 
 #[test]
 fn reinstall() {
-    let b = CrateId::new("b");
+    let b: CrateId = from_str("b").unwrap();
     let workspace = create_local_package(&b);
     let workspace = workspace.path();
     // 1. Install, then remove executable file, then install again,
     // and make sure executable was re-installed
     command_line_test([~"install", ~"b"], workspace);
-    assert_executable_exists(workspace, b.short_name);
-    assert_lib_exists(workspace, &b.path, NoVersion);
+    assert_executable_exists(workspace, b.name);
+    assert_lib_exists(workspace, &b);
     remove_executable_file(&b, workspace);
     command_line_test([~"install", ~"b"], workspace);
-    assert_executable_exists(workspace, b.short_name);
+    assert_executable_exists(workspace, b.name);
     // 2. Build, then remove build executable file, then build again,
     // and make sure executable was re-built.
     command_line_test([~"build", ~"b"], workspace);
     remove_built_executable_file(&b, workspace);
     command_line_test([~"build", ~"b"], workspace);
-    assert_built_executable_exists(workspace, b.short_name);
+    assert_built_executable_exists(workspace, b.name);
     // 3. Install, then remove both executable and built executable,
     // then install again, make sure both were recreated
     command_line_test([~"install", ~"b"], workspace);
     remove_executable_file(&b, workspace);
     remove_built_executable_file(&b, workspace);
     command_line_test([~"install", ~"b"], workspace);
-    assert_executable_exists(workspace, b.short_name);
-    assert_built_executable_exists(workspace, b.short_name);
+    assert_executable_exists(workspace, b.name);
+    assert_built_executable_exists(workspace, b.name);
 }
 
 #[test]
@@ -2049,11 +2010,11 @@ fn correct_package_name_with_rust_path_hack() {
     */
 
     // Set RUST_PATH to something containing only the sources for foo
-    let foo_id = CrateId::new("foo");
-    let bar_id = CrateId::new("bar");
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let bar_id: CrateId = from_str("bar").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
-    let dest_workspace = mk_empty_workspace(&Path::new("bar"), &NoVersion, "dest_workspace");
+    let dest_workspace = mk_empty_workspace(&bar_id, "dest_workspace");
     let dest_workspace = dest_workspace.path();
 
     writeFile(&dest_workspace.join_many(["src", "bar-0.0", "main.rs"]),
@@ -2068,18 +2029,18 @@ fn correct_package_name_with_rust_path_hack() {
                                   // FIXME #3408: Should be NONEXISTENT_PACKAGE_CODE
                                dest_workspace, rust_path, COPY_FAILED_CODE);
     assert!(!executable_exists(dest_workspace, "bar"));
-    assert!(!lib_exists(dest_workspace, &bar_id.path.clone(), bar_id.version.clone()));
+    assert!(!lib_exists(dest_workspace, &bar_id));
     assert!(!executable_exists(dest_workspace, "foo"));
-    assert!(!lib_exists(dest_workspace, &foo_id.path.clone(), foo_id.version.clone()));
+    assert!(!lib_exists(dest_workspace, &foo_id));
     assert!(!executable_exists(foo_workspace, "bar"));
-    assert!(!lib_exists(foo_workspace, &bar_id.path.clone(), bar_id.version.clone()));
+    assert!(!lib_exists(foo_workspace, &bar_id));
     assert!(!executable_exists(foo_workspace, "foo"));
-    assert!(!lib_exists(foo_workspace, &foo_id.path.clone(), foo_id.version.clone()));
+    assert!(!lib_exists(foo_workspace, &foo_id));
 }
 
 #[test]
 fn test_rustpkg_test_creates_exec() {
-    let foo_id = CrateId::new("foo");
+    let foo_id: CrateId = from_str("foo").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
     writeFile(&foo_workspace.join_many(["src", "foo-0.0", "test.rs"]),
@@ -2090,7 +2051,8 @@ fn test_rustpkg_test_creates_exec() {
 
 #[test]
 fn test_rustpkg_test_output() {
-    let workspace = create_local_package_with_test(&CrateId::new("foo"));
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let workspace = create_local_package_with_test(&foo_id);
     let output = command_line_test([~"test", ~"foo"], workspace.path());
     let output_str = str::from_utf8(output.output).unwrap();
     // The first two assertions are separate because test output may
@@ -2102,7 +2064,7 @@ fn test_rustpkg_test_output() {
 
 #[test]
 fn test_rustpkg_test_failure_exit_status() {
-    let foo_id = CrateId::new("foo");
+    let foo_id: CrateId = from_str("foo").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
     writeFile(&foo_workspace.join_many(["src", "foo-0.0", "test.rs"]),
@@ -2116,7 +2078,7 @@ fn test_rustpkg_test_failure_exit_status() {
 
 #[test]
 fn test_rustpkg_test_cfg() {
-    let foo_id = CrateId::new("foo");
+    let foo_id: CrateId = from_str("foo").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
     writeFile(&foo_workspace.join_many(["src", "foo-0.0", "test.rs"]),
@@ -2129,7 +2091,7 @@ fn test_rustpkg_test_cfg() {
 
 #[test]
 fn test_rebuild_when_needed() {
-    let foo_id = CrateId::new("foo");
+    let foo_id: CrateId = from_str("foo").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
     let test_crate = foo_workspace.join_many(["src", "foo-0.0", "test.rs"]);
@@ -2150,7 +2112,7 @@ fn test_rebuild_when_needed() {
 #[test]
 #[ignore] // FIXME (#10257): This doesn't work as is since a read only file can't execute
 fn test_no_rebuilding() {
-    let foo_id = CrateId::new("foo");
+    let foo_id: CrateId = from_str("foo").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
     let test_crate = foo_workspace.join_many(["src", "foo-0.0", "test.rs"]);
@@ -2172,8 +2134,9 @@ fn test_no_rebuilding() {
 fn test_installed_read_only() {
     // Install sources from a "remote" (actually a local github repo)
     // Check that afterward, sources are read-only and installed under build/
-    let mut temp_pkg_id = git_repo_pkg();
-    let repo = init_git_repo(&temp_pkg_id.path);
+    let temp_pkg_id = git_repo_pkg();
+    let path = Path::new(temp_pkg_id.path.as_slice());
+    let repo = init_git_repo(&path);
     let repo = repo.path();
     debug!("repo = {}", repo.display());
     let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]);
@@ -2183,12 +2146,11 @@ fn test_installed_read_only() {
               "fn main() { let _x = (); }");
     writeFile(&repo_subdir.join("lib.rs"),
               "pub fn f() { let _x = (); }");
-    add_git_tag(&repo_subdir, ~"0.1"); // this has the effect of committing the files
+    add_git_tag(&repo_subdir, ~"0.0"); // this has the effect of committing the files
     // update crateid to what will be auto-detected
-    temp_pkg_id.version = ExactRevision(~"0.1");
 
     // FIXME (#9639): This needs to handle non-utf8 paths
-    command_line_test([~"install", temp_pkg_id.path.as_str().unwrap().to_owned()], repo);
+    command_line_test([~"install", temp_pkg_id.to_str()], repo);
 
     let ws = repo.join(".rust");
     // Check that all files exist
@@ -2204,8 +2166,10 @@ fn test_installed_read_only() {
     assert!(is_rwx(&built_lib));
 
     // Make sure sources are (a) under "build" and (b) read-only
-    let src1 = target_build_dir(&ws).join_many([~"src", temp_pkg_id.to_str(), ~"main.rs"]);
-    let src2 = target_build_dir(&ws).join_many([~"src", temp_pkg_id.to_str(), ~"lib.rs"]);
+    let temp_dir = format!("{}-{}", temp_pkg_id.path, temp_pkg_id.version_or_default());
+    let src1 = target_build_dir(&ws).join_many([~"src", temp_dir.clone(), ~"main.rs"]);
+    let src2 = target_build_dir(&ws).join_many([~"src", temp_dir.clone(), ~"lib.rs"]);
+    debug!("src1: {}", src1.display());
     assert!(src1.exists());
     assert!(src2.exists());
     assert!(is_read_only(&src1));
@@ -2215,7 +2179,7 @@ fn test_installed_read_only() {
 #[test]
 fn test_installed_local_changes() {
     let temp_pkg_id = git_repo_pkg();
-    let repo = init_git_repo(&temp_pkg_id.path);
+    let repo = init_git_repo(&Path::new(temp_pkg_id.path.as_slice()));
     let repo = repo.path();
     debug!("repo = {}", repo.display());
     let repo_subdir = repo.join_many(["mockgithub.com", "catamorphism", "test-pkg"]);
@@ -2228,9 +2192,7 @@ fn test_installed_local_changes() {
               "pub fn f() { let _x = (); }");
     add_git_tag(&repo_subdir, ~"0.1"); // this has the effect of committing the files
 
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    command_line_test([~"install", temp_pkg_id.path.as_str().unwrap().to_owned()], repo);
-
+    command_line_test([~"install", temp_pkg_id.path.to_owned()], repo);
 
     // We installed the dependency.
     // Now start a new workspace and clone it into it
@@ -2242,7 +2204,7 @@ fn test_installed_local_changes() {
                                                   "test-pkg-0.0"]);
     debug!("---- git clone {} {}", repo_subdir.display(), target_dir.display());
 
-    let c_res = safe_git_clone(&repo_subdir, &NoVersion, &target_dir);
+    let c_res = safe_git_clone(&repo_subdir, &None, &target_dir);
 
     match c_res {
         DirToUse(_) => fail!("test_installed_local_changes failed"),
@@ -2262,14 +2224,13 @@ fn test_installed_local_changes() {
               fn main() { g(); }");
     // And make sure we can build it
 
-    // FIXME (#9639): This needs to handle non-utf8 paths
-    command_line_test([~"build", importer_pkg_id.path.as_str().unwrap().to_owned()],
-                      hacking_workspace);
+    command_line_test([~"build", importer_pkg_id.path.to_owned()], hacking_workspace);
 }
 
 #[test]
 fn test_7402() {
-    let dir = create_local_package(&CrateId::new("foo"));
+    let foo_id: CrateId = from_str("foo").unwrap();
+    let dir = create_local_package(&foo_id);
     let dest_workspace = TempDir::new("more_rust").expect("test_7402");
     let dest_workspace = dest_workspace.path();
     // FIXME (#9639): This needs to handle non-utf8 paths
@@ -2283,7 +2244,7 @@ fn test_7402() {
 
 #[test]
 fn test_compile_error() {
-    let foo_id = CrateId::new("foo");
+    let foo_id: CrateId = from_str("foo").unwrap();
     let foo_workspace = create_local_package(&foo_id);
     let foo_workspace = foo_workspace.path();
     let main_crate = foo_workspace.join_many(["src", "foo-0.0", "main.rs"]);
@@ -2317,7 +2278,8 @@ fn test_c_dependency_ok() {
     // registers a hook to build it if it's not fresh
     // After running `build`, test that the C library built
 
-    let dir = create_local_package(&CrateId::new("cdep"));
+    let cdep_id: CrateId = from_str("cdep").unwrap();
+    let dir = create_local_package(&cdep_id);
     let dir = dir.path();
     writeFile(&dir.join_many(["src", "cdep-0.0", "main.rs"]),
               "#[link_args = \"-lfoo\"]\nextern { fn f(); } \
@@ -2340,7 +2302,8 @@ fn test_c_dependency_ok() {
 #[test]
 #[ignore(reason="busted")]
 fn test_c_dependency_no_rebuilding() {
-    let dir = create_local_package(&CrateId::new("cdep"));
+    let cdep_id: CrateId = from_str("cdep").unwrap();
+    let dir = create_local_package(&cdep_id);
     let dir = dir.path();
     writeFile(&dir.join_many(["src", "cdep-0.0", "main.rs"]),
               "#[link_args = \"-lfoo\"]\nextern { fn f(); } \
@@ -2374,7 +2337,8 @@ fn test_c_dependency_no_rebuilding() {
 #[test]
 #[ignore(reason="busted")]
 fn test_c_dependency_yes_rebuilding() {
-    let dir = create_local_package(&CrateId::new("cdep"));
+    let cdep_id: CrateId = from_str("cdep").unwrap();
+    let dir = create_local_package(&cdep_id);
     let dir = dir.path();
     writeFile(&dir.join_many(["src", "cdep-0.0", "main.rs"]),
               "#[link_args = \"-lfoo\"]\nextern { fn f(); } \
@@ -2395,7 +2359,7 @@ fn test_c_dependency_yes_rebuilding() {
     assert!(c_library_path.exists());
 
     // Now, make the Rust library read-only so rebuilding will fail
-    match built_library_in_workspace(&CrateId::new("cdep"), dir) {
+    match built_library_in_workspace(&cdep_id, dir) {
         Some(ref pth) => assert!(chmod_read_only(pth)),
         None => assert_built_library_exists(dir, "cdep")
     }
@@ -2413,7 +2377,8 @@ fn test_c_dependency_yes_rebuilding() {
 fn correct_error_dependency() {
     // Supposing a package we're trying to install via a dependency doesn't
     // exist, we should throw a condition, and not ICE
-    let workspace_dir = create_local_package(&CrateId::new("badpkg"));
+    let crate_id: CrateId = from_str("badpkg").unwrap();
+    let workspace_dir = create_local_package(&crate_id);
 
     let dir = workspace_dir.path();
     let main_rs = dir.join_many(["src", "badpkg-0.0", "main.rs"]);
diff --git a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs
index b6c5e15c09a..b6dba40ebd4 100644
--- a/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs
+++ b/src/librustpkg/testsuite/pass/src/c-dependencies/pkg.rs
@@ -13,7 +13,7 @@ extern mod rustc;
 
 use std::{os, task};
 use rustpkg::api;
-use rustpkg::version::NoVersion;
+use rustpkg::version::None;
 use rustpkg::workcache_support::digest_file_with_date;
 use rustpkg::exit_codes::COPY_FAILED_CODE;
 
@@ -73,7 +73,7 @@ pub fn main() {
         api::install_pkg(&mut cc,
                          os::getcwd(),
                          ~"cdep",
-                         NoVersion,
+                         None,
                          ~[(~"binary", out_lib_path.clone()), (~"file", foo_c_name.clone())]);
     };
 
diff --git a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs
index 4a107de55a5..7b1291025e4 100644
--- a/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs
+++ b/src/librustpkg/testsuite/pass/src/fancy-lib/pkg.rs
@@ -14,7 +14,7 @@ extern mod rustc;
 use std::os;
 use std::io::File;
 use rustpkg::api;
-use rustpkg::version::NoVersion;
+use rustpkg::version::None;
 
 pub fn main() {
     let args = os::args();
@@ -48,5 +48,5 @@ pub fn main() {
                 for _ in xs.iter() { assert!(true); } }".as_bytes());
 
     let context = api::default_context(sysroot, api::default_workspace());
-    api::install_pkg(&context, os::getcwd(), ~"fancy-lib", NoVersion, ~[]);
+    api::install_pkg(&context, os::getcwd(), ~"fancy-lib", None, ~[]);
 }
diff --git a/src/librustpkg/util.rs b/src/librustpkg/util.rs
index 628c0b937af..57fcf564c5d 100644
--- a/src/librustpkg/util.rs
+++ b/src/librustpkg/util.rs
@@ -10,6 +10,10 @@
 
 #[allow(dead_code)];
 
+pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
+pub use target::{Target, Build, Install};
+pub use target::{lib_name_of, lib_crate_filename, WhatToBuild, MaybeCustom, Inferred};
+
 use std::cell::RefCell;
 use std::libc;
 use std::os;
@@ -17,7 +21,7 @@ use std::io;
 use std::io::fs;
 use extra::workcache;
 use rustc::metadata::creader::Loader;
-use rustc::driver::{driver, session};
+use extra::treemap::TreeMap;
 use extra::getopts::groups::getopts;
 use syntax;
 use syntax::codemap::{DUMMY_SP, Spanned};
@@ -28,19 +32,16 @@ use syntax::attr::AttrMetaMethods;
 use syntax::fold::Folder;
 use syntax::visit::Visitor;
 use syntax::util::small_vector::SmallVector;
+use syntax::crateid::CrateId;
 use rustc::back::link::OutputTypeExe;
 use rustc::back::link;
+use rustc::driver::{driver, session};
 use CtxMethods;
 use context::{in_target, StopBefore, Link, Assemble, BuildContext};
-use crate_id::CrateId;
 use package_source::PkgSrc;
 use workspace::pkg_parent_workspaces;
 use path_util::{system_library, target_build_dir};
 use path_util::{default_workspace, built_library_in_workspace};
-pub use target::{OutputType, Main, Lib, Bench, Test, JustOne, lib_name_of, lib_crate_filename};
-pub use target::{Target, Build, Install};
-use extra::treemap::TreeMap;
-pub use target::{lib_name_of, lib_crate_filename, WhatToBuild, MaybeCustom, Inferred};
 use workcache_support::{digest_file_with_date, digest_only_date};
 use messages::error;
 
@@ -135,7 +136,7 @@ struct CrateSetup<'a> {
     ctx: &'a mut ReadyCtx<'a>,
 }
 
-impl<'a> fold::Folder for CrateSetup<'a> {
+impl<'a> Folder for CrateSetup<'a> {
     fn fold_item(&mut self, item: @ast::Item) -> SmallVector<@ast::Item> {
         fold_item(item, self)
     }
@@ -162,7 +163,7 @@ pub fn ready_crate(sess: session::Session,
 
 pub fn compile_input(context: &BuildContext,
                      exec: &mut workcache::Exec,
-                     pkg_id: &CrateId,
+                     crate_id: &CrateId,
                      in_file: &Path,
                      workspace: &Path,
                      deps: &mut DepMap,
@@ -177,11 +178,11 @@ pub fn compile_input(context: &BuildContext,
     // not sure if we should support anything else
 
     let mut out_dir = target_build_dir(workspace);
-    out_dir.push(&pkg_id.path);
+    out_dir.push(crate_id.path.as_slice());
     // Make the output directory if it doesn't exist already
     fs::mkdir_recursive(&out_dir, io::UserRWX);
 
-    let binary = os::args()[0].to_owned();
+    let binary = os::args()[0];
 
     debug!("flags: {}", flags.connect(" "));
     debug!("cfgs: {}", cfgs.connect(" "));
@@ -276,7 +277,7 @@ pub fn compile_input(context: &BuildContext,
     let (mut crate, ast_map) = {
         let installer = CrateInstaller {
             context: context,
-            parent: pkg_id,
+            parent: crate_id,
             parent_crate: in_file,
             sess: sess,
             exec: exec,
@@ -312,10 +313,7 @@ pub fn compile_input(context: &BuildContext,
     if !attr::contains_name(crate.attrs, "crate_id") {
         // FIXME (#9639): This needs to handle non-utf8 paths
         let crateid_attr =
-            attr::mk_name_value_item_str(@"crate_id",
-                                         format!("{}\\#{}",
-                                                 pkg_id.path.as_str().unwrap(),
-                                                 pkg_id.version.to_str()).to_managed());
+            attr::mk_name_value_item_str(@"crate_id", crate_id.to_str().to_managed());
 
         debug!("crateid attr: {:?}", crateid_attr);
         crate.attrs.push(attr::mk_attr(crateid_attr));
@@ -333,7 +331,7 @@ pub fn compile_input(context: &BuildContext,
                                           what);
     // Discover the output
     let discovered_output = if what == Lib  {
-        built_library_in_workspace(pkg_id, workspace) // Huh???
+        built_library_in_workspace(crate_id, workspace) // Huh???
     }
     else {
         result
@@ -435,7 +433,7 @@ pub fn exe_suffix() -> ~str { ~"" }
 // Called by build_crates
 pub fn compile_crate(ctxt: &BuildContext,
                      exec: &mut workcache::Exec,
-                     pkg_id: &CrateId,
+                     crate_id: &CrateId,
                      crate: &Path,
                      workspace: &Path,
                      deps: &mut DepMap,
@@ -444,11 +442,11 @@ pub fn compile_crate(ctxt: &BuildContext,
                      opt: session::OptLevel,
                      what: OutputType) -> Option<Path> {
     debug!("compile_crate: crate={}, workspace={}", crate.display(), workspace.display());
-    debug!("compile_crate: short_name = {}, flags =...", pkg_id.to_str());
+    debug!("compile_crate: name = {}, flags =...", crate_id.to_str());
     for fl in flags.iter() {
         debug!("+++ {}", *fl);
     }
-    compile_input(ctxt, exec, pkg_id, crate, workspace, deps, flags, cfgs, opt, what)
+    compile_input(ctxt, exec, crate_id, crate, workspace, deps, flags, cfgs, opt, what)
 }
 
 struct CrateInstaller<'a> {
@@ -473,8 +471,9 @@ impl<'a> CrateInstaller<'a> {
                     None => self.sess.str_of(lib_ident)
                 };
                 debug!("Finding and installing... {}", lib_name);
+                let crate_id: CrateId = from_str(lib_name).expect("valid crate id");
                 // Check standard Rust library path first
-                let whatever = system_library(&self.context.sysroot_to_use(), lib_name);
+                let whatever = system_library(&self.context.sysroot_to_use(), &crate_id);
                 debug!("system library returned {:?}", whatever);
                 match whatever {
                     Some(ref installed_path) => {
@@ -494,13 +493,11 @@ impl<'a> CrateInstaller<'a> {
                     }
                     None => {
                         // FIXME #8711: need to parse version out of path_opt
-                        debug!("Trying to install library {}, rebuilding it",
-                               lib_name.to_str());
+                        debug!("Trying to install library {}, rebuilding it", crate_id.to_str());
                         // Try to install it
-                        let pkg_id = CrateId::new(lib_name);
                         // Find all the workspaces in the RUST_PATH that contain this package.
                         let workspaces = pkg_parent_workspaces(&self.context.context,
-                                                               &pkg_id);
+                                                               &crate_id);
                         // Three cases:
                         // (a) `workspaces` is empty. That means there's no local source
                         // for this package. In that case, we pass the default workspace
@@ -529,8 +526,8 @@ impl<'a> CrateInstaller<'a> {
                                  // Nonexistent package? Then print a better error
                                  error(format!("Package {} depends on {}, but I don't know \
                                                how to find it",
-                                               self.parent.path.display(),
-                                               pkg_id.path.display()));
+                                               self.parent.path,
+                                               crate_id.path));
                                  fail!()
                         }).inside(|| {
                             PkgSrc::new(source_workspace.clone(),
@@ -538,7 +535,7 @@ impl<'a> CrateInstaller<'a> {
                                         // Use the rust_path_hack to search for dependencies iff
                                         // we were already using it
                                         self.context.context.use_rust_path_hack,
-                                        pkg_id.clone())
+                                        crate_id.clone())
                         });
                         let (outputs_disc, inputs_disc) =
                             self.context.install(
diff --git a/src/librustpkg/version.rs b/src/librustpkg/version.rs
index 77dbb335518..93e7a052efa 100644
--- a/src/librustpkg/version.rs
+++ b/src/librustpkg/version.rs
@@ -13,170 +13,9 @@
 
 extern mod std;
 
-use extra::semver;
-use std::{char, result, run, str};
-use extra::tempfile::TempDir;
-use path_util::rust_path;
+use std::char;
 
-#[deriving(Clone)]
-pub enum Version {
-    ExactRevision(~str), // Should look like a m.n.(...).x
-    SemanticVersion(semver::Version),
-    Tagged(~str), // String that can't be parsed as a version.
-                  // Requirements get interpreted exactly
-    NoVersion // user didn't specify a version -- prints as 0.0
-}
-
-// Equality on versions is non-symmetric: if self is NoVersion, it's equal to
-// anything; but if self is a precise version, it's not equal to NoVersion.
-// We should probably make equality symmetric, and use less-than and greater-than
-// where we currently use eq
-impl Eq for Version {
-    fn eq(&self, other: &Version) -> bool {
-        match (self, other) {
-            (&ExactRevision(ref s1), &ExactRevision(ref s2)) => *s1 == *s2,
-            (&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => *v1 == *v2,
-            (&NoVersion, _) => true,
-            _ => false
-        }
-    }
-}
-
-impl Ord for Version {
-    fn lt(&self, other: &Version) -> bool {
-        match (self, other) {
-            (&NoVersion, _) => true,
-            (&ExactRevision(ref f1), &ExactRevision(ref f2)) => f1 < f2,
-            (&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => v1 < v2,
-            _ => false // incomparable, really
-        }
-    }
-    fn le(&self, other: &Version) -> bool {
-        match (self, other) {
-            (&NoVersion, _) => true,
-            (&ExactRevision(ref f1), &ExactRevision(ref f2)) => f1 <= f2,
-            (&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => v1 <= v2,
-            _ => false // incomparable, really
-        }
-    }
-    fn ge(&self, other: &Version) -> bool {
-        match (self, other) {
-            (&ExactRevision(ref f1), &ExactRevision(ref f2)) => f1 > f2,
-            (&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => v1 > v2,
-            _ => false // incomparable, really
-        }
-    }
-    fn gt(&self, other: &Version) -> bool {
-        match (self, other) {
-            (&ExactRevision(ref f1), &ExactRevision(ref f2)) => f1 >= f2,
-            (&SemanticVersion(ref v1), &SemanticVersion(ref v2)) => v1 >= v2,
-            _ => false // incomparable, really
-        }
-    }
-
-}
-
-impl ToStr for Version {
-    fn to_str(&self) -> ~str {
-        match *self {
-            ExactRevision(ref n) | Tagged(ref n) => format!("{}", n.to_str()),
-            SemanticVersion(ref v) => format!("{}", v.to_str()),
-            NoVersion => ~"0.0"
-        }
-    }
-}
-
-pub fn parse_vers(vers: ~str) -> result::Result<semver::Version, ~str> {
-    match semver::parse(vers) {
-        Some(vers) => result::Ok(vers),
-        None => result::Err(~"could not parse version: invalid")
-    }
-}
-
-/// If `local_path` is a git repo in the RUST_PATH, and the most recent tag
-/// in that repo denotes a version, return it; otherwise, `None`
-pub fn try_getting_local_version(local_path: &Path) -> Option<Version> {
-    let rustpath = rust_path();
-    for rp in rustpath.iter() {
-        let local_path = rp.join(local_path);
-        let git_dir = local_path.join(".git");
-        if !git_dir.is_dir() {
-            continue;
-        }
-        // FIXME (#9639): This needs to handle non-utf8 paths
-        let opt_outp = run::process_output("git",
-                                   ["--git-dir=" + git_dir.as_str().unwrap(), ~"tag", ~"-l"]);
-        let outp = opt_outp.expect("Failed to exec `git`");
-
-        debug!("git --git-dir={} tag -l ~~~> {:?}", git_dir.display(), outp.status);
-
-        if !outp.status.success() {
-            continue;
-        }
-
-        let mut output = None;
-        let output_text = str::from_utf8(outp.output).unwrap();
-        for l in output_text.lines() {
-            if !l.is_whitespace() {
-                output = Some(l);
-            }
-            match output.and_then(try_parsing_version) {
-                Some(v) => return Some(v),
-                None    => ()
-            }
-        }
-    }
-    None
-}
-
-/// If `remote_path` refers to a git repo that can be downloaded,
-/// and the most recent tag in that repo denotes a version, return it;
-/// otherwise, `None`
-pub fn try_getting_version(remote_path: &Path) -> Option<Version> {
-    if is_url_like(remote_path) {
-        let tmp_dir = TempDir::new("test");
-        let tmp_dir = tmp_dir.expect("try_getting_version: couldn't create temp dir");
-        let tmp_dir = tmp_dir.path();
-        debug!("(to get version) executing \\{git clone https://{} {}\\}",
-               remote_path.display(),
-               tmp_dir.display());
-        // FIXME (#9639): This needs to handle non-utf8 paths
-        let opt_outp = run::process_output("git", [~"clone", format!("https://{}",
-                                                                     remote_path.as_str().unwrap()),
-                                                   tmp_dir.as_str().unwrap().to_owned()]);
-        let outp = opt_outp.expect("Failed to exec `git`");
-        if outp.status.success() {
-            debug!("Cloned it... ( {}, {} )",
-                   str::from_utf8(outp.output).unwrap(),
-                   str::from_utf8(outp.error).unwrap());
-            let mut output = None;
-            let git_dir = tmp_dir.join(".git");
-            debug!("(getting version, now getting tags) executing \\{git --git-dir={} tag -l\\}",
-                   git_dir.display());
-            // FIXME (#9639): This needs to handle non-utf8 paths
-            let opt_outp = run::process_output("git",
-                                               ["--git-dir=" + git_dir.as_str().unwrap(),
-                                                ~"tag", ~"-l"]);
-            let outp = opt_outp.expect("Failed to exec `git`");
-            let output_text = str::from_utf8(outp.output).unwrap();
-            debug!("Full output: ( {} ) [{:?}]", output_text, outp.status);
-            for l in output_text.lines() {
-                debug!("A line of output: {}", l);
-                if !l.is_whitespace() {
-                    output = Some(l);
-                }
-            }
-
-            output.and_then(try_parsing_version)
-        }
-        else {
-            None
-        }
-    }
-    else {
-        None
-    }
-}
+pub type Version = Option<~str>;
 
 // Being lazy since we don't have a regexp library now
 #[deriving(Eq)]
@@ -186,7 +25,7 @@ enum ParseState {
     SawDot
 }
 
-pub fn try_parsing_version(s: &str) -> Option<Version> {
+pub fn try_parsing_version(s: &str) -> Option<~str> {
     let s = s.trim();
     debug!("Attempting to parse: {}", s);
     let mut parse_state = Start;
@@ -202,17 +41,11 @@ pub fn try_parsing_version(s: &str) -> Option<Version> {
         }
     }
     match parse_state {
-        SawDigit => Some(ExactRevision(s.to_owned())),
+        SawDigit => Some(s.to_owned()),
         _        => None
     }
 }
 
-/// Just an approximation
-fn is_url_like(p: &Path) -> bool {
-    // check if there are more than 2 /-separated components
-    p.as_vec().split(|b| *b == '/' as u8).nth(2).is_some()
-}
-
 /// If s is of the form foo#bar, where bar is a valid version
 /// number, return the prefix before the # and the version.
 /// Otherwise, return None.
@@ -229,7 +62,7 @@ pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Vers
         Some(i) => {
             let path = s.slice(0, i);
             // n.b. for now, assuming an exact revision is intended, not a SemVer
-            Some((path, ExactRevision(s.slice(i + 1, s.len()).to_owned())))
+            Some((path, Some(s.slice(i + 1, s.len()).to_owned())))
         }
         None => {
             None
@@ -239,11 +72,11 @@ pub fn split_version_general<'a>(s: &'a str, sep: char) -> Option<(&'a str, Vers
 
 #[test]
 fn test_parse_version() {
-    assert!(try_parsing_version("1.2") == Some(ExactRevision(~"1.2")));
-    assert!(try_parsing_version("1.0.17") == Some(ExactRevision(~"1.0.17")));
+    assert!(try_parsing_version("1.2") == Some(~"1.2"));
+    assert!(try_parsing_version("1.0.17") == Some(~"1.0.17"));
     assert!(try_parsing_version("you're_a_kitty") == None);
     assert!(try_parsing_version("42..1") == None);
-    assert!(try_parsing_version("17") == Some(ExactRevision(~"17")));
+    assert!(try_parsing_version("17") == Some(~"17"));
     assert!(try_parsing_version(".1.2.3") == None);
     assert!(try_parsing_version("2.3.") == None);
 }
@@ -252,9 +85,9 @@ fn test_parse_version() {
 fn test_split_version() {
     let s = "a/b/c#0.1";
     debug!("== {:?} ==", split_version(s));
-    assert!(split_version(s) == Some((s.slice(0, 5), ExactRevision(~"0.1"))));
+    assert!(split_version(s) == Some((s.slice(0, 5), Some(~"0.1"))));
     assert!(split_version("a/b/c") == None);
     let s = "a#1.2";
-    assert!(split_version(s) == Some((s.slice(0, 1), ExactRevision(~"1.2"))));
+    assert!(split_version(s) == Some((s.slice(0, 1), Some(~"1.2"))));
     assert!(split_version("a#a#3.4") == None);
 }
diff --git a/src/librustpkg/workspace.rs b/src/librustpkg/workspace.rs
index d6e617d2d50..e19a19dc8ab 100644
--- a/src/librustpkg/workspace.rs
+++ b/src/librustpkg/workspace.rs
@@ -11,12 +11,11 @@
 // rustpkg utilities having to do with workspaces
 
 use std::os;
-use std::path::Path;
 use context::Context;
 use path_util::{workspace_contains_crate_id, find_dir_using_rust_path_hack, default_workspace};
 use path_util::rust_path;
 use util::option_to_vec;
-use crate_id::CrateId;
+use syntax::crateid::CrateId;
 
 pub fn each_pkg_parent_workspace(cx: &Context,
                                  crateid: &CrateId,
@@ -29,7 +28,7 @@ pub fn each_pkg_parent_workspace(cx: &Context,
         // tjc: make this a condition
         fail!("Package {} not found in any of \
                     the following workspaces: {}",
-                   crateid.path.display(),
+                   crateid.path,
                    rust_path().map(|p| p.display().to_str()).to_str());
     }
     for ws in workspaces.iter() {
@@ -64,7 +63,8 @@ pub fn cwd_to_workspace() -> Option<(Path, CrateId)> {
             let rel = cwd.path_relative_from(&srcpath);
             let rel_s = rel.as_ref().and_then(|p|p.as_str());
             if rel_s.is_some() {
-                return Some((path, CrateId::new(rel_s.unwrap())));
+                let crate_id = from_str(rel_s.unwrap()).expect("valid crate id");
+                return Some((path, crate_id));
             }
         }
     }
diff --git a/src/librustuv/uvll.rs b/src/librustuv/uvll.rs
index 189a820cd3e..0a6e23e9956 100644
--- a/src/librustuv/uvll.rs
+++ b/src/librustuv/uvll.rs
@@ -373,7 +373,7 @@ pub unsafe fn malloc_handle(handle: uv_handle_type) -> *c_void {
 }
 
 pub unsafe fn free_handle(v: *c_void) {
-    free(v)
+    free(v as *mut c_void)
 }
 
 pub unsafe fn malloc_req(req: uv_req_type) -> *c_void {
@@ -383,7 +383,7 @@ pub unsafe fn malloc_req(req: uv_req_type) -> *c_void {
 }
 
 pub unsafe fn free_req(v: *c_void) {
-    free(v)
+    free(v as *mut c_void)
 }
 
 #[test]
diff --git a/src/libstd/c_str.rs b/src/libstd/c_str.rs
index c735e325068..22e93e58194 100644
--- a/src/libstd/c_str.rs
+++ b/src/libstd/c_str.rs
@@ -183,7 +183,7 @@ impl Drop for CString {
     fn drop(&mut self) {
         if self.owns_buffer_ {
             unsafe {
-                libc::free(self.buf as *libc::c_void)
+                libc::free(self.buf as *mut libc::c_void)
             }
         }
     }
@@ -459,7 +459,7 @@ mod tests {
     #[test]
     fn test_unwrap() {
         let c_str = "hello".to_c_str();
-        unsafe { libc::free(c_str.unwrap() as *libc::c_void) }
+        unsafe { libc::free(c_str.unwrap() as *mut libc::c_void) }
     }
 
     #[test]
diff --git a/src/libstd/cleanup.rs b/src/libstd/cleanup.rs
index ab374ebccfe..40c4ad842ff 100644
--- a/src/libstd/cleanup.rs
+++ b/src/libstd/cleanup.rs
@@ -10,12 +10,11 @@
 
 #[doc(hidden)];
 
-use libc::c_void;
 use ptr;
 use unstable::intrinsics::TyDesc;
 use unstable::raw;
 
-type DropGlue<'a> = 'a |**TyDesc, *c_void|;
+type DropGlue<'a> = 'a |**TyDesc, *u8|;
 
 static RC_IMMORTAL : uint = 0x77777777;
 
@@ -107,7 +106,7 @@ pub unsafe fn annihilate() {
         stats.n_bytes_freed +=
             (*((*alloc).type_desc)).size
             + mem::size_of::<raw::Box<()>>();
-        local_free(alloc as *i8);
+        local_free(alloc as *u8);
         true
     });
 
diff --git a/src/libstd/fmt/mod.rs b/src/libstd/fmt/mod.rs
index 411f9f25459..5b2a792a05b 100644
--- a/src/libstd/fmt/mod.rs
+++ b/src/libstd/fmt/mod.rs
@@ -147,6 +147,8 @@ The current mapping of types to traits is:
 * `p` ⇒ `Pointer`
 * `t` ⇒ `Binary`
 * `f` ⇒ `Float`
+* `e` ⇒ `LowerExp`
+* `E` ⇒ `UpperExp`
 * *nothing* ⇒ `Default`
 
 What this means is that any type of argument which implements the
@@ -578,6 +580,12 @@ pub trait Pointer { fn fmt(&Self, &mut Formatter); }
 /// Format trait for the `f` character
 #[allow(missing_doc)]
 pub trait Float { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `e` character
+#[allow(missing_doc)]
+pub trait LowerExp { fn fmt(&Self, &mut Formatter); }
+/// Format trait for the `E` character
+#[allow(missing_doc)]
+pub trait UpperExp { fn fmt(&Self, &mut Formatter); }
 
 /// The `write` function takes an output stream, a precompiled format string,
 /// and a list of arguments. The arguments will be formatted according to the
@@ -1085,6 +1093,28 @@ macro_rules! floating(($ty:ident) => {
             fmt.pad_integral(s.as_bytes(), "", *f >= 0.0);
         }
     }
+
+    impl LowerExp for $ty {
+        fn fmt(f: &$ty, fmt: &mut Formatter) {
+            // XXX: this shouldn't perform an allocation
+            let s = match fmt.precision {
+                Some(i) => ::$ty::to_str_exp_exact(f.abs(), i, false),
+                None => ::$ty::to_str_exp_digits(f.abs(), 6, false)
+            };
+            fmt.pad_integral(s.as_bytes(), "", *f >= 0.0);
+        }
+    }
+
+    impl UpperExp for $ty {
+        fn fmt(f: &$ty, fmt: &mut Formatter) {
+            // XXX: this shouldn't perform an allocation
+            let s = match fmt.precision {
+                Some(i) => ::$ty::to_str_exp_exact(f.abs(), i, true),
+                None => ::$ty::to_str_exp_digits(f.abs(), 6, true)
+            };
+            fmt.pad_integral(s.as_bytes(), "", *f >= 0.0);
+        }
+    }
 })
 floating!(f32)
 floating!(f64)
diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs
index 7f19105cdc8..13a03d32525 100644
--- a/src/libstd/hashmap.rs
+++ b/src/libstd/hashmap.rs
@@ -66,8 +66,9 @@ use rand::Rng;
 use rand;
 use uint;
 use util::replace;
-use vec::{ImmutableVector, MutableVector, OwnedVector};
-use vec;
+use vec::{ImmutableVector, MutableVector, OwnedVector, Items, MutItems};
+use vec_ng;
+use vec_ng::Vec;
 
 static INITIAL_CAPACITY: uint = 32u; // 2^5
 
@@ -90,7 +91,7 @@ pub struct HashMap<K,V> {
     priv k1: u64,
     priv resize_at: uint,
     priv size: uint,
-    priv buckets: ~[Option<Bucket<K, V>>],
+    priv buckets: Vec<Option<Bucket<K, V>>>
 }
 
 // We could rewrite FoundEntry to have type Option<&Bucket<K, V>>
@@ -151,7 +152,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> {
                              -> SearchResult {
         let mut ret = TableFull;
         self.bucket_sequence(hash, |i| {
-            match self.buckets[i] {
+            match self.buckets.as_slice()[i] {
                 Some(ref bkt) if bkt.hash == hash && *k == bkt.key => {
                     ret = FoundEntry(i); false
                 },
@@ -169,7 +170,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> {
                                                -> SearchResult {
         let mut ret = TableFull;
         self.bucket_sequence(hash, |i| {
-            match self.buckets[i] {
+            match self.buckets.as_slice()[i] {
                 Some(ref bkt) if bkt.hash == hash && k.equiv(&bkt.key) => {
                     ret = FoundEntry(i); false
                 },
@@ -194,7 +195,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> {
         self.resize_at = resize_at(new_capacity);
 
         let old_buckets = replace(&mut self.buckets,
-                                  vec::from_fn(new_capacity, |_| None));
+                                  Vec::from_fn(new_capacity, |_| None));
 
         self.size = 0;
         for bucket in old_buckets.move_iter() {
@@ -213,7 +214,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> {
 
     #[inline]
     fn value_for_bucket<'a>(&'a self, idx: uint) -> &'a V {
-        match self.buckets[idx] {
+        match self.buckets.as_slice()[idx] {
             Some(ref bkt) => &bkt.value,
             None => fail!("HashMap::find: internal logic error"),
         }
@@ -221,7 +222,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> {
 
     #[inline]
     fn mut_value_for_bucket<'a>(&'a mut self, idx: uint) -> &'a mut V {
-        match self.buckets[idx] {
+        match self.buckets.as_mut_slice()[idx] {
             Some(ref mut bkt) => &mut bkt.value,
             None => unreachable!()
         }
@@ -234,13 +235,12 @@ impl<K:Hash + Eq,V> HashMap<K, V> {
         match self.bucket_for_key_with_hash(hash, &k) {
             TableFull => { fail!("Internal logic error"); }
             FoundHole(idx) => {
-                self.buckets[idx] = Some(Bucket{hash: hash, key: k,
-                                                value: v});
+                self.buckets.as_mut_slice()[idx] = Some(Bucket{hash: hash, key: k, value: v});
                 self.size += 1;
                 None
             }
             FoundEntry(idx) => {
-                match self.buckets[idx] {
+                match self.buckets.as_mut_slice()[idx] {
                     None => { fail!("insert_internal: Internal logic error") }
                     Some(ref mut b) => {
                         b.hash = hash;
@@ -273,7 +273,7 @@ impl<K:Hash + Eq,V> HashMap<K, V> {
         };
 
         let len_buckets = self.buckets.len();
-        let bucket = self.buckets[idx].take();
+        let bucket = self.buckets.as_mut_slice()[idx].take();
 
         let value = bucket.map(|bucket| bucket.value);
 
@@ -281,8 +281,8 @@ impl<K:Hash + Eq,V> HashMap<K, V> {
         what our new size is ahead of time before we start insertions */
         let size = self.size - 1;
         idx = self.next_bucket(idx, len_buckets);
-        while self.buckets[idx].is_some() {
-            let bucket = self.buckets[idx].take();
+        while self.buckets.as_slice()[idx].is_some() {
+            let bucket = self.buckets.as_mut_slice()[idx].take();
             self.insert_opt_bucket(bucket);
             idx = self.next_bucket(idx, len_buckets);
         }
@@ -300,7 +300,7 @@ impl<K:Hash + Eq,V> Container for HashMap<K, V> {
 impl<K:Hash + Eq,V> Mutable for HashMap<K, V> {
     /// Clear the map, removing all key-value pairs.
     fn clear(&mut self) {
-        for bkt in self.buckets.mut_iter() {
+        for bkt in self.buckets.as_mut_slice().mut_iter() {
             *bkt = None;
         }
         self.size = 0;
@@ -380,7 +380,7 @@ impl<K: Hash + Eq, V> HashMap<K, V> {
             k0: k0, k1: k1,
             resize_at: resize_at(cap),
             size: 0,
-            buckets: vec::from_fn(cap, |_| None)
+            buckets: Vec::from_fn(cap, |_| None)
         }
     }
 
@@ -455,7 +455,7 @@ impl<K: Hash + Eq, V> HashMap<K, V> {
             FoundEntry(idx) => { found(&k, self.mut_value_for_bucket(idx), a); idx }
             FoundHole(idx) => {
                 let v = not_found(&k, a);
-                self.buckets[idx] = Some(Bucket{hash: hash, key: k, value: v});
+                self.buckets.as_mut_slice()[idx] = Some(Bucket{hash: hash, key: k, value: v});
                 self.size += 1;
                 idx
             }
@@ -541,14 +541,14 @@ impl<K: Hash + Eq, V> HashMap<K, V> {
     /// An iterator visiting all key-value pairs in arbitrary order.
     /// Iterator element type is (&'a K, &'a V).
     pub fn iter<'a>(&'a self) -> Entries<'a, K, V> {
-        Entries { iter: self.buckets.iter() }
+        Entries { iter: self.buckets.as_slice().iter() }
     }
 
     /// An iterator visiting all key-value pairs in arbitrary order,
     /// with mutable references to the values.
     /// Iterator element type is (&'a K, &'a mut V).
     pub fn mut_iter<'a>(&'a mut self) -> MutEntries<'a, K, V> {
-        MutEntries { iter: self.buckets.mut_iter() }
+        MutEntries { iter: self.buckets.as_mut_slice().mut_iter() }
     }
 
     /// Creates a consuming iterator, that is, one that moves each key-value
@@ -599,17 +599,17 @@ impl<K:Hash + Eq + Clone,V:Clone> Clone for HashMap<K,V> {
 /// HashMap iterator
 #[deriving(Clone)]
 pub struct Entries<'a, K, V> {
-    priv iter: vec::Items<'a, Option<Bucket<K, V>>>,
+    priv iter: Items<'a, Option<Bucket<K, V>>>,
 }
 
 /// HashMap mutable values iterator
 pub struct MutEntries<'a, K, V> {
-    priv iter: vec::MutItems<'a, Option<Bucket<K, V>>>,
+    priv iter: MutItems<'a, Option<Bucket<K, V>>>,
 }
 
 /// HashMap move iterator
 pub struct MoveEntries<K, V> {
-    priv iter: vec::MoveItems<Option<Bucket<K, V>>>,
+    priv iter: vec_ng::MoveItems<Option<Bucket<K, V>>>,
 }
 
 /// HashMap keys iterator
@@ -623,12 +623,12 @@ pub type Values<'a, K, V> =
 /// HashSet iterator
 #[deriving(Clone)]
 pub struct SetItems<'a, K> {
-    priv iter: vec::Items<'a, Option<Bucket<K, ()>>>,
+    priv iter: Items<'a, Option<Bucket<K, ()>>>,
 }
 
 /// HashSet move iterator
 pub struct SetMoveItems<K> {
-    priv iter: vec::MoveItems<Option<Bucket<K, ()>>>,
+    priv iter: vec_ng::MoveItems<Option<Bucket<K, ()>>>,
 }
 
 impl<'a, K, V> Iterator<(&'a K, &'a V)> for Entries<'a, K, V> {
@@ -807,7 +807,7 @@ impl<T:Hash + Eq> HashSet<T> {
     /// An iterator visiting all elements in arbitrary order.
     /// Iterator element type is &'a T.
     pub fn iter<'a>(&'a self) -> SetItems<'a, T> {
-        SetItems { iter: self.map.buckets.iter() }
+        SetItems { iter: self.map.buckets.as_slice().iter() }
     }
 
     /// Creates a consuming iterator, that is, one that moves each value out
diff --git a/src/libstd/io/test.rs b/src/libstd/io/test.rs
index 92b2cfa8be2..d81de989df7 100644
--- a/src/libstd/io/test.rs
+++ b/src/libstd/io/test.rs
@@ -34,6 +34,7 @@ macro_rules! iotest (
             use io::net::udp::*;
             #[cfg(unix)]
             use io::net::unix::*;
+            use io::timer::*;
             use io::process::*;
             use str;
             use util;
diff --git a/src/libstd/io/timer.rs b/src/libstd/io/timer.rs
index d156a7460e1..4bf89a1d559 100644
--- a/src/libstd/io/timer.rs
+++ b/src/libstd/io/timer.rs
@@ -96,61 +96,177 @@ impl Timer {
 
 #[cfg(test)]
 mod test {
-    use prelude::*;
-    use super::*;
-
-    #[test]
-    fn test_io_timer_sleep_simple() {
+    iotest!(fn test_io_timer_sleep_simple() {
         let mut timer = Timer::new().unwrap();
         timer.sleep(1);
-    }
+    })
 
-    #[test]
-    fn test_io_timer_sleep_oneshot() {
+    iotest!(fn test_io_timer_sleep_oneshot() {
         let mut timer = Timer::new().unwrap();
         timer.oneshot(1).recv();
-    }
+    })
 
-    #[test]
-    fn test_io_timer_sleep_oneshot_forget() {
+    iotest!(fn test_io_timer_sleep_oneshot_forget() {
         let mut timer = Timer::new().unwrap();
         timer.oneshot(100000000000);
-    }
+    })
 
-    #[test]
-    fn oneshot_twice() {
+    iotest!(fn oneshot_twice() {
         let mut timer = Timer::new().unwrap();
         let port1 = timer.oneshot(10000);
         let port = timer.oneshot(1);
         port.recv();
-        assert!(port1.recv_opt().is_none());
-    }
+        assert_eq!(port1.recv_opt(), None);
+    })
 
-    #[test]
-    fn test_io_timer_oneshot_then_sleep() {
+    iotest!(fn test_io_timer_oneshot_then_sleep() {
         let mut timer = Timer::new().unwrap();
         let port = timer.oneshot(100000000000);
         timer.sleep(1); // this should invalidate the port
-        assert!(port.recv_opt().is_none());
-    }
 
-    #[test]
-    fn test_io_timer_sleep_periodic() {
+        assert_eq!(port.recv_opt(), None);
+    })
+
+    iotest!(fn test_io_timer_sleep_periodic() {
         let mut timer = Timer::new().unwrap();
         let port = timer.periodic(1);
         port.recv();
         port.recv();
         port.recv();
-    }
+    })
 
-    #[test]
-    fn test_io_timer_sleep_periodic_forget() {
+    iotest!(fn test_io_timer_sleep_periodic_forget() {
         let mut timer = Timer::new().unwrap();
         timer.periodic(100000000000);
-    }
+    })
 
-    #[test]
-    fn test_io_timer_sleep_standalone() {
+    iotest!(fn test_io_timer_sleep_standalone() {
         sleep(1)
-    }
+    })
+
+    iotest!(fn oneshot() {
+        let mut timer = Timer::new().unwrap();
+
+        let port = timer.oneshot(1);
+        port.recv();
+        assert!(port.recv_opt().is_none());
+
+        let port = timer.oneshot(1);
+        port.recv();
+        assert!(port.recv_opt().is_none());
+    })
+
+    iotest!(fn override() {
+        let mut timer = Timer::new().unwrap();
+        let oport = timer.oneshot(100);
+        let pport = timer.periodic(100);
+        timer.sleep(1);
+        assert_eq!(oport.recv_opt(), None);
+        assert_eq!(pport.recv_opt(), None);
+        timer.oneshot(1).recv();
+    })
+
+    iotest!(fn period() {
+        let mut timer = Timer::new().unwrap();
+        let port = timer.periodic(1);
+        port.recv();
+        port.recv();
+        let port2 = timer.periodic(1);
+        port2.recv();
+        port2.recv();
+    })
+
+    iotest!(fn sleep() {
+        let mut timer = Timer::new().unwrap();
+        timer.sleep(1);
+        timer.sleep(1);
+    })
+
+    iotest!(fn oneshot_fail() {
+        let mut timer = Timer::new().unwrap();
+        let _port = timer.oneshot(1);
+        fail!();
+    } #[should_fail])
+
+    iotest!(fn period_fail() {
+        let mut timer = Timer::new().unwrap();
+        let _port = timer.periodic(1);
+        fail!();
+    } #[should_fail])
+
+    iotest!(fn normal_fail() {
+        let _timer = Timer::new().unwrap();
+        fail!();
+    } #[should_fail])
+
+    iotest!(fn closing_channel_during_drop_doesnt_kill_everything() {
+        // see issue #10375
+        let mut timer = Timer::new().unwrap();
+        let timer_port = timer.periodic(1000);
+
+        do spawn {
+            timer_port.recv_opt();
+        }
+
+        // when we drop the TimerWatcher we're going to destroy the channel,
+        // which must wake up the task on the other end
+    })
+
+    iotest!(fn reset_doesnt_switch_tasks() {
+        // similar test to the one above.
+        let mut timer = Timer::new().unwrap();
+        let timer_port = timer.periodic(1000);
+
+        do spawn {
+            timer_port.recv_opt();
+        }
+
+        timer.oneshot(1);
+    })
+
+    iotest!(fn reset_doesnt_switch_tasks2() {
+        // similar test to the one above.
+        let mut timer = Timer::new().unwrap();
+        let timer_port = timer.periodic(1000);
+
+        do spawn {
+            timer_port.recv_opt();
+        }
+
+        timer.sleep(1);
+    })
+
+    iotest!(fn sender_goes_away_oneshot() {
+        let port = {
+            let mut timer = Timer::new().unwrap();
+            timer.oneshot(1000)
+        };
+        assert_eq!(port.recv_opt(), None);
+    })
+
+    iotest!(fn sender_goes_away_period() {
+        let port = {
+            let mut timer = Timer::new().unwrap();
+            timer.periodic(1000)
+        };
+        assert_eq!(port.recv_opt(), None);
+    })
+
+    iotest!(fn receiver_goes_away_oneshot() {
+        let mut timer1 = Timer::new().unwrap();
+        timer1.oneshot(1);
+        let mut timer2 = Timer::new().unwrap();
+        // while sleeping, the prevous timer should fire and not have its
+        // callback do something terrible.
+        timer2.sleep(2);
+    })
+
+    iotest!(fn receiver_goes_away_period() {
+        let mut timer1 = Timer::new().unwrap();
+        timer1.periodic(1);
+        let mut timer2 = Timer::new().unwrap();
+        // while sleeping, the prevous timer should fire and not have its
+        // callback do something terrible.
+        timer2.sleep(2);
+    })
 }
diff --git a/src/libstd/iter.rs b/src/libstd/iter.rs
index 8081c6ed8db..a65da914373 100644
--- a/src/libstd/iter.rs
+++ b/src/libstd/iter.rs
@@ -670,21 +670,21 @@ pub trait DoubleEndedIterator<A>: Iterator<A> {
     /// Yield an element from the end of the range, returning `None` if the range is empty.
     fn next_back(&mut self) -> Option<A>;
 
-    /// Flip the direction of the iterator
+    /// Change the direction of the iterator
     ///
-    /// The inverted iterator flips the ends on an iterator that can already
+    /// The flipped iterator swaps the ends on an iterator that can already
     /// be iterated from the front and from the back.
     ///
     ///
-    /// If the iterator also implements RandomAccessIterator, the inverted
+    /// If the iterator also implements RandomAccessIterator, the flipped
     /// iterator is also random access, with the indices starting at the back
     /// of the original iterator.
     ///
-    /// Note: Random access with inverted indices still only applies to the first
+    /// Note: Random access with flipped indices still only applies to the first
     /// `uint::max_value` elements of the original iterator.
     #[inline]
-    fn invert(self) -> Invert<Self> {
-        Invert{iter: self}
+    fn rev(self) -> Rev<Self> {
+        Rev{iter: self}
     }
 }
 
@@ -759,30 +759,30 @@ pub trait ExactSize<A> : DoubleEndedIterator<A> {
 // Adaptors that may overflow in `size_hint` are not, i.e. `Chain`.
 impl<A, T: ExactSize<A>> ExactSize<(uint, A)> for Enumerate<T> {}
 impl<'a, A, T: ExactSize<A>> ExactSize<A> for Inspect<'a, A, T> {}
-impl<A, T: ExactSize<A>> ExactSize<A> for Invert<T> {}
+impl<A, T: ExactSize<A>> ExactSize<A> for Rev<T> {}
 impl<'a, A, B, T: ExactSize<A>> ExactSize<B> for Map<'a, A, B, T> {}
 impl<A, B, T: ExactSize<A>, U: ExactSize<B>> ExactSize<(A, B)> for Zip<T, U> {}
 
 /// An double-ended iterator with the direction inverted
 #[deriving(Clone)]
-pub struct Invert<T> {
+pub struct Rev<T> {
     priv iter: T
 }
 
-impl<A, T: DoubleEndedIterator<A>> Iterator<A> for Invert<T> {
+impl<A, T: DoubleEndedIterator<A>> Iterator<A> for Rev<T> {
     #[inline]
     fn next(&mut self) -> Option<A> { self.iter.next_back() }
     #[inline]
     fn size_hint(&self) -> (uint, Option<uint>) { self.iter.size_hint() }
 }
 
-impl<A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for Invert<T> {
+impl<A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for Rev<T> {
     #[inline]
     fn next_back(&mut self) -> Option<A> { self.iter.next() }
 }
 
 impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterator<A>
-    for Invert<T> {
+    for Rev<T> {
     #[inline]
     fn indexable(&self) -> uint { self.iter.indexable() }
     #[inline]
@@ -2590,12 +2590,12 @@ mod tests {
     }
 
     #[test]
-    fn test_invert() {
+    fn test_rev() {
         let xs = [2, 4, 6, 8, 10, 12, 14, 16];
         let mut it = xs.iter();
         it.next();
         it.next();
-        assert_eq!(it.invert().map(|&x| x).collect::<~[int]>(), ~[16, 14, 12, 10, 8, 6]);
+        assert_eq!(it.rev().map(|&x| x).collect::<~[int]>(), ~[16, 14, 12, 10, 8, 6]);
     }
 
     #[test]
@@ -2662,7 +2662,7 @@ mod tests {
     fn test_double_ended_chain() {
         let xs = [1, 2, 3, 4, 5];
         let ys = ~[7, 9, 11];
-        let mut it = xs.iter().chain(ys.iter()).invert();
+        let mut it = xs.iter().chain(ys.iter()).rev();
         assert_eq!(it.next().unwrap(), &11)
         assert_eq!(it.next().unwrap(), &9)
         assert_eq!(it.next_back().unwrap(), &1)
@@ -2764,10 +2764,10 @@ mod tests {
     }
 
     #[test]
-    fn test_random_access_invert() {
+    fn test_random_access_rev() {
         let xs = [1, 2, 3, 4, 5];
-        check_randacc_iter(xs.iter().invert(), xs.len());
-        let mut it = xs.iter().invert();
+        check_randacc_iter(xs.iter().rev(), xs.len());
+        let mut it = xs.iter().rev();
         it.next();
         it.next_back();
         it.next();
@@ -2833,13 +2833,13 @@ mod tests {
 
     #[test]
     fn test_double_ended_range() {
-        assert_eq!(range(11i, 14).invert().collect::<~[int]>(), ~[13i, 12, 11]);
-        for _ in range(10i, 0).invert() {
+        assert_eq!(range(11i, 14).rev().collect::<~[int]>(), ~[13i, 12, 11]);
+        for _ in range(10i, 0).rev() {
             fail!("unreachable");
         }
 
-        assert_eq!(range(11u, 14).invert().collect::<~[uint]>(), ~[13u, 12, 11]);
-        for _ in range(10u, 0).invert() {
+        assert_eq!(range(11u, 14).rev().collect::<~[uint]>(), ~[13u, 12, 11]);
+        for _ in range(10u, 0).rev() {
             fail!("unreachable");
         }
     }
@@ -2886,11 +2886,11 @@ mod tests {
 
         assert_eq!(range(0i, 5).collect::<~[int]>(), ~[0i, 1, 2, 3, 4]);
         assert_eq!(range(-10i, -1).collect::<~[int]>(), ~[-10, -9, -8, -7, -6, -5, -4, -3, -2]);
-        assert_eq!(range(0i, 5).invert().collect::<~[int]>(), ~[4, 3, 2, 1, 0]);
+        assert_eq!(range(0i, 5).rev().collect::<~[int]>(), ~[4, 3, 2, 1, 0]);
         assert_eq!(range(200, -5).collect::<~[int]>(), ~[]);
-        assert_eq!(range(200, -5).invert().collect::<~[int]>(), ~[]);
+        assert_eq!(range(200, -5).rev().collect::<~[int]>(), ~[]);
         assert_eq!(range(200, 200).collect::<~[int]>(), ~[]);
-        assert_eq!(range(200, 200).invert().collect::<~[int]>(), ~[]);
+        assert_eq!(range(200, 200).rev().collect::<~[int]>(), ~[]);
 
         assert_eq!(range(0i, 100).size_hint(), (100, Some(100)));
         // this test is only meaningful when sizeof uint < sizeof u64
@@ -2902,11 +2902,11 @@ mod tests {
     #[test]
     fn test_range_inclusive() {
         assert_eq!(range_inclusive(0i, 5).collect::<~[int]>(), ~[0i, 1, 2, 3, 4, 5]);
-        assert_eq!(range_inclusive(0i, 5).invert().collect::<~[int]>(), ~[5i, 4, 3, 2, 1, 0]);
+        assert_eq!(range_inclusive(0i, 5).rev().collect::<~[int]>(), ~[5i, 4, 3, 2, 1, 0]);
         assert_eq!(range_inclusive(200, -5).collect::<~[int]>(), ~[]);
-        assert_eq!(range_inclusive(200, -5).invert().collect::<~[int]>(), ~[]);
+        assert_eq!(range_inclusive(200, -5).rev().collect::<~[int]>(), ~[]);
         assert_eq!(range_inclusive(200, 200).collect::<~[int]>(), ~[200]);
-        assert_eq!(range_inclusive(200, 200).invert().collect::<~[int]>(), ~[200]);
+        assert_eq!(range_inclusive(200, 200).rev().collect::<~[int]>(), ~[200]);
     }
 
     #[test]
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index f4f83892a9c..7e53a0071bd 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -110,6 +110,7 @@ pub mod char;
 pub mod tuple;
 
 pub mod vec;
+pub mod vec_ng;
 pub mod at_vec;
 pub mod str;
 
diff --git a/src/libstd/libc.rs b/src/libstd/libc.rs
index 77ac226a7f1..6f2d64ff668 100644
--- a/src/libstd/libc.rs
+++ b/src/libstd/libc.rs
@@ -3225,7 +3225,7 @@ pub mod funcs {
                 pub fn calloc(nobj: size_t, size: size_t) -> *c_void;
                 pub fn malloc(size: size_t) -> *mut c_void;
                 pub fn realloc(p: *mut c_void, size: size_t) -> *mut c_void;
-                pub fn free(p: *c_void);
+                pub fn free(p: *mut c_void);
                 pub fn exit(status: c_int) -> !;
                 // Omitted: atexit.
                 pub fn system(s: *c_char) -> c_int;
@@ -3548,6 +3548,7 @@ pub mod funcs {
                 pub fn setsid() -> pid_t;
                 pub fn setuid(uid: uid_t) -> c_int;
                 pub fn sleep(secs: c_uint) -> c_uint;
+                pub fn usleep(secs: c_uint) -> c_int;
                 pub fn sysconf(name: c_int) -> c_long;
                 pub fn tcgetpgrp(fd: c_int) -> pid_t;
                 pub fn ttyname(fd: c_int) -> *c_char;
diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs
index 7ef7a256c16..7406fe8ee40 100644
--- a/src/libstd/local_data.rs
+++ b/src/libstd/local_data.rs
@@ -41,10 +41,9 @@ local_data::get(key_vector, |opt| assert_eq!(*opt.unwrap(), ~[4]));
 // magic.
 
 use cast;
-use libc;
 use prelude::*;
 use rt::task::{Task, LocalStorage};
-use util;
+use util::replace;
 
 /**
  * Indexes a task-local data slot. This pointer is used for comparison to
@@ -87,7 +86,7 @@ impl<T: 'static> LocalData for T {}
 // n.b. If TLS is used heavily in future, this could be made more efficient with
 //      a proper map.
 #[doc(hidden)]
-pub type Map = ~[Option<(*libc::c_void, TLSValue, LoanState)>];
+pub type Map = ~[Option<(*u8, TLSValue, LoanState)>];
 type TLSValue = ~LocalData;
 
 // Gets the map from the runtime. Lazily initialises if not done so already.
@@ -128,7 +127,7 @@ impl LoanState {
     }
 }
 
-fn key_to_key_value<T: 'static>(key: Key<T>) -> *libc::c_void {
+fn key_to_key_value<T: 'static>(key: Key<T>) -> *u8 {
     unsafe { cast::transmute(key) }
 }
 
@@ -151,7 +150,7 @@ pub fn pop<T: 'static>(key: Key<T>) -> Option<T> {
                 // Move the data out of the `entry` slot via util::replace.
                 // This is guaranteed to succeed because we already matched
                 // on `Some` above.
-                let data = match util::replace(entry, None) {
+                let data = match replace(entry, None) {
                     Some((_, data, _)) => data,
                     None => abort()
                 };
@@ -302,7 +301,7 @@ pub fn set<T: 'static>(key: Key<T>, data: T) {
     let data = ~data as ~LocalData:;
 
     fn insertion_position(map: &mut Map,
-                          key: *libc::c_void) -> Option<uint> {
+                          key: *u8) -> Option<uint> {
         // First see if the map contains this key already
         let curspot = map.iter().position(|entry| {
             match *entry {
diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs
index 5b0c75ef174..0af8f155c68 100644
--- a/src/libstd/num/f32.rs
+++ b/src/libstd/num/f32.rs
@@ -285,20 +285,16 @@ impl Signed for f32 {
     #[inline]
     fn abs(&self) -> f32 { abs(*self) }
 
-    ///
     /// The positive difference of two numbers. Returns `0.0` if the number is less than or
     /// equal to `other`, otherwise the difference between`self` and `other` is returned.
-    ///
     #[inline]
     fn abs_sub(&self, other: &f32) -> f32 { abs_sub(*self, *other) }
 
-    ///
     /// # Returns
     ///
     /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
     /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
     /// - `NAN` if the number is NaN
-    ///
     #[inline]
     fn signum(&self) -> f32 {
         if self.is_nan() { NAN } else { copysign(1.0, *self) }
@@ -330,14 +326,12 @@ impl Round for f32 {
     #[inline]
     fn trunc(&self) -> f32 { trunc(*self) }
 
-    ///
     /// The fractional part of the number, satisfying:
     ///
     /// ```rust
     /// let x = 1.65f32;
     /// assert!(x == x.trunc() + x.fract())
     /// ```
-    ///
     #[inline]
     fn fract(&self) -> f32 { *self - self.trunc() }
 }
@@ -490,7 +484,6 @@ impl Real for f32 {
     #[inline]
     fn tanh(&self) -> f32 { tanh(*self) }
 
-    ///
     /// Inverse hyperbolic sine
     ///
     /// # Returns
@@ -498,7 +491,6 @@ impl Real for f32 {
     /// - on success, the inverse hyperbolic sine of `self` will be returned
     /// - `self` if `self` is `0.0`, `-0.0`, `INFINITY`, or `NEG_INFINITY`
     /// - `NAN` if `self` is `NAN`
-    ///
     #[inline]
     fn asinh(&self) -> f32 {
         match *self {
@@ -507,7 +499,6 @@ impl Real for f32 {
         }
     }
 
-    ///
     /// Inverse hyperbolic cosine
     ///
     /// # Returns
@@ -515,7 +506,6 @@ impl Real for f32 {
     /// - on success, the inverse hyperbolic cosine of `self` will be returned
     /// - `INFINITY` if `self` is `INFINITY`
     /// - `NAN` if `self` is `NAN` or `self < 1.0` (including `NEG_INFINITY`)
-    ///
     #[inline]
     fn acosh(&self) -> f32 {
         match *self {
@@ -524,7 +514,6 @@ impl Real for f32 {
         }
     }
 
-    ///
     /// Inverse hyperbolic tangent
     ///
     /// # Returns
@@ -535,7 +524,6 @@ impl Real for f32 {
     /// - `NEG_INFINITY` if `self` is `-1.0`
     /// - `NAN` if the `self` is `NAN` or outside the domain of `-1.0 <= self <= 1.0`
     ///   (including `INFINITY` and `NEG_INFINITY`)
-    ///
     #[inline]
     fn atanh(&self) -> f32 {
         0.5 * ((2.0 * *self) / (1.0 - *self)).ln_1p()
@@ -643,12 +631,10 @@ impl Float for f32 {
         ldexp(x, exp as c_int)
     }
 
-    ///
     /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
     ///
     /// - `self = x * pow(2, exp)`
     /// - `0.5 <= abs(x) < 1.0`
-    ///
     #[inline]
     fn frexp(&self) -> (f32, int) {
         let mut exp = 0;
@@ -656,25 +642,19 @@ impl Float for f32 {
         (x, exp as int)
     }
 
-    ///
     /// Returns the exponential of the number, minus `1`, in a way that is accurate
     /// even if the number is close to zero
-    ///
     #[inline]
     fn exp_m1(&self) -> f32 { exp_m1(*self) }
 
-    ///
     /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
     /// than if the operations were performed separately
-    ///
     #[inline]
     fn ln_1p(&self) -> f32 { ln_1p(*self) }
 
-    ///
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
     /// produces a more accurate result with better performance than a separate multiplication
     /// operation followed by an add.
-    ///
     #[inline]
     fn mul_add(&self, a: f32, b: f32) -> f32 {
         mul_add(*self, a, b)
@@ -708,35 +688,30 @@ impl Float for f32 {
 // Section: String Conversions
 //
 
-///
 /// Converts a float to a string
 ///
 /// # Arguments
 ///
 /// * num - The float value
-///
 #[inline]
 pub fn to_str(num: f32) -> ~str {
     let (r, _) = strconv::float_to_str_common(
-        num, 10u, true, strconv::SignNeg, strconv::DigAll);
+        num, 10u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
     r
 }
 
-///
 /// Converts a float to a string in hexadecimal format
 ///
 /// # Arguments
 ///
 /// * num - The float value
-///
 #[inline]
 pub fn to_str_hex(num: f32) -> ~str {
     let (r, _) = strconv::float_to_str_common(
-        num, 16u, true, strconv::SignNeg, strconv::DigAll);
+        num, 16u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
     r
 }
 
-///
 /// Converts a float to a string in a given radix, and a flag indicating
 /// whether it's a special value
 ///
@@ -744,14 +719,12 @@ pub fn to_str_hex(num: f32) -> ~str {
 ///
 /// * num - The float value
 /// * radix - The base to use
-///
 #[inline]
 pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
     strconv::float_to_str_common(num, rdx, true,
-                           strconv::SignNeg, strconv::DigAll)
+                           strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false)
 }
 
-///
 /// Converts a float to a string with exactly the number of
 /// provided significant digits
 ///
@@ -759,15 +732,13 @@ pub fn to_str_radix_special(num: f32, rdx: uint) -> (~str, bool) {
 ///
 /// * num - The float value
 /// * digits - The number of significant digits
-///
 #[inline]
 pub fn to_str_exact(num: f32, dig: uint) -> ~str {
     let (r, _) = strconv::float_to_str_common(
-        num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
+        num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpNone, false);
     r
 }
 
-///
 /// Converts a float to a string with a maximum number of
 /// significant digits
 ///
@@ -775,11 +746,40 @@ pub fn to_str_exact(num: f32, dig: uint) -> ~str {
 ///
 /// * num - The float value
 /// * digits - The number of significant digits
-///
 #[inline]
 pub fn to_str_digits(num: f32, dig: uint) -> ~str {
     let (r, _) = strconv::float_to_str_common(
-        num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
+        num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpNone, false);
+    r
+}
+
+/// Converts a float to a string using the exponential notation with exactly the number of
+/// provided digits after the decimal point in the significand
+///
+/// # Arguments
+///
+/// * num - The float value
+/// * digits - The number of digits after the decimal point
+/// * upper - Use `E` instead of `e` for the exponent sign
+#[inline]
+pub fn to_str_exp_exact(num: f32, dig: uint, upper: bool) -> ~str {
+    let (r, _) = strconv::float_to_str_common(
+        num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpDec, upper);
+    r
+}
+
+/// Converts a float to a string using the exponential notation with the maximum number of
+/// digits after the decimal point in the significand
+///
+/// # Arguments
+///
+/// * num - The float value
+/// * digits - The number of digits after the decimal point
+/// * upper - Use `E` instead of `e` for the exponent sign
+#[inline]
+pub fn to_str_exp_digits(num: f32, dig: uint, upper: bool) -> ~str {
+    let (r, _) = strconv::float_to_str_common(
+        num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpDec, upper);
     r
 }
 
@@ -804,14 +804,13 @@ impl num::ToStrRadix for f32 {
     #[inline]
     fn to_str_radix(&self, rdx: uint) -> ~str {
         let (r, special) = strconv::float_to_str_common(
-            *self, rdx, true, strconv::SignNeg, strconv::DigAll);
+            *self, rdx, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
         if special { fail!("number has a special value, \
                             try to_str_radix_special() if those are expected") }
         r
     }
 }
 
-///
 /// Convert a string in base 16 to a float.
 /// Accepts a optional binary exponent.
 ///
@@ -837,7 +836,6 @@ impl num::ToStrRadix for f32 {
 ///
 /// `None` if the string did not represent a valid number.  Otherwise,
 /// `Some(n)` where `n` is the floating-point number represented by `[num]`.
-///
 #[inline]
 pub fn from_str_hex(num: &str) -> Option<f32> {
     strconv::from_str_common(num, 16u, true, true, true,
@@ -845,7 +843,6 @@ pub fn from_str_hex(num: &str) -> Option<f32> {
 }
 
 impl FromStr for f32 {
-    ///
     /// Convert a string in base 10 to a float.
     /// Accepts a optional decimal exponent.
     ///
@@ -871,7 +868,6 @@ impl FromStr for f32 {
     ///
     /// `None` if the string did not represent a valid number.  Otherwise,
     /// `Some(n)` where `n` is the floating-point number represented by `num`.
-    ///
     #[inline]
     fn from_str(val: &str) -> Option<f32> {
         strconv::from_str_common(val, 10u, true, true, true,
@@ -880,7 +876,6 @@ impl FromStr for f32 {
 }
 
 impl num::FromStrRadix for f32 {
-    ///
     /// Convert a string in an given base to a float.
     ///
     /// Due to possible conflicts, this function does **not** accept
@@ -898,7 +893,6 @@ impl num::FromStrRadix for f32 {
     ///
     /// `None` if the string did not represent a valid number. Otherwise,
     /// `Some(n)` where `n` is the floating-point number represented by `num`.
-    ///
     #[inline]
     fn from_str_radix(val: &str, rdx: uint) -> Option<f32> {
         strconv::from_str_common(val, rdx, true, true, false,
diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs
index 95e5797ae93..1155a89876e 100644
--- a/src/libstd/num/f64.rs
+++ b/src/libstd/num/f64.rs
@@ -287,20 +287,16 @@ impl Signed for f64 {
     #[inline]
     fn abs(&self) -> f64 { abs(*self) }
 
-    ///
     /// The positive difference of two numbers. Returns `0.0` if the number is less than or
     /// equal to `other`, otherwise the difference between`self` and `other` is returned.
-    ///
     #[inline]
     fn abs_sub(&self, other: &f64) -> f64 { abs_sub(*self, *other) }
 
-    ///
     /// # Returns
     ///
     /// - `1.0` if the number is positive, `+0.0` or `INFINITY`
     /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
     /// - `NAN` if the number is NaN
-    ///
     #[inline]
     fn signum(&self) -> f64 {
         if self.is_nan() { NAN } else { copysign(1.0, *self) }
@@ -332,14 +328,12 @@ impl Round for f64 {
     #[inline]
     fn trunc(&self) -> f64 { trunc(*self) }
 
-    ///
     /// The fractional part of the number, satisfying:
     ///
     /// ```rust
     /// let x = 1.65f64;
     /// assert!(x == x.trunc() + x.fract())
     /// ```
-    ///
     #[inline]
     fn fract(&self) -> f64 { *self - self.trunc() }
 }
@@ -492,7 +486,6 @@ impl Real for f64 {
     #[inline]
     fn tanh(&self) -> f64 { tanh(*self) }
 
-    ///
     /// Inverse hyperbolic sine
     ///
     /// # Returns
@@ -500,7 +493,6 @@ impl Real for f64 {
     /// - on success, the inverse hyperbolic sine of `self` will be returned
     /// - `self` if `self` is `0.0`, `-0.0`, `INFINITY`, or `NEG_INFINITY`
     /// - `NAN` if `self` is `NAN`
-    ///
     #[inline]
     fn asinh(&self) -> f64 {
         match *self {
@@ -509,7 +501,6 @@ impl Real for f64 {
         }
     }
 
-    ///
     /// Inverse hyperbolic cosine
     ///
     /// # Returns
@@ -517,7 +508,6 @@ impl Real for f64 {
     /// - on success, the inverse hyperbolic cosine of `self` will be returned
     /// - `INFINITY` if `self` is `INFINITY`
     /// - `NAN` if `self` is `NAN` or `self < 1.0` (including `NEG_INFINITY`)
-    ///
     #[inline]
     fn acosh(&self) -> f64 {
         match *self {
@@ -526,7 +516,6 @@ impl Real for f64 {
         }
     }
 
-    ///
     /// Inverse hyperbolic tangent
     ///
     /// # Returns
@@ -537,7 +526,6 @@ impl Real for f64 {
     /// - `NEG_INFINITY` if `self` is `-1.0`
     /// - `NAN` if the `self` is `NAN` or outside the domain of `-1.0 <= self <= 1.0`
     ///   (including `INFINITY` and `NEG_INFINITY`)
-    ///
     #[inline]
     fn atanh(&self) -> f64 {
         0.5 * ((2.0 * *self) / (1.0 - *self)).ln_1p()
@@ -645,12 +633,10 @@ impl Float for f64 {
         ldexp(x, exp as c_int)
     }
 
-    ///
     /// Breaks the number into a normalized fraction and a base-2 exponent, satisfying:
     ///
     /// - `self = x * pow(2, exp)`
     /// - `0.5 <= abs(x) < 1.0`
-    ///
     #[inline]
     fn frexp(&self) -> (f64, int) {
         let mut exp = 0;
@@ -658,25 +644,19 @@ impl Float for f64 {
         (x, exp as int)
     }
 
-    ///
     /// Returns the exponential of the number, minus `1`, in a way that is accurate
     /// even if the number is close to zero
-    ///
     #[inline]
     fn exp_m1(&self) -> f64 { exp_m1(*self) }
 
-    ///
     /// Returns the natural logarithm of the number plus `1` (`ln(1+n)`) more accurately
     /// than if the operations were performed separately
-    ///
     #[inline]
     fn ln_1p(&self) -> f64 { ln_1p(*self) }
 
-    ///
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding error. This
     /// produces a more accurate result with better performance than a separate multiplication
     /// operation followed by an add.
-    ///
     #[inline]
     fn mul_add(&self, a: f64, b: f64) -> f64 {
         mul_add(*self, a, b)
@@ -710,35 +690,30 @@ impl Float for f64 {
 // Section: String Conversions
 //
 
-///
 /// Converts a float to a string
 ///
 /// # Arguments
 ///
 /// * num - The float value
-///
 #[inline]
 pub fn to_str(num: f64) -> ~str {
     let (r, _) = strconv::float_to_str_common(
-        num, 10u, true, strconv::SignNeg, strconv::DigAll);
+        num, 10u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
     r
 }
 
-///
 /// Converts a float to a string in hexadecimal format
 ///
 /// # Arguments
 ///
 /// * num - The float value
-///
 #[inline]
 pub fn to_str_hex(num: f64) -> ~str {
     let (r, _) = strconv::float_to_str_common(
-        num, 16u, true, strconv::SignNeg, strconv::DigAll);
+        num, 16u, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
     r
 }
 
-///
 /// Converts a float to a string in a given radix, and a flag indicating
 /// whether it's a special value
 ///
@@ -746,14 +721,12 @@ pub fn to_str_hex(num: f64) -> ~str {
 ///
 /// * num - The float value
 /// * radix - The base to use
-///
 #[inline]
 pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
     strconv::float_to_str_common(num, rdx, true,
-                           strconv::SignNeg, strconv::DigAll)
+                           strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false)
 }
 
-///
 /// Converts a float to a string with exactly the number of
 /// provided significant digits
 ///
@@ -761,15 +734,13 @@ pub fn to_str_radix_special(num: f64, rdx: uint) -> (~str, bool) {
 ///
 /// * num - The float value
 /// * digits - The number of significant digits
-///
 #[inline]
 pub fn to_str_exact(num: f64, dig: uint) -> ~str {
     let (r, _) = strconv::float_to_str_common(
-        num, 10u, true, strconv::SignNeg, strconv::DigExact(dig));
+        num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpNone, false);
     r
 }
 
-///
 /// Converts a float to a string with a maximum number of
 /// significant digits
 ///
@@ -777,11 +748,40 @@ pub fn to_str_exact(num: f64, dig: uint) -> ~str {
 ///
 /// * num - The float value
 /// * digits - The number of significant digits
-///
 #[inline]
 pub fn to_str_digits(num: f64, dig: uint) -> ~str {
     let (r, _) = strconv::float_to_str_common(
-        num, 10u, true, strconv::SignNeg, strconv::DigMax(dig));
+        num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpNone, false);
+    r
+}
+
+/// Converts a float to a string using the exponential notation with exactly the number of
+/// provided digits after the decimal point in the significand
+///
+/// # Arguments
+///
+/// * num - The float value
+/// * digits - The number of digits after the decimal point
+/// * upper - Use `E` instead of `e` for the exponent sign
+#[inline]
+pub fn to_str_exp_exact(num: f64, dig: uint, upper: bool) -> ~str {
+    let (r, _) = strconv::float_to_str_common(
+        num, 10u, true, strconv::SignNeg, strconv::DigExact(dig), strconv::ExpDec, upper);
+    r
+}
+
+/// Converts a float to a string using the exponential notation with the maximum number of
+/// digits after the decimal point in the significand
+///
+/// # Arguments
+///
+/// * num - The float value
+/// * digits - The number of digits after the decimal point
+/// * upper - Use `E` instead of `e` for the exponent sign
+#[inline]
+pub fn to_str_exp_digits(num: f64, dig: uint, upper: bool) -> ~str {
+    let (r, _) = strconv::float_to_str_common(
+        num, 10u, true, strconv::SignNeg, strconv::DigMax(dig), strconv::ExpDec, upper);
     r
 }
 
@@ -806,14 +806,13 @@ impl num::ToStrRadix for f64 {
     #[inline]
     fn to_str_radix(&self, rdx: uint) -> ~str {
         let (r, special) = strconv::float_to_str_common(
-            *self, rdx, true, strconv::SignNeg, strconv::DigAll);
+            *self, rdx, true, strconv::SignNeg, strconv::DigAll, strconv::ExpNone, false);
         if special { fail!("number has a special value, \
                              try to_str_radix_special() if those are expected") }
         r
     }
 }
 
-///
 /// Convert a string in base 16 to a float.
 /// Accepts a optional binary exponent.
 ///
@@ -839,7 +838,6 @@ impl num::ToStrRadix for f64 {
 ///
 /// `None` if the string did not represent a valid number.  Otherwise,
 /// `Some(n)` where `n` is the floating-point number represented by `[num]`.
-///
 #[inline]
 pub fn from_str_hex(num: &str) -> Option<f64> {
     strconv::from_str_common(num, 16u, true, true, true,
@@ -847,7 +845,6 @@ pub fn from_str_hex(num: &str) -> Option<f64> {
 }
 
 impl FromStr for f64 {
-    ///
     /// Convert a string in base 10 to a float.
     /// Accepts a optional decimal exponent.
     ///
@@ -873,7 +870,6 @@ impl FromStr for f64 {
     ///
     /// `none` if the string did not represent a valid number.  Otherwise,
     /// `Some(n)` where `n` is the floating-point number represented by `num`.
-    ///
     #[inline]
     fn from_str(val: &str) -> Option<f64> {
         strconv::from_str_common(val, 10u, true, true, true,
@@ -882,7 +878,6 @@ impl FromStr for f64 {
 }
 
 impl num::FromStrRadix for f64 {
-    ///
     /// Convert a string in an given base to a float.
     ///
     /// Due to possible conflicts, this function does **not** accept
@@ -900,7 +895,6 @@ impl num::FromStrRadix for f64 {
     ///
     /// `None` if the string did not represent a valid number. Otherwise,
     /// `Some(n)` where `n` is the floating-point number represented by `num`.
-    ///
     #[inline]
     fn from_str_radix(val: &str, rdx: uint) -> Option<f64> {
         strconv::from_str_common(val, rdx, true, true, false,
diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs
index bf9e6b739f2..30abe86866e 100644
--- a/src/libstd/num/strconv.rs
+++ b/src/libstd/num/strconv.rs
@@ -207,11 +207,13 @@ pub fn int_to_str_bytes_common<T:NumCast
  * # Arguments
  * - `num`           - The number to convert. Accepts any number that
  *                     implements the numeric traits.
- * - `radix`         - Base to use. Accepts only the values 2-36.
+ * - `radix`         - Base to use. Accepts only the values 2-36. If the exponential notation
+ *                     is used, then this base is only used for the significand. The exponent
+ *                     itself always printed using a base of 10.
  * - `negative_zero` - Whether to treat the special value `-0` as
  *                     `-0` or as `+0`.
  * - `sign`          - How to emit the sign. Options are:
- *     - `SignNone`: No sign at all. Basically emits `abs(num)`.
+ *     - `SignNone`: No sign at all. The exponent sign is also omitted.
  *     - `SignNeg`:  Only `-` on negative values.
  *     - `SignAll`:  Both `+` on positive, and `-` on negative numbers.
  * - `digits`        - The amount of digits to use for emitting the
@@ -220,6 +222,17 @@ pub fn int_to_str_bytes_common<T:NumCast
  *                         fractions!
  *     - `DigMax(uint)`:   Maximum N digits, truncating any trailing zeros.
  *     - `DigExact(uint)`: Exactly N digits.
+ * - `exp_format`   - Whether or not to use the exponential (scientific) notation.
+ *                    Options are:
+ *     - `ExpNone`: Do not use the exponential notation.
+ *     - `ExpDec`:  Use the exponential notation with the exponent having a base of 10,
+ *                  and exponent sign being `'e'` or `'E'` depending on the value of
+ *                  the `exp_upper` argument. E.g. the number 1000 would be printed as 1e3.
+ *     - `ExpBin`:  Use the exponential notation with the exponent having a base of 2,
+ *                  and exponent sign being `'p'` or `'P'` depending on the value of
+ *                  the `exp_upper` argument. E.g. the number 8 would be printed as 1p3.
+ * - `exp_capital`   - Whether or not to use a capital letter for the exponent sign, if
+ *                     exponential notation is desired.
  *
  * # Return value
  * A tuple containing the byte vector, and a boolean flag indicating
@@ -229,12 +242,26 @@ pub fn int_to_str_bytes_common<T:NumCast
  *
  * # Failure
  * - Fails if `radix` < 2 or `radix` > 36.
+ * - Fails if `radix` > 14 and `exp_format` is `ExpDec` due to conflict
+ *   between digit and exponent sign `'e'`.
+ * - Fails if `radix` > 25 and `exp_format` is `ExpBin` due to conflict
+ *   between digit and exponent sign `'p'`.
  */
 pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+
                                   Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
         num: T, radix: uint, negative_zero: bool,
-        sign: SignFormat, digits: SignificantDigits) -> (~[u8], bool) {
+        sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool
+        ) -> (~[u8], bool) {
     assert!(2 <= radix && radix <= 36);
+    match exp_format {
+        ExpDec if radix >= DIGIT_E_RADIX       // decimal exponent 'e'
+          => fail!("float_to_str_bytes_common: radix {} incompatible with \
+                    use of 'e' as decimal exponent", radix),
+        ExpBin if radix >= DIGIT_P_RADIX       // binary exponent 'p'
+          => fail!("float_to_str_bytes_common: radix {} incompatible with \
+                    use of 'p' as binary exponent", radix),
+        _ => ()
+    }
 
     let _0: T = Zero::zero();
     let _1: T = One::one();
@@ -260,6 +287,23 @@ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+
     let mut buf: ~[u8] = ~[];
     let radix_gen: T   = cast(radix as int).unwrap();
 
+    let (num, exp) = match exp_format {
+        ExpNone => (num, 0i32),
+        ExpDec | ExpBin => {
+            if num == _0 {
+                (num, 0i32)
+            } else {
+                let (exp, exp_base) = match exp_format {
+                    ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()),
+                    ExpBin => (num.abs().log2().floor(), cast::<f64, T>(2.0f64).unwrap()),
+                    ExpNone => unreachable!()
+                };
+
+                (num / exp_base.powf(&exp), cast::<T, i32>(exp).unwrap())
+            }
+        }
+    };
+
     // First emit the non-fractional part, looping at least once to make
     // sure at least a `0` gets emitted.
     let mut deccum = num.trunc();
@@ -413,6 +457,21 @@ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+
         }
     }
 
+    match exp_format {
+        ExpNone => (),
+        _ => {
+            buf.push(match exp_format {
+                ExpDec if exp_upper => 'E',
+                ExpDec if !exp_upper => 'e',
+                ExpBin if exp_upper => 'P',
+                ExpBin if !exp_upper => 'p',
+                _ => unreachable!()
+            } as u8);
+
+            int_to_str_bytes_common(exp, 10, sign, |c| buf.push(c));
+        }
+    }
+
     (buf, false)
 }
 
@@ -424,9 +483,10 @@ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+Eq+Ord+Float+Round+
 pub fn float_to_str_common<T:NumCast+Zero+One+Eq+Ord+NumStrConv+Float+Round+
                              Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
         num: T, radix: uint, negative_zero: bool,
-        sign: SignFormat, digits: SignificantDigits) -> (~str, bool) {
+        sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool
+        ) -> (~str, bool) {
     let (bytes, special) = float_to_str_bytes_common(num, radix,
-                               negative_zero, sign, digits);
+                               negative_zero, sign, digits, exp_format, exp_capital);
     (str::from_utf8_owned(bytes).unwrap(), special)
 }
 
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 36ce3e93127..93762a3cdd5 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -44,9 +44,9 @@ use unstable::finally::Finally;
 use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
 
 /// Delegates to the libc close() function, returning the same return value.
-pub fn close(fd: c_int) -> c_int {
+pub fn close(fd: int) -> int {
     unsafe {
-        libc::close(fd)
+        libc::close(fd as c_int) as int
     }
 }
 
@@ -57,7 +57,7 @@ static BUF_BYTES : uint = 2048u;
 pub fn getcwd() -> Path {
     use c_str::CString;
 
-    let mut buf = [0 as libc::c_char, ..BUF_BYTES];
+    let mut buf = [0 as c_char, ..BUF_BYTES];
     unsafe {
         if libc::getcwd(buf.as_mut_ptr(), buf.len() as size_t).is_null() {
             fail!()
@@ -164,7 +164,7 @@ pub fn env() -> ~[(~str,~str)] {
                        os::last_os_error());
             }
             let mut result = ~[];
-            c_str::from_c_multistring(ch as *libc::c_char, None, |cstr| {
+            c_str::from_c_multistring(ch as *c_char, None, |cstr| {
                 result.push(cstr.as_str().unwrap().to_owned());
             });
             FreeEnvironmentStringsA(ch);
@@ -173,7 +173,7 @@ pub fn env() -> ~[(~str,~str)] {
         #[cfg(unix)]
         unsafe fn get_env_pairs() -> ~[~str] {
             extern {
-                fn rust_env_pairs() -> **libc::c_char;
+                fn rust_env_pairs() -> **c_char;
             }
             let environ = rust_env_pairs();
             if environ as uint == 0 {
@@ -306,9 +306,9 @@ pub struct Pipe {
 #[cfg(unix)]
 pub fn pipe() -> Pipe {
     unsafe {
-        let mut fds = Pipe {input: 0 as c_int,
-                            out: 0 as c_int };
-        assert_eq!(libc::pipe(&mut fds.input), (0 as c_int));
+        let mut fds = Pipe {input: 0,
+                            out: 0};
+        assert_eq!(libc::pipe(&mut fds.input), 0);
         return Pipe {input: fds.input, out: fds.out};
     }
 }
@@ -321,13 +321,13 @@ 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 std::run.
-        let mut fds = Pipe {input: 0 as c_int,
-                    out: 0 as c_int };
+        let mut fds = Pipe {input: 0,
+                    out: 0};
         let res = libc::pipe(&mut fds.input, 1024 as ::libc::c_uint,
                              (libc::O_BINARY | libc::O_NOINHERIT) as c_int);
-        assert_eq!(res, 0 as c_int);
-        assert!((fds.input != -1 as c_int && fds.input != 0 as c_int));
-        assert!((fds.out != -1 as c_int && fds.input != 0 as c_int));
+        assert_eq!(res, 0);
+        assert!((fds.input != -1 && fds.input != 0 ));
+        assert!((fds.out != -1 && fds.input != 0));
         return Pipe {input: fds.input, out: fds.out};
     }
 }
@@ -699,7 +699,7 @@ pub fn get_exit_status() -> int {
 }
 
 #[cfg(target_os = "macos")]
-unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] {
+unsafe fn load_argc_and_argv(argc: int, argv: **c_char) -> ~[~str] {
     let mut args = ~[];
     for i in range(0u, argc as uint) {
         args.push(str::raw::from_c_str(*argv.offset(i as int)));
@@ -715,7 +715,7 @@ unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] {
 #[cfg(target_os = "macos")]
 fn real_args() -> ~[~str] {
     unsafe {
-        let (argc, argv) = (*_NSGetArgc() as c_int,
+        let (argc, argv) = (*_NSGetArgc() as int,
                             *_NSGetArgv() as **c_char);
         load_argc_and_argv(argc, argv)
     }
@@ -833,7 +833,7 @@ pub struct MemoryMap {
     /// Pointer to the memory created or modified by this map.
     data: *mut u8,
     /// Number of bytes this map applies to
-    len: size_t,
+    len: uint,
     /// Type of mapping
     kind: MemoryMapKind
 }
@@ -842,7 +842,7 @@ pub struct MemoryMap {
 pub enum MemoryMapKind {
     /// Memory-mapped file. On Windows, the inner pointer is a handle to the mapping, and
     /// corresponds to `CreateFileMapping`. Elsewhere, it is null.
-    MapFile(*c_void),
+    MapFile(*u8),
     /// Virtual memory map. Usually used to change the permissions of a given chunk of memory.
     /// Corresponds to `VirtualAlloc` on Windows.
     MapVirtual
@@ -857,7 +857,7 @@ pub enum MapOption {
     /// The memory should be executable
     MapExecutable,
     /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on POSIX.
-    MapAddr(*c_void),
+    MapAddr(*u8),
     /// Create a memory mapping for a file with a given fd.
     MapFd(c_int),
     /// When using `MapFd`, the start of the map is `uint` bytes from the start of the file.
@@ -881,7 +881,7 @@ pub enum MapError {
     /// using `MapFd`, the target of the fd didn't have enough resources to fulfill the request.
     ErrNoMem,
     /// Unrecognized error. The inner value is the unrecognized errno.
-    ErrUnknown(libc::c_int),
+    ErrUnknown(int),
     /// ## The following are win32-specific
     ///
     /// Unsupported combination of protection flags (`MapReadable`/`MapWritable`/`MapExecutable`).
@@ -926,12 +926,12 @@ impl MemoryMap {
     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
         use libc::off_t;
 
-        let mut addr: *c_void = ptr::null();
-        let mut prot: c_int = 0;
-        let mut flags: c_int = libc::MAP_PRIVATE;
-        let mut fd: c_int = -1;
-        let mut offset: off_t = 0;
-        let len = round_up(min_len, page_size()) as size_t;
+        let mut addr: *u8 = ptr::null();
+        let mut prot = 0;
+        let mut flags = libc::MAP_PRIVATE;
+        let mut fd = -1;
+        let mut offset = 0;
+        let len = round_up(min_len, page_size());
 
         for &o in options.iter() {
             match o {
@@ -952,7 +952,7 @@ impl MemoryMap {
         if fd == -1 { flags |= libc::MAP_ANON; }
 
         let r = unsafe {
-            libc::mmap(addr, len, prot, flags, fd, offset)
+            libc::mmap(addr as *c_void, len as size_t, prot, flags, fd, offset)
         };
         if r.equiv(&libc::MAP_FAILED) {
             Err(match errno() as c_int {
@@ -961,7 +961,7 @@ impl MemoryMap {
                 libc::EINVAL => ErrUnaligned,
                 libc::ENODEV => ErrNoMapSupport,
                 libc::ENOMEM => ErrNoMem,
-                code => ErrUnknown(code)
+                code => ErrUnknown(code as int)
             })
         } else {
             Ok(MemoryMap {
@@ -987,7 +987,7 @@ impl Drop for MemoryMap {
     /// Unmap the mapping. Fails the task if `munmap` fails.
     fn drop(&mut self) {
         unsafe {
-            match libc::munmap(self.data as *c_void, self.len) {
+            match libc::munmap(self.data as *c_void, self.len as libc::size_t) {
                 0 => (),
                 -1 => match errno() as c_int {
                     libc::EINVAL => error!("invalid addr or len"),
@@ -1011,7 +1011,7 @@ impl MemoryMap {
         let mut executable = false;
         let mut fd: c_int = -1;
         let mut offset: uint = 0;
-        let len = round_up(min_len, page_size()) as SIZE_T;
+        let len = round_up(min_len, page_size());
 
         for &o in options.iter() {
             match o {
@@ -1040,7 +1040,7 @@ impl MemoryMap {
             }
             let r = unsafe {
                 libc::VirtualAlloc(lpAddress,
-                                   len,
+                                   len as SIZE_T,
                                    libc::MEM_COMMIT | libc::MEM_RESERVE,
                                    flProtect)
             };
@@ -1085,7 +1085,7 @@ impl MemoryMap {
                     _ => Ok(MemoryMap {
                        data: r as *mut u8,
                        len: len,
-                       kind: MapFile(mapping as *c_void)
+                       kind: MapFile(mapping as *u8)
                     })
                 }
             }
@@ -1116,7 +1116,7 @@ impl Drop for MemoryMap {
             match self.kind {
                 MapVirtual => {
                     if libc::VirtualFree(self.data as *mut c_void,
-                                         self.len,
+                                         self.len as size_t,
                                          libc::MEM_RELEASE) == FALSE {
                         error!("VirtualFree failed: {}", errno());
                     }
diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs
index 666b8977cc9..cc0705ee76f 100644
--- a/src/libstd/path/windows.rs
+++ b/src/libstd/path/windows.rs
@@ -17,7 +17,7 @@ use clone::Clone;
 use container::Container;
 use cmp::Eq;
 use from_str::FromStr;
-use iter::{AdditiveIterator, DoubleEndedIterator, Extendable, Invert, Iterator, Map};
+use iter::{AdditiveIterator, DoubleEndedIterator, Extendable, Rev, Iterator, Map};
 use option::{Option, Some, None};
 use str;
 use str::{CharSplits, OwnedStr, Str, StrVector, StrSlice};
@@ -35,7 +35,7 @@ pub type StrComponents<'a> = Map<'a, &'a str, Option<&'a str>,
 ///
 /// Each component is yielded as Option<&str> for compatibility with PosixPath, but
 /// every component in WindowsPath is guaranteed to be Some.
-pub type RevStrComponents<'a> = Invert<Map<'a, &'a str, Option<&'a str>,
+pub type RevStrComponents<'a> = Rev<Map<'a, &'a str, Option<&'a str>,
                                                  CharSplits<'a, char>>>;
 
 /// Iterator that yields successive components of a Path as &[u8]
@@ -571,8 +571,8 @@ impl GenericPath for Path {
 
     fn ends_with_path(&self, child: &Path) -> bool {
         if !child.is_relative() { return false; }
-        let mut selfit = self.str_components().invert();
-        let mut childit = child.str_components().invert();
+        let mut selfit = self.str_components().rev();
+        let mut childit = child.str_components().rev();
         loop {
             match (selfit.next(), childit.next()) {
                 (Some(a), Some(b)) => if a != b { return false; },
@@ -628,7 +628,7 @@ impl Path {
     /// Returns an iterator that yields each component of the path in reverse as an Option<&str>
     /// See str_components() for details.
     pub fn rev_str_components<'a>(&'a self) -> RevStrComponents<'a> {
-        self.str_components().invert()
+        self.str_components().rev()
     }
 
     /// Returns an iterator that yields each component of the path in turn as a &[u8].
diff --git a/src/libstd/rc.rs b/src/libstd/rc.rs
index 48e796f0f4a..fe82ac74069 100644
--- a/src/libstd/rc.rs
+++ b/src/libstd/rc.rs
@@ -78,7 +78,7 @@ impl<T> Drop for Rc<T> {
                 if (*self.ptr).strong == 0 {
                     read_ptr(self.borrow()); // destroy the contained object
                     if (*self.ptr).weak == 0 {
-                        exchange_free(self.ptr as *mut u8 as *i8)
+                        exchange_free(self.ptr as *u8)
                     }
                 }
             }
@@ -153,7 +153,7 @@ impl<T> Drop for Weak<T> {
             if self.ptr != 0 as *mut RcBox<T> {
                 (*self.ptr).weak -= 1;
                 if (*self.ptr).weak == 0 && (*self.ptr).strong == 0 {
-                    exchange_free(self.ptr as *mut u8 as *i8)
+                    exchange_free(self.ptr as *u8)
                 }
             }
         }
diff --git a/src/libstd/reflect.rs b/src/libstd/reflect.rs
index e619e404dac..c0af649f26c 100644
--- a/src/libstd/reflect.rs
+++ b/src/libstd/reflect.rs
@@ -17,7 +17,6 @@ Runtime type reflection
 #[allow(missing_doc)];
 
 use unstable::intrinsics::{Disr, Opaque, TyDesc, TyVisitor};
-use libc::c_void;
 use mem;
 use unstable::raw;
 
@@ -28,7 +27,7 @@ use unstable::raw;
  * then build a MovePtrAdaptor wrapped around your struct.
  */
 pub trait MovePtr {
-    fn move_ptr(&mut self, adjustment: |*c_void| -> *c_void);
+    fn move_ptr(&mut self, adjustment: |*u8| -> *u8);
     fn push_ptr(&mut self);
     fn pop_ptr(&mut self);
 }
@@ -50,12 +49,12 @@ pub fn MovePtrAdaptor<V:TyVisitor + MovePtr>(v: V) -> MovePtrAdaptor<V> {
 impl<V:TyVisitor + MovePtr> MovePtrAdaptor<V> {
     #[inline]
     pub fn bump(&mut self, sz: uint) {
-        self.inner.move_ptr(|p| ((p as uint) + sz) as *c_void)
+        self.inner.move_ptr(|p| ((p as uint) + sz) as *u8)
     }
 
     #[inline]
     pub fn align(&mut self, a: uint) {
-        self.inner.move_ptr(|p| align(p as uint, a) as *c_void)
+        self.inner.move_ptr(|p| align(p as uint, a) as *u8)
     }
 
     #[inline]
diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs
index 8919f9f8903..e3b34147c01 100644
--- a/src/libstd/repr.rs
+++ b/src/libstd/repr.rs
@@ -21,7 +21,6 @@ use char;
 use container::Container;
 use io;
 use iter::Iterator;
-use libc::c_void;
 use option::{Some, None};
 use ptr;
 use reflect;
@@ -98,13 +97,13 @@ enum VariantState {
 }
 
 pub struct ReprVisitor<'a> {
-    priv ptr: *c_void,
-    priv ptr_stk: ~[*c_void],
+    priv ptr: *u8,
+    priv ptr_stk: ~[*u8],
     priv var_stk: ~[VariantState],
     priv writer: &'a mut io::Writer
 }
 
-pub fn ReprVisitor<'a>(ptr: *c_void,
+pub fn ReprVisitor<'a>(ptr: *u8,
                        writer: &'a mut io::Writer) -> ReprVisitor<'a> {
     ReprVisitor {
         ptr: ptr,
@@ -116,7 +115,7 @@ pub fn ReprVisitor<'a>(ptr: *c_void,
 
 impl<'a> MovePtr for ReprVisitor<'a> {
     #[inline]
-    fn move_ptr(&mut self, adjustment: |*c_void| -> *c_void) {
+    fn move_ptr(&mut self, adjustment: |*u8| -> *u8) {
         self.ptr = adjustment(self.ptr);
     }
     fn push_ptr(&mut self) {
@@ -133,7 +132,7 @@ impl<'a> ReprVisitor<'a> {
     #[inline]
     pub fn get<T>(&mut self, f: |&mut ReprVisitor, &T|) -> bool {
         unsafe {
-            f(self, transmute::<*c_void,&T>(self.ptr));
+            f(self, transmute::<*u8,&T>(self.ptr));
         }
         true
     }
@@ -144,7 +143,7 @@ impl<'a> ReprVisitor<'a> {
     }
 
     #[inline]
-    pub fn visit_ptr_inner(&mut self, ptr: *c_void, inner: *TyDesc) -> bool {
+    pub fn visit_ptr_inner(&mut self, ptr: *u8, inner: *TyDesc) -> bool {
         unsafe {
             // This should call the constructor up above, but due to limiting
             // issues we have to recreate it here.
@@ -200,7 +199,7 @@ impl<'a> ReprVisitor<'a> {
             } else {
                 self.writer.write(", ".as_bytes());
             }
-            self.visit_ptr_inner(p as *c_void, inner);
+            self.visit_ptr_inner(p as *u8, inner);
             p = align(unsafe { ptr::offset(p, sz as int) as uint }, al) as *u8;
             left -= dec;
         }
@@ -298,20 +297,20 @@ impl<'a> TyVisitor for ReprVisitor<'a> {
         self.writer.write(['@' as u8]);
         self.write_mut_qualifier(mtbl);
         self.get::<&raw::Box<()>>(|this, b| {
-            let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
+            let p = ptr::to_unsafe_ptr(&b.data) as *u8;
             this.visit_ptr_inner(p, inner);
         })
     }
 
     fn visit_uniq(&mut self, _mtbl: uint, inner: *TyDesc) -> bool {
         self.writer.write(['~' as u8]);
-        self.get::<*c_void>(|this, b| {
+        self.get::<*u8>(|this, b| {
             this.visit_ptr_inner(*b, inner);
         })
     }
 
     fn visit_ptr(&mut self, mtbl: uint, _inner: *TyDesc) -> bool {
-        self.get::<*c_void>(|this, p| {
+        self.get::<*u8>(|this, p| {
             write!(this.writer, "({} as *", *p);
             this.write_mut_qualifier(mtbl);
             this.writer.write("())".as_bytes());
@@ -321,7 +320,7 @@ impl<'a> TyVisitor for ReprVisitor<'a> {
     fn visit_rptr(&mut self, mtbl: uint, inner: *TyDesc) -> bool {
         self.writer.write(['&' as u8]);
         self.write_mut_qualifier(mtbl);
-        self.get::<*c_void>(|this, p| {
+        self.get::<*u8>(|this, p| {
             this.visit_ptr_inner(*p, inner);
         })
     }
@@ -584,7 +583,7 @@ impl<'a> TyVisitor for ReprVisitor<'a> {
     fn visit_opaque_box(&mut self) -> bool {
         self.writer.write(['@' as u8]);
         self.get::<&raw::Box<()>>(|this, b| {
-            let p = ptr::to_unsafe_ptr(&b.data) as *c_void;
+            let p = ptr::to_unsafe_ptr(&b.data) as *u8;
             this.visit_ptr_inner(p, b.type_desc);
         })
     }
@@ -594,7 +593,7 @@ impl<'a> TyVisitor for ReprVisitor<'a> {
 
 pub fn write_repr<T>(writer: &mut io::Writer, object: &T) {
     unsafe {
-        let ptr = ptr::to_unsafe_ptr(object) as *c_void;
+        let ptr = ptr::to_unsafe_ptr(object) as *u8;
         let tydesc = get_tydesc::<T>();
         let u = ReprVisitor(ptr, writer);
         let mut v = reflect::MovePtrAdaptor(u);
diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs
new file mode 100644
index 00000000000..6f9be64a73d
--- /dev/null
+++ b/src/libstd/rt/at_exit_imp.rs
@@ -0,0 +1,72 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Implementation of running at_exit routines
+//!
+//! Documentation can be found on the `rt::at_exit` function.
+
+use cast;
+use iter::Iterator;
+use option::{Some, None};
+use ptr::RawPtr;
+use unstable::sync::Exclusive;
+use util;
+use vec::OwnedVector;
+
+type Queue = Exclusive<~[proc()]>;
+
+// You'll note that these variables are *not* atomic, and this is done on
+// purpose. This module is designed to have init() called *once* in a
+// single-task context, and then run() is called only once in another
+// single-task context. As a result of this, only the `push` function is
+// thread-safe, and it assumes that the `init` function has run previously.
+static mut QUEUE: *mut Queue = 0 as *mut Queue;
+static mut RUNNING: bool = false;
+
+pub fn init() {
+    unsafe {
+        rtassert!(!RUNNING);
+        rtassert!(QUEUE.is_null());
+        let state: ~Queue = ~Exclusive::new(~[]);
+        QUEUE = cast::transmute(state);
+    }
+}
+
+pub fn push(f: proc()) {
+    unsafe {
+        rtassert!(!RUNNING);
+        rtassert!(!QUEUE.is_null());
+        let state: &mut Queue = cast::transmute(QUEUE);
+        let mut f = Some(f);
+        state.with(|arr|  {
+            arr.push(f.take_unwrap());
+        });
+    }
+}
+
+pub fn run() {
+    let vec = unsafe {
+        rtassert!(!RUNNING);
+        rtassert!(!QUEUE.is_null());
+        RUNNING = true;
+        let state: ~Queue = cast::transmute(QUEUE);
+        QUEUE = 0 as *mut Queue;
+        let mut vec = None;
+        state.with(|arr| {
+            vec = Some(util::replace(arr, ~[]));
+        });
+        vec.take_unwrap()
+    };
+
+
+    for f in vec.move_iter() {
+        f();
+    }
+}
diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs
index 00195f726cb..6bee8cb70f5 100644
--- a/src/libstd/rt/global_heap.rs
+++ b/src/libstd/rt/global_heap.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use libc::{c_void, c_char, size_t, uintptr_t, free, malloc, realloc};
+use libc::{c_void, size_t, free, malloc, realloc};
 use ptr::{RawPtr, mut_null};
 use unstable::intrinsics::{TyDesc, abort};
 use unstable::raw;
@@ -31,7 +31,7 @@ fn align_to(size: uint, align: uint) -> uint {
 
 /// A wrapper around libc::malloc, aborting on out-of-memory
 #[inline]
-pub unsafe fn malloc_raw(size: uint) -> *mut c_void {
+pub unsafe fn malloc_raw(size: uint) -> *mut u8 {
     // `malloc(0)` may allocate, but it may also return a null pointer
     // http://pubs.opengroup.org/onlinepubs/9699919799/functions/malloc.html
     if size == 0 {
@@ -42,25 +42,25 @@ pub unsafe fn malloc_raw(size: uint) -> *mut c_void {
             // we need a non-allocating way to print an error here
             abort();
         }
-        p
+        p as *mut u8
     }
 }
 
 /// A wrapper around libc::realloc, aborting on out-of-memory
 #[inline]
-pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void {
+pub unsafe fn realloc_raw(ptr: *mut u8, size: uint) -> *mut u8 {
     // `realloc(ptr, 0)` may allocate, but it may also return a null pointer
     // http://pubs.opengroup.org/onlinepubs/9699919799/functions/realloc.html
     if size == 0 {
-        free(ptr as *c_void);
+        free(ptr as *mut c_void);
         mut_null()
     } else {
-        let p = realloc(ptr, size as size_t);
+        let p = realloc(ptr as *mut c_void, size as size_t);
         if p.is_null() {
             // we need a non-allocating way to print an error here
             abort();
         }
-        p
+        p as *mut u8
     }
 }
 
@@ -68,22 +68,22 @@ pub unsafe fn realloc_raw(ptr: *mut c_void, size: uint) -> *mut c_void {
 #[cfg(not(test))]
 #[lang="exchange_malloc"]
 #[inline]
-pub unsafe fn exchange_malloc(size: uintptr_t) -> *c_char {
-    malloc_raw(size as uint) as *c_char
+pub unsafe fn exchange_malloc(size: uint) -> *u8 {
+    malloc_raw(size) as *u8
 }
 
 // FIXME: #7496
 #[cfg(not(test))]
 #[lang="closure_exchange_malloc"]
 #[inline]
-pub unsafe fn closure_exchange_malloc_(td: *c_char, size: uintptr_t) -> *c_char {
+pub unsafe fn closure_exchange_malloc_(td: *u8, size: uint) -> *u8 {
     closure_exchange_malloc(td, size)
 }
 
 #[inline]
-pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
+pub unsafe fn closure_exchange_malloc(td: *u8, size: uint) -> *u8 {
     let td = td as *TyDesc;
-    let size = size as uint;
+    let size = size;
 
     assert!(td.is_not_null());
 
@@ -93,7 +93,7 @@ pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
     let alloc = p as *mut raw::Box<()>;
     (*alloc).type_desc = td;
 
-    alloc as *c_char
+    alloc as *u8
 }
 
 // NB: Calls to free CANNOT be allowed to fail, as throwing an exception from
@@ -101,13 +101,13 @@ pub unsafe fn closure_exchange_malloc(td: *c_char, size: uintptr_t) -> *c_char {
 #[cfg(not(test))]
 #[lang="exchange_free"]
 #[inline]
-pub unsafe fn exchange_free_(ptr: *c_char) {
+pub unsafe fn exchange_free_(ptr: *u8) {
     exchange_free(ptr)
 }
 
 #[inline]
-pub unsafe fn exchange_free(ptr: *c_char) {
-    free(ptr as *c_void);
+pub unsafe fn exchange_free(ptr: *u8) {
+    free(ptr as *mut c_void);
 }
 
 #[cfg(test)]
diff --git a/src/libstd/rt/local_heap.rs b/src/libstd/rt/local_heap.rs
index 90179612272..36e3bf858e3 100644
--- a/src/libstd/rt/local_heap.rs
+++ b/src/libstd/rt/local_heap.rs
@@ -12,8 +12,6 @@
 
 use cast;
 use iter::Iterator;
-use libc::{c_void, uintptr_t};
-use libc;
 use mem;
 use ops::Drop;
 use option::{Option, None, Some};
@@ -223,7 +221,7 @@ impl MemoryRegion {
 
         let total_size = size + AllocHeader::size();
         let alloc: *AllocHeader = unsafe {
-            global_heap::realloc_raw(orig_alloc as *mut libc::c_void,
+            global_heap::realloc_raw(orig_alloc as *mut u8,
                                      total_size) as *AllocHeader
         };
 
@@ -243,7 +241,7 @@ impl MemoryRegion {
             self.release(cast::transmute(alloc));
             rtassert!(self.live_allocations > 0);
             self.live_allocations -= 1;
-            global_heap::exchange_free(alloc as *libc::c_char)
+            global_heap::exchange_free(alloc as *u8)
         }
     }
 
@@ -294,12 +292,12 @@ impl Drop for MemoryRegion {
 }
 
 #[inline]
-pub unsafe fn local_malloc(td: *libc::c_char, size: libc::uintptr_t) -> *libc::c_char {
+pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 {
     // XXX: Unsafe borrow for speed. Lame.
     let task: Option<*mut Task> = Local::try_unsafe_borrow();
     match task {
         Some(task) => {
-            (*task).heap.alloc(td as *TyDesc, size as uint) as *libc::c_char
+            (*task).heap.alloc(td as *TyDesc, size) as *u8
         }
         None => rtabort!("local malloc outside of task")
     }
@@ -307,7 +305,7 @@ pub unsafe fn local_malloc(td: *libc::c_char, size: libc::uintptr_t) -> *libc::c
 
 // A little compatibility function
 #[inline]
-pub unsafe fn local_free(ptr: *libc::c_char) {
+pub unsafe fn local_free(ptr: *u8) {
     // XXX: Unsafe borrow for speed. Lame.
     let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
     match task_ptr {
diff --git a/src/libstd/rt/local_ptr.rs b/src/libstd/rt/local_ptr.rs
index f4efd8e27d0..d4e57ab19b1 100644
--- a/src/libstd/rt/local_ptr.rs
+++ b/src/libstd/rt/local_ptr.rs
@@ -81,25 +81,75 @@ pub mod compiled {
     use cast;
     use option::{Option, Some, None};
     use ptr::RawPtr;
-    #[cfg(not(test))] use libc::c_void;
 
     #[cfg(test)]
     pub use realstd::rt::shouldnt_be_public::RT_TLS_PTR;
 
     #[cfg(not(test))]
     #[thread_local]
-    pub static mut RT_TLS_PTR: *mut c_void = 0 as *mut c_void;
+    pub static mut RT_TLS_PTR: *mut u8 = 0 as *mut u8;
 
     pub fn init() {}
 
     pub unsafe fn cleanup() {}
 
+    // Rationale for all of these functions being inline(never)
+    //
+    // The #[thread_local] annotation gets propagated all the way through to
+    // LLVM, meaning the global is specially treated by LLVM to lower it to an
+    // efficient sequence of instructions. This also involves dealing with fun
+    // stuff in object files and whatnot. Regardless, it turns out this causes
+    // trouble with green threads and lots of optimizations turned on. The
+    // following case study was done on linux x86_64, but I would imagine that
+    // other platforms are similar.
+    //
+    // On linux, the instruction sequence for loading the tls pointer global
+    // looks like:
+    //
+    //      mov %fs:0x0, %rax
+    //      mov -0x8(%rax), %rbx
+    //
+    // This code leads me to believe that (%fs:0x0) is a table, and then the
+    // table contains the TLS values for the process. Hence, the slot at offset
+    // -0x8 is the task TLS pointer. This leads us to the conclusion that this
+    // table is the actual thread local part of each thread. The kernel sets up
+    // the fs segment selector to point at the right region of memory for each
+    // thread.
+    //
+    // Optimizations lead me to believe that this code is lowered to these
+    // instructions in the LLVM codegen passes, because you'll see code like
+    // this when everything is optimized:
+    //
+    //      mov %fs:0x0, %r14
+    //      mov -0x8(%r14), %rbx
+    //      // do something with %rbx, the rust Task pointer
+    //
+    //      ... // <- do more things
+    //
+    //      mov -0x8(%r14), %rbx
+    //      // do something else with %rbx
+    //
+    // Note that the optimization done here is that the first load is not
+    // duplicated during the lower instructions. This means that the %fs:0x0
+    // memory location is only dereferenced once.
+    //
+    // Normally, this is actually a good thing! With green threads, however,
+    // it's very possible for the code labeled "do more things" to context
+    // switch to another thread. If this happens, then we *must* re-load %fs:0x0
+    // because it's changed (we're on a different thread). If we don't re-load
+    // the table location, then we'll be reading the original thread's TLS
+    // values, not our thread's TLS values.
+    //
+    // Hence, we never inline these functions. By never inlining, we're
+    // guaranteed that loading the table is a local decision which is forced to
+    // *always* happen.
+
     /// Give a pointer to thread-local storage.
     ///
     /// # Safety note
     ///
     /// Does not validate the pointer type.
-    #[inline]
+    #[inline(never)] // see comments above
     pub unsafe fn put<T>(sched: ~T) {
         RT_TLS_PTR = cast::transmute(sched)
     }
@@ -109,7 +159,7 @@ pub mod compiled {
     /// # Safety note
     ///
     /// Does not validate the pointer type.
-    #[inline]
+    #[inline(never)] // see comments above
     pub unsafe fn take<T>() -> ~T {
         let ptr = RT_TLS_PTR;
         rtassert!(!ptr.is_null());
@@ -124,7 +174,7 @@ pub mod compiled {
     /// # Safety note
     ///
     /// Does not validate the pointer type.
-    #[inline]
+    #[inline(never)] // see comments above
     pub unsafe fn try_take<T>() -> Option<~T> {
         let ptr = RT_TLS_PTR;
         if ptr.is_null() {
@@ -143,18 +193,20 @@ pub mod compiled {
     ///
     /// Does not validate the pointer type.
     /// Leaves the old pointer in TLS for speed.
-    #[inline]
+    #[inline(never)] // see comments above
     pub unsafe fn unsafe_take<T>() -> ~T {
         cast::transmute(RT_TLS_PTR)
     }
 
     /// Check whether there is a thread-local pointer installed.
+    #[inline(never)] // see comments above
     pub fn exists() -> bool {
         unsafe {
             RT_TLS_PTR.is_not_null()
         }
     }
 
+    #[inline(never)] // see comments above
     pub unsafe fn unsafe_borrow<T>() -> *mut T {
         if RT_TLS_PTR.is_null() {
             rtabort!("thread-local pointer is null. bogus!");
@@ -162,6 +214,7 @@ pub mod compiled {
         RT_TLS_PTR as *mut T
     }
 
+    #[inline(never)] // see comments above
     pub unsafe fn try_unsafe_borrow<T>() -> Option<*mut T> {
         if RT_TLS_PTR.is_null() {
             None
@@ -176,7 +229,6 @@ pub mod compiled {
 /// thread-local value.
 pub mod native {
     use cast;
-    use libc::c_void;
     use option::{Option, Some, None};
     use ptr;
     use ptr::RawPtr;
@@ -205,7 +257,7 @@ pub mod native {
     #[inline]
     pub unsafe fn put<T>(sched: ~T) {
         let key = tls_key();
-        let void_ptr: *mut c_void = cast::transmute(sched);
+        let void_ptr: *mut u8 = cast::transmute(sched);
         tls::set(key, void_ptr);
     }
 
@@ -217,7 +269,7 @@ pub mod native {
     #[inline]
     pub unsafe fn take<T>() -> ~T {
         let key = tls_key();
-        let void_ptr: *mut c_void = tls::get(key);
+        let void_ptr: *mut u8 = tls::get(key);
         if void_ptr.is_null() {
             rtabort!("thread-local pointer is null. bogus!");
         }
@@ -235,7 +287,7 @@ pub mod native {
     pub unsafe fn try_take<T>() -> Option<~T> {
         match maybe_tls_key() {
             Some(key) => {
-                let void_ptr: *mut c_void = tls::get(key);
+                let void_ptr: *mut u8 = tls::get(key);
                 if void_ptr.is_null() {
                     None
                 } else {
@@ -257,7 +309,7 @@ pub mod native {
     #[inline]
     pub unsafe fn unsafe_take<T>() -> ~T {
         let key = tls_key();
-        let void_ptr: *mut c_void = tls::get(key);
+        let void_ptr: *mut u8 = tls::get(key);
         if void_ptr.is_null() {
             rtabort!("thread-local pointer is null. bogus!");
         }
diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs
index 40e9a3ec5b2..7aa966802f2 100644
--- a/src/libstd/rt/mod.rs
+++ b/src/libstd/rt/mod.rs
@@ -127,6 +127,9 @@ mod util;
 // Global command line argument storage
 pub mod args;
 
+// Support for running procedures when a program has exited.
+mod at_exit_imp;
+
 /// The default error code of the rust runtime if the main task fails instead
 /// of exiting cleanly.
 pub static DEFAULT_ERROR_CODE: int = 101;
@@ -171,9 +174,27 @@ pub fn init(argc: int, argv: **u8) {
         env::init();
         logging::init();
         local_ptr::init();
+        at_exit_imp::init();
     }
 }
 
+/// Enqueues a procedure to run when the runtime is cleaned up
+///
+/// The procedure passed to this function will be executed as part of the
+/// runtime cleanup phase. For normal rust programs, this means that it will run
+/// after all other tasks have exited.
+///
+/// The procedure is *not* executed with a local `Task` available to it, so
+/// primitives like logging, I/O, channels, spawning, etc, are *not* available.
+/// This is meant for "bare bones" usage to clean up runtime details, this is
+/// not meant as a general-purpose "let's clean everything up" function.
+///
+/// It is forbidden for procedures to register more `at_exit` handlers when they
+/// are running, and doing so will lead to a process abort.
+pub fn at_exit(f: proc()) {
+    at_exit_imp::push(f);
+}
+
 /// One-time runtime cleanup.
 ///
 /// This function is unsafe because it performs no checks to ensure that the
@@ -184,6 +205,7 @@ pub fn init(argc: int, argv: **u8) {
 /// Invoking cleanup while portions of the runtime are still in use may cause
 /// undefined behavior.
 pub unsafe fn cleanup() {
+    at_exit_imp::run();
     args::cleanup();
     local_ptr::cleanup();
 }
diff --git a/src/libstd/rt/thread.rs b/src/libstd/rt/thread.rs
index f4f4aaa2765..b5262424c06 100644
--- a/src/libstd/rt/thread.rs
+++ b/src/libstd/rt/thread.rs
@@ -196,7 +196,7 @@ mod imp {
     use unstable::intrinsics;
 
     pub type rust_thread = libc::pthread_t;
-    pub type rust_thread_return = *libc::c_void;
+    pub type rust_thread_return = *u8;
 
     pub unsafe fn create(stack: uint, p: ~proc()) -> rust_thread {
         let mut native: libc::pthread_t = intrinsics::uninit();
diff --git a/src/libstd/rt/thread_local_storage.rs b/src/libstd/rt/thread_local_storage.rs
index d5affdd5173..40d9523cf3a 100644
--- a/src/libstd/rt/thread_local_storage.rs
+++ b/src/libstd/rt/thread_local_storage.rs
@@ -10,7 +10,6 @@
 
 #[allow(dead_code)];
 
-use libc::c_void;
 #[cfg(unix)]
 use libc::c_int;
 #[cfg(unix)]
@@ -27,12 +26,12 @@ pub unsafe fn create(key: &mut Key) {
 }
 
 #[cfg(unix)]
-pub unsafe fn set(key: Key, value: *mut c_void) {
+pub unsafe fn set(key: Key, value: *mut u8) {
     assert_eq!(0, pthread_setspecific(key, value));
 }
 
 #[cfg(unix)]
-pub unsafe fn get(key: Key) -> *mut c_void {
+pub unsafe fn get(key: Key) -> *mut u8 {
     pthread_getspecific(key)
 }
 
@@ -55,8 +54,8 @@ type pthread_key_t = ::libc::c_uint;
 extern {
     fn pthread_key_create(key: *mut pthread_key_t, dtor: *u8) -> c_int;
     fn pthread_key_delete(key: pthread_key_t) -> c_int;
-    fn pthread_getspecific(key: pthread_key_t) -> *mut c_void;
-    fn pthread_setspecific(key: pthread_key_t, value: *mut c_void) -> c_int;
+    fn pthread_getspecific(key: pthread_key_t) -> *mut u8;
+    fn pthread_setspecific(key: pthread_key_t, value: *mut u8) -> c_int;
 }
 
 #[cfg(windows)]
@@ -70,13 +69,13 @@ pub unsafe fn create(key: &mut Key) {
 }
 
 #[cfg(windows)]
-pub unsafe fn set(key: Key, value: *mut c_void) {
-    assert!(0 != TlsSetValue(key, value))
+pub unsafe fn set(key: Key, value: *mut u8) {
+    assert!(0 != TlsSetValue(key, value as *mut ::libc::c_void))
 }
 
 #[cfg(windows)]
-pub unsafe fn get(key: Key) -> *mut c_void {
-    TlsGetValue(key)
+pub unsafe fn get(key: Key) -> *mut u8 {
+    TlsGetValue(key) as *mut u8
 }
 
 #[cfg(windows)]
diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs
index ffe254574eb..6f3aa4c4fd0 100644
--- a/src/libstd/rt/unwind.rs
+++ b/src/libstd/rt/unwind.rs
@@ -59,7 +59,6 @@ use any::{Any, AnyRefExt};
 use c_str::CString;
 use cast;
 use kinds::Send;
-use libc::{c_void, c_char, size_t};
 use option::{Some, None, Option};
 use prelude::drop;
 use ptr::RawPtr;
@@ -79,7 +78,7 @@ mod libunwind {
     #[allow(non_camel_case_types)];
     #[allow(dead_code)] // these are just bindings
 
-    use libc::{uintptr_t, uint64_t};
+    use libc::{uintptr_t};
 
     #[cfg(not(target_arch = "arm"))]
     #[repr(C)]
@@ -118,7 +117,7 @@ mod libunwind {
         _URC_FAILURE = 9, // used only by ARM EABI
     }
 
-    pub type _Unwind_Exception_Class = uint64_t;
+    pub type _Unwind_Exception_Class = u64;
 
     pub type _Unwind_Word = uintptr_t;
 
@@ -164,6 +163,7 @@ impl Unwinder {
 
     pub fn try(&mut self, f: ||) {
         use unstable::raw::Closure;
+        use libc::{c_void};
 
         unsafe {
             let closure: Closure = cast::transmute(f);
@@ -365,10 +365,11 @@ pub mod eabi {
 /// The arguments are normally generated by the compiler, and need to
 /// have static lifetimes.
 #[inline(never)] #[cold] // this is the slow path, please never inline this
-pub fn begin_unwind_raw(msg: *c_char, file: *c_char, line: size_t) -> ! {
+pub fn begin_unwind_raw(msg: *u8, file: *u8, line: uint) -> ! {
+    use libc::c_char;
     #[inline]
-    fn static_char_ptr(p: *c_char) -> &'static str {
-        let s = unsafe { CString::new(p, false) };
+    fn static_char_ptr(p: *u8) -> &'static str {
+        let s = unsafe { CString::new(p as *c_char, false) };
         match s.as_str() {
             Some(s) => unsafe { cast::transmute::<&str, &'static str>(s) },
             None => rtabort!("message wasn't utf8?")
diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs
index a5d5a4677f1..b482e2fb67f 100644
--- a/src/libstd/rt/util.rs
+++ b/src/libstd/rt/util.rs
@@ -70,7 +70,6 @@ pub fn default_sched_threads() -> uint {
 
 pub fn dumb_println(args: &fmt::Arguments) {
     use io;
-    use libc;
 
     struct Stderr;
     impl io::Writer for Stderr {
diff --git a/src/libstd/run.rs b/src/libstd/run.rs
index f460d3f4944..f42163791a6 100644
--- a/src/libstd/run.rs
+++ b/src/libstd/run.rs
@@ -331,7 +331,6 @@ pub fn process_output(prog: &str, args: &[~str]) -> Option<ProcessOutput> {
 #[cfg(test)]
 mod tests {
     use prelude::*;
-    use libc::c_int;
     use os;
     use run;
     use str;
@@ -339,6 +338,7 @@ mod tests {
     use unstable::running_on_valgrind;
     use io::pipe::PipeStream;
     use io::{io_error, FileNotFound};
+    use libc::c_int;
 
     #[test]
     #[cfg(not(target_os="android"))] // FIXME(#10380)
@@ -410,9 +410,9 @@ mod tests {
             err_fd: Some(pipe_err.out)
         }).expect("failed to exec `cat`");
 
-        os::close(pipe_in.input);
-        os::close(pipe_out.out);
-        os::close(pipe_err.out);
+        os::close(pipe_in.input as int);
+        os::close(pipe_out.out as int);
+        os::close(pipe_err.out as int);
 
         do spawn {
             writeclose(pipe_in.out, "test");
diff --git a/src/libstd/str.rs b/src/libstd/str.rs
index 95a02e1631a..22c9ae606d3 100644
--- a/src/libstd/str.rs
+++ b/src/libstd/str.rs
@@ -102,7 +102,7 @@ use clone::{Clone, DeepClone};
 use container::{Container, Mutable};
 use iter::{Iterator, FromIterator, Extendable, range};
 use iter::{Filter, AdditiveIterator, Map};
-use iter::{Invert, DoubleEndedIterator, ExactSize};
+use iter::{Rev, DoubleEndedIterator, ExactSize};
 use libc;
 use num::{Saturating};
 use option::{None, Option, Some};
@@ -376,11 +376,11 @@ impl<'a> DoubleEndedIterator<(uint, char)> for CharOffsets<'a> {
 
 /// External iterator for a string's characters in reverse order.
 /// Use with the `std::iter` module.
-pub type RevChars<'a> = Invert<Chars<'a>>;
+pub type RevChars<'a> = Rev<Chars<'a>>;
 
 /// External iterator for a string's characters and their byte offsets in reverse order.
 /// Use with the `std::iter` module.
-pub type RevCharOffsets<'a> = Invert<CharOffsets<'a>>;
+pub type RevCharOffsets<'a> = Rev<CharOffsets<'a>>;
 
 /// External iterator for a string's bytes.
 /// Use with the `std::iter` module.
@@ -389,7 +389,7 @@ pub type Bytes<'a> =
 
 /// External iterator for a string's bytes in reverse order.
 /// Use with the `std::iter` module.
-pub type RevBytes<'a> = Invert<Bytes<'a>>;
+pub type RevBytes<'a> = Rev<Bytes<'a>>;
 
 /// An iterator over the substrings of a string, separated by `sep`.
 #[deriving(Clone)]
@@ -405,7 +405,7 @@ pub struct CharSplits<'a, Sep> {
 
 /// An iterator over the substrings of a string, separated by `sep`,
 /// starting from the back of the string.
-pub type RevCharSplits<'a, Sep> = Invert<CharSplits<'a, Sep>>;
+pub type RevCharSplits<'a, Sep> = Rev<CharSplits<'a, Sep>>;
 
 /// An iterator over the substrings of a string, separated by `sep`,
 /// splitting at most `count` times.
@@ -486,7 +486,7 @@ for CharSplits<'a, Sep> {
         let mut next_split = None;
 
         if self.only_ascii {
-            for (idx, byte) in self.string.bytes().enumerate().invert() {
+            for (idx, byte) in self.string.bytes().enumerate().rev() {
                 if self.sep.matches(byte as char) && byte < 128u8 {
                     next_split = Some((idx, idx + 1));
                     break;
@@ -1980,7 +1980,7 @@ impl<'a> StrSlice<'a> for &'a str {
 
     #[inline]
     fn chars_rev(&self) -> RevChars<'a> {
-        self.chars().invert()
+        self.chars().rev()
     }
 
     #[inline]
@@ -1990,7 +1990,7 @@ impl<'a> StrSlice<'a> for &'a str {
 
     #[inline]
     fn bytes_rev(&self) -> RevBytes<'a> {
-        self.bytes().invert()
+        self.bytes().rev()
     }
 
     #[inline]
@@ -2000,7 +2000,7 @@ impl<'a> StrSlice<'a> for &'a str {
 
     #[inline]
     fn char_indices_rev(&self) -> RevCharOffsets<'a> {
-        self.char_indices().invert()
+        self.char_indices().rev()
     }
 
     #[inline]
@@ -2035,7 +2035,7 @@ impl<'a> StrSlice<'a> for &'a str {
 
     #[inline]
     fn rsplit<Sep: CharEq>(&self, sep: Sep) -> RevCharSplits<'a, Sep> {
-        self.split(sep).invert()
+        self.split(sep).rev()
     }
 
     #[inline]
@@ -3789,11 +3789,11 @@ mod tests {
     fn test_rev_split_char_iterator_no_trailing() {
         let data = "\nMäry häd ä little lämb\nLittle lämb\n";
 
-        let mut split: ~[&str] = data.split('\n').invert().collect();
+        let mut split: ~[&str] = data.split('\n').rev().collect();
         split.reverse();
         assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb", ""]);
 
-        let mut split: ~[&str] = data.split_terminator('\n').invert().collect();
+        let mut split: ~[&str] = data.split_terminator('\n').rev().collect();
         split.reverse();
         assert_eq!(split, ~["", "Märy häd ä little lämb", "Little lämb"]);
     }
diff --git a/src/libstd/sync/atomics.rs b/src/libstd/sync/atomics.rs
index bc9d99c0f37..30d9ede8a43 100644
--- a/src/libstd/sync/atomics.rs
+++ b/src/libstd/sync/atomics.rs
@@ -24,7 +24,6 @@
 use unstable::intrinsics;
 use cast;
 use option::{Option,Some,None};
-use libc::c_void;
 use ops::Drop;
 use util::NonCopyable;
 
@@ -73,7 +72,7 @@ pub struct AtomicPtr<T> {
  */
 #[unsafe_no_drop_flag]
 pub struct AtomicOption<T> {
-    priv p: *mut c_void
+    priv p: *mut u8
 }
 
 pub enum Ordering {
diff --git a/src/libstd/sync/deque.rs b/src/libstd/sync/deque.rs
index e99e9ef0940..e740862fddf 100644
--- a/src/libstd/sync/deque.rs
+++ b/src/libstd/sync/deque.rs
@@ -389,7 +389,7 @@ impl<T: Send> Buffer<T> {
 impl<T: Send> Drop for Buffer<T> {
     fn drop(&mut self) {
         // It is assumed that all buffers are empty on drop.
-        unsafe { libc::free(self.storage as *libc::c_void) }
+        unsafe { libc::free(self.storage as *mut libc::c_void) }
     }
 }
 
diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs
index ead9cec9943..8b9b41f027c 100644
--- a/src/libstd/trie.rs
+++ b/src/libstd/trie.rs
@@ -728,7 +728,7 @@ mod test_map {
     fn test_each_reverse_break() {
         let mut m = TrieMap::new();
 
-        for x in range(uint::max_value - 10000, uint::max_value).invert() {
+        for x in range(uint::max_value - 10000, uint::max_value).rev() {
             m.insert(x, x / 2);
         }
 
@@ -781,7 +781,7 @@ mod test_map {
         let last = uint::max_value;
 
         let mut map = TrieMap::new();
-        for x in range(first, last).invert() {
+        for x in range(first, last).rev() {
             map.insert(x, x / 2);
         }
 
@@ -803,7 +803,7 @@ mod test_map {
         let last = uint::max_value;
 
         let mut map = TrieMap::new();
-        for x in range(first, last).invert() {
+        for x in range(first, last).rev() {
             map.insert(x, x / 2);
         }
 
diff --git a/src/libstd/unstable/dynamic_lib.rs b/src/libstd/unstable/dynamic_lib.rs
index 24568fe13e5..8529b69c6eb 100644
--- a/src/libstd/unstable/dynamic_lib.rs
+++ b/src/libstd/unstable/dynamic_lib.rs
@@ -18,12 +18,11 @@ A simple wrapper over the platform's dynamic library facilities
 use c_str::ToCStr;
 use cast;
 use path;
-use libc;
 use ops::*;
 use option::*;
 use result::*;
 
-pub struct DynamicLibrary { priv handle: *libc::c_void }
+pub struct DynamicLibrary { priv handle: *u8}
 
 impl Drop for DynamicLibrary {
     fn drop(&mut self) {
@@ -142,14 +141,14 @@ pub mod dl {
     use str;
     use result::*;
 
-    pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
+    pub unsafe fn open_external(filename: &path::Path) -> *u8 {
         filename.with_c_str(|raw_name| {
-            dlopen(raw_name, Lazy as libc::c_int)
+            dlopen(raw_name, Lazy as libc::c_int) as *u8
         })
     }
 
-    pub unsafe fn open_internal() -> *libc::c_void {
-        dlopen(ptr::null(), Lazy as libc::c_int)
+    pub unsafe fn open_internal() -> *u8 {
+        dlopen(ptr::null(), Lazy as libc::c_int) as *u8
     }
 
     pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, ~str> {
@@ -174,11 +173,11 @@ pub mod dl {
         }
     }
 
-    pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
-        dlsym(handle, symbol)
+    pub unsafe fn symbol(handle: *u8, symbol: *libc::c_char) -> *u8 {
+        dlsym(handle as *libc::c_void, symbol) as *u8
     }
-    pub unsafe fn close(handle: *libc::c_void) {
-        dlclose(handle); ()
+    pub unsafe fn close(handle: *u8) {
+        dlclose(handle as *libc::c_void); ()
     }
 
     pub enum RTLD {
@@ -206,16 +205,16 @@ pub mod dl {
     use ptr;
     use result::{Ok, Err, Result};
 
-    pub unsafe fn open_external(filename: &path::Path) -> *libc::c_void {
+    pub unsafe fn open_external(filename: &path::Path) -> *u8 {
         os::win32::as_utf16_p(filename.as_str().unwrap(), |raw_name| {
-            LoadLibraryW(raw_name)
+            LoadLibraryW(raw_name as *libc::c_void) as *u8
         })
     }
 
-    pub unsafe fn open_internal() -> *libc::c_void {
+    pub unsafe fn open_internal() -> *u8 {
         let handle = ptr::null();
         GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &handle as **libc::c_void);
-        handle
+        handle as *u8
     }
 
     pub fn check_for_errors_in<T>(f: || -> T) -> Result<T, ~str> {
@@ -233,17 +232,17 @@ pub mod dl {
         }
     }
 
-    pub unsafe fn symbol(handle: *libc::c_void, symbol: *libc::c_char) -> *libc::c_void {
-        GetProcAddress(handle, symbol)
+    pub unsafe fn symbol(handle: *u8, symbol: *libc::c_char) -> *u8 {
+        GetProcAddress(handle as *libc::c_void, symbol) as *u8
     }
-    pub unsafe fn close(handle: *libc::c_void) {
-        FreeLibrary(handle); ()
+    pub unsafe fn close(handle: *u8) {
+        FreeLibrary(handle as *libc::c_void); ()
     }
 
     #[link_name = "kernel32"]
     extern "system" {
-        fn SetLastError(error: u32);
-        fn LoadLibraryW(name: *u16) -> *libc::c_void;
+        fn SetLastError(error: libc::size_t);
+        fn LoadLibraryW(name: *libc::c_void) -> *libc::c_void;
         fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *u16,
                               handle: **libc::c_void) -> *libc::c_void;
         fn GetProcAddress(handle: *libc::c_void, name: *libc::c_char) -> *libc::c_void;
diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs
index 8460152ff7b..046d3fc820d 100644
--- a/src/libstd/unstable/lang.rs
+++ b/src/libstd/unstable/lang.rs
@@ -1,4 +1,4 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -11,25 +11,24 @@
 //! Runtime calls emitted by the compiler.
 
 use c_str::ToCStr;
-use libc::{c_char, size_t, uintptr_t};
 
 #[cold]
 #[lang="fail_"]
-pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! {
+pub fn fail_(expr: *u8, file: *u8, line: uint) -> ! {
     ::rt::begin_unwind_raw(expr, file, line);
 }
 
 #[cold]
 #[lang="fail_bounds_check"]
-pub fn fail_bounds_check(file: *c_char, line: size_t, index: size_t, len: size_t) -> ! {
+pub fn fail_bounds_check(file: *u8, line: uint, index: uint, len: uint) -> ! {
     let msg = format!("index out of bounds: the len is {} but the index is {}",
                       len as uint, index as uint);
-    msg.with_c_str(|buf| fail_(buf, file, line))
+    msg.with_c_str(|buf| fail_(buf as *u8, file, line))
 }
 
 #[lang="malloc"]
 #[inline]
-pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
+pub unsafe fn local_malloc(td: *u8, size: uint) -> *u8 {
     ::rt::local_heap::local_malloc(td, size)
 }
 
@@ -38,6 +37,6 @@ pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
 // problem occurs, call exit instead.
 #[lang="free"]
 #[inline]
-pub unsafe fn local_free(ptr: *c_char) {
+pub unsafe fn local_free(ptr: *u8) {
     ::rt::local_heap::local_free(ptr);
 }
diff --git a/src/libstd/unstable/mutex.rs b/src/libstd/unstable/mutex.rs
index 81317b7de79..69c6204cc32 100644
--- a/src/libstd/unstable/mutex.rs
+++ b/src/libstd/unstable/mutex.rs
@@ -48,7 +48,6 @@
 #[allow(non_camel_case_types)];
 
 use int;
-use libc::c_void;
 use sync::atomics;
 
 pub struct Mutex {
@@ -133,38 +132,37 @@ impl Mutex {
         if cond != 0 { imp::free_cond(cond) }
     }
 
-    unsafe fn getlock(&mut self) -> *c_void {
+    unsafe fn getlock(&mut self) -> uint{
         match self.lock.load(atomics::Relaxed) {
             0 => {}
-            n => return n as *c_void
+            n => return n
         }
         let lock = imp::init_lock();
         match self.lock.compare_and_swap(0, lock, atomics::SeqCst) {
-            0 => return lock as *c_void,
+            0 => return lock,
             _ => {}
         }
         imp::free_lock(lock);
-        return self.lock.load(atomics::Relaxed) as *c_void;
+        self.lock.load(atomics::Relaxed)
     }
 
-    unsafe fn getcond(&mut self) -> *c_void {
+    unsafe fn getcond(&mut self) -> uint {
         match self.cond.load(atomics::Relaxed) {
             0 => {}
-            n => return n as *c_void
+            n => return n
         }
         let cond = imp::init_cond();
         match self.cond.compare_and_swap(0, cond, atomics::SeqCst) {
-            0 => return cond as *c_void,
+            0 => return cond,
             _ => {}
         }
         imp::free_cond(cond);
-        return self.cond.load(atomics::Relaxed) as *c_void;
+        self.cond.load(atomics::Relaxed)
     }
 }
 
 #[cfg(unix)]
 mod imp {
-    use libc::c_void;
     use libc;
     use ptr;
     use rt::global_heap::malloc_raw;
@@ -175,49 +173,49 @@ mod imp {
     type pthread_condattr_t = libc::c_void;
 
     pub unsafe fn init_lock() -> uint {
-        let block = malloc_raw(rust_pthread_mutex_t_size() as uint) as *c_void;
+        let block = malloc_raw(rust_pthread_mutex_t_size() as uint) as *mut pthread_mutex_t;
         let n = pthread_mutex_init(block, ptr::null());
         assert_eq!(n, 0);
         return block as uint;
     }
 
     pub unsafe fn init_cond() -> uint {
-        let block = malloc_raw(rust_pthread_cond_t_size() as uint) as *c_void;
+        let block = malloc_raw(rust_pthread_cond_t_size() as uint) as *mut pthread_cond_t;
         let n = pthread_cond_init(block, ptr::null());
         assert_eq!(n, 0);
         return block as uint;
     }
 
     pub unsafe fn free_lock(h: uint) {
-        let block = h as *c_void;
+        let block = h as *mut libc::c_void;
         assert_eq!(pthread_mutex_destroy(block), 0);
         libc::free(block);
     }
 
     pub unsafe fn free_cond(h: uint) {
-        let block = h as *c_void;
+        let block = h as *mut pthread_cond_t;
         assert_eq!(pthread_cond_destroy(block), 0);
         libc::free(block);
     }
 
-    pub unsafe fn lock(l: *pthread_mutex_t) {
-        assert_eq!(pthread_mutex_lock(l), 0);
+    pub unsafe fn lock(l: uint) {
+        assert_eq!(pthread_mutex_lock(l as *mut pthread_mutex_t), 0);
     }
 
-    pub unsafe fn trylock(l: *c_void) -> bool {
-        pthread_mutex_trylock(l) == 0
+    pub unsafe fn trylock(l: uint) -> bool {
+        pthread_mutex_trylock(l as *mut pthread_mutex_t) == 0
     }
 
-    pub unsafe fn unlock(l: *pthread_mutex_t) {
-        assert_eq!(pthread_mutex_unlock(l), 0);
+    pub unsafe fn unlock(l: uint) {
+        assert_eq!(pthread_mutex_unlock(l as *mut pthread_mutex_t), 0);
     }
 
-    pub unsafe fn wait(cond: *pthread_cond_t, m: *pthread_mutex_t) {
-        assert_eq!(pthread_cond_wait(cond, m), 0);
+    pub unsafe fn wait(cond: uint, m: uint) {
+        assert_eq!(pthread_cond_wait(cond as *mut pthread_cond_t, m as *mut pthread_mutex_t), 0);
     }
 
-    pub unsafe fn signal(cond: *pthread_cond_t) {
-        assert_eq!(pthread_cond_signal(cond), 0);
+    pub unsafe fn signal(cond: uint) {
+        assert_eq!(pthread_cond_signal(cond as *mut pthread_cond_t), 0);
     }
 
     extern {
@@ -226,19 +224,19 @@ mod imp {
     }
 
     extern {
-        fn pthread_mutex_init(lock: *pthread_mutex_t,
+        fn pthread_mutex_init(lock: *mut pthread_mutex_t,
                               attr: *pthread_mutexattr_t) -> libc::c_int;
-        fn pthread_mutex_destroy(lock: *pthread_mutex_t) -> libc::c_int;
-        fn pthread_cond_init(cond: *pthread_cond_t,
+        fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int;
+        fn pthread_cond_init(cond: *mut pthread_cond_t,
                               attr: *pthread_condattr_t) -> libc::c_int;
-        fn pthread_cond_destroy(cond: *pthread_cond_t) -> libc::c_int;
-        fn pthread_mutex_lock(lock: *pthread_mutex_t) -> libc::c_int;
-        fn pthread_mutex_trylock(lock: *pthread_mutex_t) -> libc::c_int;
-        fn pthread_mutex_unlock(lock: *pthread_mutex_t) -> libc::c_int;
+        fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int;
+        fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int;
+        fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int;
+        fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int;
 
-        fn pthread_cond_wait(cond: *pthread_cond_t,
-                             lock: *pthread_mutex_t) -> libc::c_int;
-        fn pthread_cond_signal(cond: *pthread_cond_t) -> libc::c_int;
+        fn pthread_cond_wait(cond: *mut pthread_cond_t,
+                             lock: *mut pthread_mutex_t) -> libc::c_int;
+        fn pthread_cond_signal(cond: *mut pthread_cond_t) -> libc::c_int;
     }
 }
 
@@ -265,7 +263,7 @@ mod imp {
 
     pub unsafe fn free_lock(h: uint) {
         DeleteCriticalSection(h as LPCRITICAL_SECTION);
-        libc::free(h as *c_void);
+        libc::free(h as *mut c_void);
     }
 
     pub unsafe fn free_cond(h: uint) {
@@ -273,25 +271,25 @@ mod imp {
         libc::CloseHandle(block);
     }
 
-    pub unsafe fn lock(l: *c_void) {
+    pub unsafe fn lock(l: uint) {
         EnterCriticalSection(l as LPCRITICAL_SECTION)
     }
 
-    pub unsafe fn trylock(l: *c_void) -> bool {
+    pub unsafe fn trylock(l: uint) -> bool {
         TryEnterCriticalSection(l as LPCRITICAL_SECTION) != 0
     }
 
-    pub unsafe fn unlock(l: *c_void) {
+    pub unsafe fn unlock(l: uint) {
         LeaveCriticalSection(l as LPCRITICAL_SECTION)
     }
 
-    pub unsafe fn wait(cond: *c_void, m: *c_void) {
+    pub unsafe fn wait(cond: uint, m: uint) {
         unlock(m);
         WaitForSingleObject(cond as HANDLE, libc::INFINITE);
         lock(m);
     }
 
-    pub unsafe fn signal(cond: *c_void) {
+    pub unsafe fn signal(cond: uint) {
         assert!(SetEvent(cond as HANDLE) != 0);
     }
 
diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs
index 27e949a5640..41cae372dbb 100644
--- a/src/libstd/vec.rs
+++ b/src/libstd/vec.rs
@@ -109,7 +109,6 @@ use cmp::{Eq, TotalOrd, Ordering, Less, Equal, Greater};
 use cmp;
 use default::Default;
 use iter::*;
-use libc::{c_char, c_void};
 use num::{Integer, CheckedAdd, Saturating};
 use option::{None, Option, Some};
 use ptr::to_unsafe_ptr;
@@ -961,7 +960,7 @@ pub trait ImmutableVector<'a, T> {
     fn flat_map<U>(&self, f: |t: &T| -> ~[U]) -> ~[U];
     /// Returns a pointer to the element at the given index, without doing
     /// bounds checking.
-    unsafe fn unsafe_ref(&self, index: uint) -> *T;
+    unsafe fn unsafe_ref(self, index: uint) -> &'a T;
 
     /**
      * Returns an unsafe pointer to the vector's buffer
@@ -1068,7 +1067,7 @@ impl<'a,T> ImmutableVector<'a, T> for &'a [T] {
 
     #[inline]
     fn rev_iter(self) -> RevItems<'a, T> {
-        self.iter().invert()
+        self.iter().rev()
     }
 
     #[inline]
@@ -1150,8 +1149,8 @@ impl<'a,T> ImmutableVector<'a, T> for &'a [T] {
     }
 
     #[inline]
-    unsafe fn unsafe_ref(&self, index: uint) -> *T {
-        self.repr().data.offset(index as int)
+    unsafe fn unsafe_ref(self, index: uint) -> &'a T {
+        cast::transmute(self.repr().data.offset(index as int))
     }
 
     #[inline]
@@ -1465,7 +1464,7 @@ impl<T> OwnedVector<T> for ~[T] {
 
     #[inline]
     fn move_rev_iter(self) -> RevMoveItems<T> {
-        self.move_iter().invert()
+        self.move_iter().rev()
     }
 
     fn reserve(&mut self, n: uint) {
@@ -1478,8 +1477,8 @@ impl<T> OwnedVector<T> for ~[T] {
                 if alloc / mem::nonzero_size_of::<T>() != n || size < alloc {
                     fail!("vector size is too large: {}", n);
                 }
-                *ptr = realloc_raw(*ptr as *mut c_void, size)
-                       as *mut Vec<()>;
+                *ptr = realloc_raw(*ptr as *mut u8, size)
+                                   as *mut Vec<()>;
                 (**ptr).alloc = alloc;
             }
         }
@@ -1513,7 +1512,7 @@ impl<T> OwnedVector<T> for ~[T] {
             let ptr: *mut *mut Vec<()> = cast::transmute(self);
             let alloc = (**ptr).fill;
             let size = alloc + mem::size_of::<Vec<()>>();
-            *ptr = realloc_raw(*ptr as *mut c_void, size) as *mut Vec<()>;
+            *ptr = realloc_raw(*ptr as *mut u8, size) as *mut Vec<()>;
             (**ptr).alloc = alloc;
         }
     }
@@ -2184,7 +2183,7 @@ pub trait MutableVector<'a, T> {
     fn move_from(self, src: ~[T], start: uint, end: uint) -> uint;
 
     /// Returns an unsafe mutable pointer to the element in index
-    unsafe fn unsafe_mut_ref(self, index: uint) -> *mut T;
+    unsafe fn unsafe_mut_ref(self, index: uint) -> &'a mut T;
 
     /// Return an unsafe mutable pointer to the vector's buffer.
     ///
@@ -2301,7 +2300,7 @@ impl<'a,T> MutableVector<'a, T> for &'a mut [T] {
 
     #[inline]
     fn mut_rev_iter(self) -> RevMutItems<'a, T> {
-        self.mut_iter().invert()
+        self.mut_iter().rev()
     }
 
     #[inline]
@@ -2362,8 +2361,8 @@ impl<'a,T> MutableVector<'a, T> for &'a mut [T] {
     }
 
     #[inline]
-    unsafe fn unsafe_mut_ref(self, index: uint) -> *mut T {
-        ptr::mut_offset(self.repr().data as *mut T, index as int)
+    unsafe fn unsafe_mut_ref(self, index: uint) -> &'a mut T {
+        cast::transmute(ptr::mut_offset(self.repr().data as *mut T, index as int))
     }
 
     #[inline]
@@ -2715,7 +2714,7 @@ impl<'a, T> RandomAccessIterator<&'a T> for Items<'a, T> {
 }
 
 iterator!{struct Items -> *T, &'a T}
-pub type RevItems<'a, T> = Invert<Items<'a, T>>;
+pub type RevItems<'a, T> = Rev<Items<'a, T>>;
 
 impl<'a, T> ExactSize<&'a T> for Items<'a, T> {}
 impl<'a, T> ExactSize<&'a mut T> for MutItems<'a, T> {}
@@ -2725,7 +2724,7 @@ impl<'a, T> Clone for Items<'a, T> {
 }
 
 iterator!{struct MutItems -> *mut T, &'a mut T}
-pub type RevMutItems<'a, T> = Invert<MutItems<'a, T>>;
+pub type RevMutItems<'a, T> = Rev<MutItems<'a, T>>;
 
 /// An iterator over the subslices of the vector which are separated
 /// by elements that match `pred`.
@@ -2877,13 +2876,13 @@ impl<T> Drop for MoveItems<T> {
         // destroy the remaining elements
         for _x in *self {}
         unsafe {
-            exchange_free(self.allocation as *u8 as *c_char)
+            exchange_free(self.allocation as *u8)
         }
     }
 }
 
 /// An iterator that moves out of a vector in reverse order.
-pub type RevMoveItems<T> = Invert<MoveItems<T>>;
+pub type RevMoveItems<T> = Rev<MoveItems<T>>;
 
 impl<A> FromIterator<A> for ~[A] {
     fn from_iterator<T: Iterator<A>>(iterator: &mut T) -> ~[A] {
@@ -3986,7 +3985,7 @@ mod tests {
         assert_eq!(v.chunks(3).collect::<~[&[int]]>(), ~[&[1i,2,3], &[4,5]]);
         assert_eq!(v.chunks(6).collect::<~[&[int]]>(), ~[&[1i,2,3,4,5]]);
 
-        assert_eq!(v.chunks(2).invert().collect::<~[&[int]]>(), ~[&[5i], &[3,4], &[1,2]]);
+        assert_eq!(v.chunks(2).rev().collect::<~[&[int]]>(), ~[&[5i], &[3,4], &[1,2]]);
         let it = v.chunks(2);
         assert_eq!(it.indexable(), 3);
         assert_eq!(it.idx(0).unwrap(), &[1,2]);
@@ -4242,9 +4241,9 @@ mod tests {
     }
 
     #[test]
-    fn test_mut_splitator_invert() {
+    fn test_mut_splitator_rev() {
         let mut xs = [1,2,0,3,4,0,0,5,6,0];
-        for slice in xs.mut_split(|x| *x == 0).invert().take(4) {
+        for slice in xs.mut_split(|x| *x == 0).rev().take(4) {
             slice.reverse();
         }
         assert_eq!(xs, [1,2,0,4,3,0,0,6,5,0]);
@@ -4263,9 +4262,9 @@ mod tests {
     }
 
     #[test]
-    fn test_mut_chunks_invert() {
+    fn test_mut_chunks_rev() {
         let mut v = [0u8, 1, 2, 3, 4, 5, 6];
-        for (i, chunk) in v.mut_chunks(3).invert().enumerate() {
+        for (i, chunk) in v.mut_chunks(3).rev().enumerate() {
             for x in chunk.mut_iter() {
                 *x = i as u8;
             }
diff --git a/src/libstd/vec_ng.rs b/src/libstd/vec_ng.rs
new file mode 100644
index 00000000000..e503497d95d
--- /dev/null
+++ b/src/libstd/vec_ng.rs
@@ -0,0 +1,231 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Migrate documentation over from `std::vec` when it is removed.
+#[doc(hidden)];
+
+use prelude::*;
+use container::Container;
+use mem::size_of;
+use cast::{forget, transmute};
+use rt::global_heap::{malloc_raw, realloc_raw};
+use vec::Items;
+use unstable::raw::Slice;
+use ptr::{offset, read_ptr};
+use libc::{free, c_void};
+use unstable::intrinsics::move_val_init;
+
+pub struct Vec<T> {
+    priv len: uint,
+    priv cap: uint,
+    priv ptr: *mut T
+}
+
+impl<T> Vec<T> {
+    #[inline]
+    pub fn new() -> Vec<T> {
+        Vec { len: 0, cap: 0, ptr: 0 as *mut T }
+    }
+
+    pub fn with_capacity(capacity: uint) -> Vec<T> {
+        if capacity == 0 {
+            Vec::new()
+        } else {
+            let size = capacity.checked_mul(&size_of::<T>()).expect("capacity overflow");
+            let ptr = unsafe { malloc_raw(size) };
+            Vec { len: 0, cap: capacity, ptr: ptr as *mut T }
+        }
+    }
+
+    pub fn from_fn(length: uint, op: |uint| -> T) -> Vec<T> {
+        unsafe {
+            let mut xs = Vec::with_capacity(length);
+            while xs.len < length {
+                move_val_init(xs.as_mut_slice().unsafe_mut_ref(xs.len), op(xs.len));
+                xs.len += 1;
+            }
+            xs
+        }
+    }
+}
+
+impl<T: Clone> Vec<T> {
+    pub fn from_elem(length: uint, value: T) -> Vec<T> {
+        unsafe {
+            let mut xs = Vec::with_capacity(length);
+            while xs.len < length {
+                move_val_init(xs.as_mut_slice().unsafe_mut_ref(xs.len), value.clone());
+                xs.len += 1;
+            }
+            xs
+        }
+    }
+}
+
+impl<T> Container for Vec<T> {
+    #[inline]
+    fn len(&self) -> uint {
+        self.len
+    }
+}
+
+impl<T> Vec<T> {
+    #[inline]
+    pub fn capacity(&self) -> uint {
+        self.cap
+    }
+
+    pub fn reserve_exact(&mut self, capacity: uint) {
+        if capacity >= self.len {
+            let size = capacity.checked_mul(&size_of::<T>()).expect("capacity overflow");
+            self.cap = capacity;
+            unsafe {
+                self.ptr = realloc_raw(self.ptr as *mut u8, size) as *mut T;
+            }
+        }
+    }
+
+    pub fn shrink_to_fit(&mut self) {
+        if self.len == 0 {
+            unsafe { free(self.ptr as *mut c_void) };
+            self.cap = 0;
+            self.ptr = 0 as *mut T;
+        } else {
+            unsafe {
+                // Overflow check is unnecessary as the vector is already at least this large.
+                self.ptr = realloc_raw(self.ptr as *mut u8, self.len * size_of::<T>()) as *mut T;
+            }
+            self.cap = self.len;
+        }
+    }
+
+    #[inline]
+    pub fn pop(&mut self) -> Option<T> {
+        if self.len == 0 {
+            None
+        } else {
+            unsafe {
+                self.len -= 1;
+                Some(read_ptr(self.as_slice().unsafe_ref(self.len())))
+            }
+        }
+    }
+
+    #[inline]
+    pub fn push(&mut self, value: T) {
+        if self.len == self.cap {
+            if self.cap == 0 { self.cap += 2 }
+            let old_size = self.cap * size_of::<T>();
+            self.cap = self.cap * 2;
+            let size = old_size * 2;
+            if old_size > size { fail!("capacity overflow") }
+            unsafe {
+                self.ptr = realloc_raw(self.ptr as *mut u8, size) as *mut T;
+            }
+        }
+
+        unsafe {
+            let end = offset(self.ptr as *T, self.len as int) as *mut T;
+            move_val_init(&mut *end, value);
+            self.len += 1;
+        }
+    }
+
+    pub fn truncate(&mut self, len: uint) {
+        unsafe {
+            let mut i = len;
+            // drop any extra elements
+            while i < self.len {
+                read_ptr(self.as_slice().unsafe_ref(i));
+                i += 1;
+            }
+        }
+        self.len = len;
+    }
+
+    #[inline]
+    pub fn as_slice<'a>(&'a self) -> &'a [T] {
+        let slice = Slice { data: self.ptr as *T, len: self.len };
+        unsafe { transmute(slice) }
+    }
+
+    #[inline]
+    pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] {
+        let slice = Slice { data: self.ptr as *T, len: self.len };
+        unsafe { transmute(slice) }
+    }
+
+    #[inline]
+    pub fn move_iter(self) -> MoveItems<T> {
+        unsafe {
+            let iter = transmute(self.as_slice().iter());
+            let ptr = self.ptr as *mut c_void;
+            forget(self);
+            MoveItems { allocation: ptr, iter: iter }
+        }
+    }
+
+    #[inline]
+    pub unsafe fn set_len(&mut self, len: uint) {
+        self.len = len;
+    }
+}
+
+
+#[unsafe_destructor]
+impl<T> Drop for Vec<T> {
+    fn drop(&mut self) {
+        unsafe {
+            for x in self.as_mut_slice().iter() {
+                read_ptr(x);
+            }
+            free(self.ptr as *mut c_void)
+        }
+    }
+}
+
+pub struct MoveItems<T> {
+    priv allocation: *mut c_void, // the block of memory allocated for the vector
+    priv iter: Items<'static, T>
+}
+
+impl<T> Iterator<T> for MoveItems<T> {
+    #[inline]
+    fn next(&mut self) -> Option<T> {
+        unsafe {
+            self.iter.next().map(|x| read_ptr(x))
+        }
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (uint, Option<uint>) {
+        self.iter.size_hint()
+    }
+}
+
+impl<T> DoubleEndedIterator<T> for MoveItems<T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<T> {
+        unsafe {
+            self.iter.next_back().map(|x| read_ptr(x))
+        }
+    }
+}
+
+#[unsafe_destructor]
+impl<T> Drop for MoveItems<T> {
+    fn drop(&mut self) {
+        // destroy the remaining elements
+        for _x in *self {}
+        unsafe {
+            free(self.allocation)
+        }
+    }
+}
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index ebf02f7691e..d81999c1e5f 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -308,10 +308,6 @@ impl CodeMap {
         }
     }
 
-    pub fn adjust_span(&self, sp: Span) -> Span {
-        sp
-    }
-
     pub fn span_to_str(&self, sp: Span) -> ~str {
         {
             let files = self.files.borrow();
diff --git a/src/libsyntax/crateid.rs b/src/libsyntax/crateid.rs
index 0bb1eec512b..0831f319ce7 100644
--- a/src/libsyntax/crateid.rs
+++ b/src/libsyntax/crateid.rs
@@ -70,7 +70,11 @@ impl FromStr for CrateId {
             };
 
             let version = if !hash_version.is_empty() {
-                Some(hash_version.to_owned())
+                if hash_version == "0.0" {
+                    None
+                } else {
+                    Some(hash_version.to_owned())
+                }
             } else {
                 None
             };
@@ -93,6 +97,10 @@ impl CrateId {
             Some(ref version) => version.as_slice(),
         }
     }
+
+    pub fn short_name_with_version(&self) -> ~str {
+        format!("{}-{}", self.name, self.version_or_default())
+    }
 }
 
 #[test]
diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs
index 0eca56e2691..a9d3f6fea24 100644
--- a/src/libsyntax/diagnostic.rs
+++ b/src/libsyntax/diagnostic.rs
@@ -19,12 +19,16 @@ use extra::term;
 
 static BUG_REPORT_URL: &'static str =
     "http://static.rust-lang.org/doc/master/complement-bugreport.html";
+// maximum number of lines we will print for each error; arbitrary.
+static MAX_LINES: uint = 6u;
 
 pub trait Emitter {
     fn emit(&self,
             cmsp: Option<(&codemap::CodeMap, Span)>,
             msg: &str,
             lvl: Level);
+    fn custom_emit(&self, cm: &codemap::CodeMap,
+                   sp: Span, msg: &str, lvl: Level);
 }
 
 /// This structure is used to signify that a task has failed with a fatal error
@@ -55,6 +59,9 @@ impl SpanHandler {
     pub fn span_note(@self, sp: Span, msg: &str) {
         self.handler.emit(Some((&*self.cm, sp)), msg, Note);
     }
+    pub fn span_end_note(@self, sp: Span, msg: &str) {
+        self.handler.custom_emit(&*self.cm, sp, msg, Note);
+    }
     pub fn span_bug(@self, sp: Span, msg: &str) -> ! {
         self.span_fatal(sp, ice_msg(msg));
     }
@@ -122,6 +129,10 @@ impl Handler {
             lvl: Level) {
         self.emit.emit(cmsp, msg, lvl);
     }
+    pub fn custom_emit(@self, cm: &codemap::CodeMap,
+                       sp: Span, msg: &str, lvl: Level) {
+        self.emit.custom_emit(cm, sp, msg, lvl);
+    }
 }
 
 pub fn ice_msg(msg: &str) -> ~str {
@@ -239,17 +250,34 @@ impl Emitter for DefaultEmitter {
             msg: &str,
             lvl: Level) {
         match cmsp {
-            Some((cm, sp)) => {
-                let sp = cm.adjust_span(sp);
-                let ss = cm.span_to_str(sp);
-                let lines = cm.span_to_lines(sp);
-                print_diagnostic(ss, lvl, msg);
-                highlight_lines(cm, sp, lvl, lines);
-                print_macro_backtrace(cm, sp);
-            }
+            Some((cm, sp)) => emit(cm, sp, msg, lvl, false),
             None => print_diagnostic("", lvl, msg),
         }
     }
+
+    fn custom_emit(&self, cm: &codemap::CodeMap,
+                   sp: Span, msg: &str, lvl: Level) {
+        emit(cm, sp, msg, lvl, true);
+    }
+}
+
+fn emit(cm: &codemap::CodeMap, sp: Span,
+        msg: &str, lvl: Level, custom: bool) {
+    let ss = cm.span_to_str(sp);
+    let lines = cm.span_to_lines(sp);
+    if custom {
+        // we want to tell compiletest/runtest to look at the last line of the
+        // span (since `custom_highlight_lines` displays an arrow to the end of
+        // the span)
+        let span_end = Span { lo: sp.hi, hi: sp.hi, expn_info: sp.expn_info};
+        let ses = cm.span_to_str(span_end);
+        print_diagnostic(ses, lvl, msg);
+        custom_highlight_lines(cm, sp, lvl, lines);
+    } else {
+        print_diagnostic(ss, lvl, msg);
+        highlight_lines(cm, sp, lvl, lines);
+    }
+    print_macro_backtrace(cm, sp);
 }
 
 fn highlight_lines(cm: &codemap::CodeMap,
@@ -260,12 +288,10 @@ fn highlight_lines(cm: &codemap::CodeMap,
     let mut err = io::stderr();
     let err = &mut err as &mut io::Writer;
 
-    // arbitrarily only print up to six lines of the error
-    let max_lines = 6u;
     let mut elided = false;
     let mut display_lines = lines.lines.as_slice();
-    if display_lines.len() > max_lines {
-        display_lines = display_lines.slice(0u, max_lines);
+    if display_lines.len() > MAX_LINES {
+        display_lines = display_lines.slice(0u, MAX_LINES);
         elided = true;
     }
     // Print the offending lines
@@ -319,6 +345,44 @@ fn highlight_lines(cm: &codemap::CodeMap,
     }
 }
 
+// Here are the differences between this and the normal `highlight_lines`:
+// `custom_highlight_lines` will always put arrow on the last byte of the
+// span (instead of the first byte). Also, when the span is too long (more
+// than 6 lines), `custom_highlight_lines` will print the first line, then
+// dot dot dot, then last line, whereas `highlight_lines` prints the first
+// six lines.
+fn custom_highlight_lines(cm: &codemap::CodeMap,
+                          sp: Span,
+                          lvl: Level,
+                          lines: &codemap::FileLines) {
+    let fm = lines.file;
+    let mut err = io::stderr();
+    let err = &mut err as &mut io::Writer;
+
+    let lines = lines.lines.as_slice();
+    if lines.len() > MAX_LINES {
+        write!(err, "{}:{} {}\n", fm.name,
+               lines[0] + 1, fm.get_line(lines[0] as int));
+        write!(err, "...\n");
+        let last_line = lines[lines.len()-1];
+        write!(err, "{}:{} {}\n", fm.name,
+               last_line + 1, fm.get_line(last_line as int));
+    } else {
+        for line in lines.iter() {
+            write!(err, "{}:{} {}\n", fm.name,
+                   *line + 1, fm.get_line(*line as int));
+        }
+    }
+    let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1]+1);
+    let hi = cm.lookup_char_pos(sp.hi);
+    // Span seems to use half-opened interval, so subtract 1
+    let skip = last_line_start.len() + hi.col.to_uint() - 1;
+    let mut s = ~"";
+    skip.times(|| s.push_char(' '));
+    s.push_char('^');
+    print_maybe_styled(s + "\n", term::attr::ForegroundColor(lvl.color()));
+}
+
 fn print_macro_backtrace(cm: &codemap::CodeMap, sp: Span) {
     for ei in sp.expn_info.iter() {
         let ss = ei.callee.span.as_ref().map_or(~"", |span| cm.span_to_str(*span));
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index fbaa086c7d3..2c817365390 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -556,7 +556,7 @@ impl SyntaxEnv {
     }
 
     fn find_escape_frame<'a>(&'a mut self) -> &'a mut MapChainFrame {
-        for (i, frame) in self.chain.mut_iter().enumerate().invert() {
+        for (i, frame) in self.chain.mut_iter().enumerate().rev() {
             if !frame.info.macros_escape || i == 0 {
                 return frame
             }
@@ -565,7 +565,7 @@ impl SyntaxEnv {
     }
 
     pub fn find<'a>(&'a self, k: &Name) -> Option<&'a SyntaxExtension> {
-        for frame in self.chain.iter().invert() {
+        for frame in self.chain.iter().rev() {
             match frame.map.find(k) {
                 Some(v) => return Some(v),
                 None => {}
diff --git a/src/libsyntax/ext/format.rs b/src/libsyntax/ext/format.rs
index 8e7947a3d31..bbf6f7fff7f 100644
--- a/src/libsyntax/ext/format.rs
+++ b/src/libsyntax/ext/format.rs
@@ -687,6 +687,8 @@ impl<'a> Context<'a> {
                     "b" => "Bool",
                     "c" => "Char",
                     "d" | "i" => "Signed",
+                    "e" => "LowerExp",
+                    "E" => "UpperExp",
                     "f" => "Float",
                     "o" => "Octal",
                     "p" => "Pointer",
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 4e1703fe6b0..557e7e04ebf 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -2021,7 +2021,7 @@ impl Parser {
                 let es = self.parse_unspanned_seq(
                     &token::LPAREN,
                     &token::RPAREN,
-                    seq_sep_trailing_disallowed(token::COMMA),
+                    seq_sep_trailing_allowed(token::COMMA),
                     |p| p.parse_expr()
                 );
                 hi = self.last_span.hi;
@@ -2994,6 +2994,7 @@ impl Parser {
                 if self.look_ahead(1, |t| *t != token::RPAREN) {
                     while self.token == token::COMMA {
                         self.bump();
+                        if self.token == token::RPAREN { break; }
                         fields.push(self.parse_pat());
                     }
                 }
@@ -3573,7 +3574,7 @@ impl Parser {
             self.parse_unspanned_seq(
                 &token::LPAREN,
                 &token::RPAREN,
-                seq_sep_trailing_disallowed(token::COMMA),
+                seq_sep_trailing_allowed(token::COMMA),
                 |p| {
                     if p.token == token::DOTDOTDOT {
                         p.bump();
diff --git a/src/llvm b/src/llvm
-Subproject 8841dcef357e051c34a46030db7c7b1a83f9b1d
+Subproject 535989a92ce1f6f6488c94a2c8f4ed438349f16
diff --git a/src/rustllvm/llvm-auto-clean-trigger b/src/rustllvm/llvm-auto-clean-trigger
index 95b950973d1..96cd67dcec4 100644
--- a/src/rustllvm/llvm-auto-clean-trigger
+++ b/src/rustllvm/llvm-auto-clean-trigger
@@ -1,4 +1,4 @@
 # If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
 # The actual contents of this file do not matter, but to trigger a change on the
 # build bots then the contents should be changed so git updates the mtime.
-2013-12-29
+2014-01-22
diff --git a/src/test/bench/core-map.rs b/src/test/bench/core-map.rs
index 0a37e93f6e7..4c75ca494ff 100644
--- a/src/test/bench/core-map.rs
+++ b/src/test/bench/core-map.rs
@@ -52,13 +52,13 @@ fn descending<M: MutableMap<uint, uint>>(map: &mut M, n_keys: uint) {
     println!(" Descending integers:");
 
     timed("insert", || {
-        for i in range(0, n_keys).invert() {
+        for i in range(0, n_keys).rev() {
             map.insert(i, i + 1);
         }
     });
 
     timed("search", || {
-        for i in range(0, n_keys).invert() {
+        for i in range(0, n_keys).rev() {
             assert_eq!(map.find(&i).unwrap(), &(i + 1));
         }
     });
diff --git a/src/test/bench/shootout-meteor.rs b/src/test/bench/shootout-meteor.rs
index c5b01e68fc4..53d188962e8 100644
--- a/src/test/bench/shootout-meteor.rs
+++ b/src/test/bench/shootout-meteor.rs
@@ -220,7 +220,7 @@ fn handle_sol(raw_sol: &List<u64>, data: &mut Data) -> bool {
     // reverse order, i.e. the board rotated by half a turn.
     data.nb += 2;
     let sol1 = to_utf8(raw_sol);
-    let sol2: ~str = sol1.chars().invert().collect();
+    let sol2: ~str = sol1.chars().rev().collect();
 
     if data.nb == 2 {
         data.min = sol1.clone();
diff --git a/src/test/compile-fail/borrowck-borrow-mut-object-twice.rs b/src/test/compile-fail/borrowck-borrow-mut-object-twice.rs
index 502d7e017b5..c338aac2ddf 100644
--- a/src/test/compile-fail/borrowck-borrow-mut-object-twice.rs
+++ b/src/test/compile-fail/borrowck-borrow-mut-object-twice.rs
@@ -18,7 +18,7 @@ trait Foo {
 
 fn test(x: &mut Foo) {
     let _y = x.f1();
-    x.f2(); //~ ERROR cannot borrow `*x` as mutable more than once at a time
+    x.f2(); //~ ERROR cannot borrow `*x` because it is already borrowed as mutable
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/borrowck-report-with-custom-diagnostic.rs b/src/test/compile-fail/borrowck-report-with-custom-diagnostic.rs
new file mode 100644
index 00000000000..3c01045369f
--- /dev/null
+++ b/src/test/compile-fail/borrowck-report-with-custom-diagnostic.rs
@@ -0,0 +1,31 @@
+#[allow(dead_code)];
+fn main() {
+    // Original borrow ends at end of function
+    let mut x = 1u;
+    let y = &mut x;
+    let z = &x; //~ ERROR cannot borrow
+}
+//~^ NOTE previous borrow ends here
+
+fn foo() {
+    match true {
+        true => {
+            // Original borrow ends at end of match arm
+            let mut x = 1u;
+            let y = &x;
+            let z = &mut x; //~ ERROR cannot borrow
+        }
+     //~^ NOTE previous borrow ends here
+        false => ()
+    }
+}
+
+fn bar() {
+    // Original borrow ends at end of closure
+    || {
+        let mut x = 1u;
+        let y = &mut x;
+        let z = &mut x; //~ ERROR cannot borrow
+    };
+ //~^ NOTE previous borrow ends here
+}
diff --git a/src/test/compile-fail/mut-cant-alias.rs b/src/test/compile-fail/mut-cant-alias.rs
index f031467328f..5b8079b832e 100644
--- a/src/test/compile-fail/mut-cant-alias.rs
+++ b/src/test/compile-fail/mut-cant-alias.rs
@@ -14,5 +14,5 @@ fn main() {
     let m = RefCell::new(0);
     let mut b = m.borrow_mut();
     let b1 = b.get();
-    let b2 = b.get(); //~ ERROR cannot borrow `b` as mutable more than once at a time
+    let b2 = b.get(); //~ ERROR cannot borrow `b` because it is already borrowed as mutable
 }
diff --git a/src/test/compile-fail/vec-mut-iter-borrow.rs b/src/test/compile-fail/vec-mut-iter-borrow.rs
index 19c786b553f..21ffc1ae7f9 100644
--- a/src/test/compile-fail/vec-mut-iter-borrow.rs
+++ b/src/test/compile-fail/vec-mut-iter-borrow.rs
@@ -12,6 +12,6 @@ fn main() {
     let mut xs = ~[1, 2, 3, 4];
 
     for x in xs.mut_iter() {
-        xs.push(1) //~ ERROR cannot borrow `xs` as mutable
+        xs.push(1) //~ ERROR cannot borrow `xs` because it is already borrowed as mutable
     }
 }
diff --git a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs
index 0ba2bfd1595..a8b7dc3d382 100644
--- a/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs
+++ b/src/test/run-pass-fulldeps/quote-unused-sp-no-warning.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 // xfail-fast
+// xfail-android
 
 #[deny(unused_variable)];
 
diff --git a/src/test/run-pass/exponential-notation.rs b/src/test/run-pass/exponential-notation.rs
new file mode 100644
index 00000000000..254c093e703
--- /dev/null
+++ b/src/test/run-pass/exponential-notation.rs
@@ -0,0 +1,34 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[feature(macro_rules)];
+
+use s = std::num::strconv;
+use to_str = std::num::strconv::float_to_str_common;
+
+macro_rules! t(($a:expr, $b:expr) => { { let (r, _) = $a; assert_eq!(r, $b.to_owned()) } })
+
+pub fn main() {
+    // Basic usage
+    t!(to_str(1.2345678e-5, 10u, true, s::SignNeg, s::DigMax(6), s::ExpDec, false),
+             "1.234568e-5")
+
+    // Hexadecimal output
+    t!(to_str(7.281738281250e+01, 16u, true, s::SignAll, s::DigMax(6), s::ExpBin, false),
+              "+1.2345p+6")
+    t!(to_str(-1.777768135071e-02, 16u, true, s::SignAll, s::DigMax(6), s::ExpBin, false),
+             "-1.2345p-6")
+
+    // Some denormals
+    t!(to_str(4.9406564584124654e-324, 10u, true, s::SignNeg, s::DigMax(6), s::ExpBin, false),
+             "1p-1074")
+    t!(to_str(2.2250738585072009e-308, 10u, true, s::SignNeg, s::DigMax(6), s::ExpBin, false),
+             "1p-1022")
+}
diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs
index 76759d04ab4..610cba1eb1f 100644
--- a/src/test/run-pass/ifmt.rs
+++ b/src/test/run-pass/ifmt.rs
@@ -1,4 +1,4 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -219,6 +219,14 @@ pub fn main() {
     t!(format!("{:+10.3f}", 1.0f64),  "    +1.000");
     t!(format!("{:+10.3f}", -1.0f64), "    -1.000");
 
+    t!(format!("{:e}", 1.2345e6f32), "1.2345e6");
+    t!(format!("{:e}", 1.2345e6f64), "1.2345e6");
+    t!(format!("{:E}", 1.2345e6f64), "1.2345E6");
+    t!(format!("{:.3e}", 1.2345e6f64), "1.234e6");
+    t!(format!("{:10.3e}", 1.2345e6f64),   "   1.234e6");
+    t!(format!("{:+10.3e}", 1.2345e6f64),  "  +1.234e6");
+    t!(format!("{:+10.3e}", -1.2345e6f64), "  -1.234e6");
+
     // Escaping
     t!(format!("\\{"), "{");
     t!(format!("\\}"), "}");
diff --git a/src/test/run-pass/trailing-comma.rs b/src/test/run-pass/trailing-comma.rs
new file mode 100644
index 00000000000..13d79959f81
--- /dev/null
+++ b/src/test/run-pass/trailing-comma.rs
@@ -0,0 +1,16 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn f(_: int,) {}
+
+pub fn main() {
+    f(0,);
+    let (_, _,) = (1, 1,);
+}