about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compiletest/compiletest.rs4
-rw-r--r--src/compiletest/util.rs2
-rw-r--r--src/liballoc/lib.rs1
-rw-r--r--src/libarena/lib.rs71
-rw-r--r--src/libcollections/bench.rs198
-rw-r--r--src/libcollections/btree/map.rs72
-rw-r--r--src/libcollections/btree/node.rs16
-rw-r--r--src/libcollections/fmt.rs2
-rw-r--r--src/libcollections/lib.rs8
-rw-r--r--src/libcollections/slice.rs12
-rw-r--r--src/libcollections/vec.rs18
-rw-r--r--src/libcollections/vec_map.rs73
-rw-r--r--src/libcore/fmt/mod.rs2
-rw-r--r--src/libcore/intrinsics.rs11
-rw-r--r--src/libcore/marker.rs18
-rw-r--r--src/libcore/ops.rs9
-rw-r--r--src/libcore/ptr.rs17
-rw-r--r--src/libcore/slice.rs39
-rw-r--r--src/libcore/str/mod.rs6
-rw-r--r--src/libcoretest/any.rs22
-rw-r--r--src/libcoretest/cell.rs24
-rw-r--r--src/libcoretest/char.rs24
-rw-r--r--src/libcoretest/iter.rs90
-rw-r--r--src/libcoretest/mem.rs38
-rw-r--r--src/libcoretest/num/uint_macros.rs8
-rw-r--r--src/libcoretest/ops.rs14
-rw-r--r--src/libcoretest/ptr.rs4
-rw-r--r--src/libcoretest/tuple.rs2
-rw-r--r--src/libflate/lib.rs4
-rw-r--r--src/liblibc/lib.rs3
-rw-r--r--src/liblog/lib.rs2
-rw-r--r--src/librbml/lib.rs7
-rw-r--r--src/librustc/lint/builtin.rs42
-rw-r--r--src/librustc/lint/context.rs2
-rw-r--r--src/librustc/metadata/creader.rs2
-rw-r--r--src/librustc/metadata/csearch.rs8
-rw-r--r--src/librustc/metadata/decoder.rs40
-rw-r--r--src/librustc/metadata/encoder.rs69
-rw-r--r--src/librustc/metadata/filesearch.rs2
-rw-r--r--src/librustc/metadata/tydecode.rs11
-rw-r--r--src/librustc/metadata/tyencode.rs8
-rw-r--r--src/librustc/middle/astencode.rs19
-rw-r--r--src/librustc/middle/dataflow.rs22
-rw-r--r--src/librustc/middle/dead.rs2
-rw-r--r--src/librustc/middle/entry.rs5
-rw-r--r--src/librustc/middle/graph.rs6
-rw-r--r--src/librustc/middle/infer/error_reporting.rs27
-rw-r--r--src/librustc/middle/infer/mod.rs5
-rw-r--r--src/librustc/middle/infer/region_inference/graphviz.rs4
-rw-r--r--src/librustc/middle/infer/region_inference/mod.rs15
-rw-r--r--src/librustc/middle/lang_items.rs2
-rw-r--r--src/librustc/middle/liveness.rs4
-rw-r--r--src/librustc/middle/mem_categorization.rs5
-rw-r--r--src/librustc/middle/region.rs139
-rw-r--r--src/librustc/middle/resolve_lifetime.rs16
-rw-r--r--src/librustc/middle/stability.rs43
-rw-r--r--src/librustc/middle/subst.rs18
-rw-r--r--src/librustc/middle/traits/mod.rs12
-rw-r--r--src/librustc/middle/traits/object_safety.rs5
-rw-r--r--src/librustc/middle/traits/project.rs24
-rw-r--r--src/librustc/middle/traits/select.rs8
-rw-r--r--src/librustc/middle/traits/util.rs2
-rw-r--r--src/librustc/middle/ty.rs191
-rw-r--r--src/librustc/middle/ty_fold.rs13
-rw-r--r--src/librustc/plugin/load.rs67
-rw-r--r--src/librustc/session/config.rs2
-rw-r--r--src/librustc/util/ppaux.rs111
-rw-r--r--src/librustc_back/target/mod.rs2
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs32
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/mod.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs12
-rw-r--r--src/librustc_borrowck/borrowck/move_data.rs6
-rw-r--r--src/librustc_driver/driver.rs4
-rw-r--r--src/librustc_driver/lib.rs5
-rw-r--r--src/librustc_driver/test.rs4
-rw-r--r--src/librustc_resolve/diagnostics.rs3
-rw-r--r--src/librustc_resolve/lib.rs44
-rw-r--r--src/librustc_trans/back/write.rs11
-rw-r--r--src/librustc_trans/save/mod.rs2
-rw-r--r--src/librustc_trans/trans/cleanup.rs17
-rw-r--r--src/librustc_typeck/astconv.rs11
-rw-r--r--src/librustc_typeck/check/_match.rs13
-rw-r--r--src/librustc_typeck/check/closure.rs6
-rw-r--r--src/librustc_typeck/check/compare_method.rs4
-rw-r--r--src/librustc_typeck/check/dropck.rs293
-rw-r--r--src/librustc_typeck/check/method/confirm.rs29
-rw-r--r--src/librustc_typeck/check/method/mod.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs12
-rw-r--r--src/librustc_typeck/check/mod.rs122
-rw-r--r--src/librustc_typeck/check/regionck.rs76
-rw-r--r--src/librustc_typeck/check/vtable.rs13
-rw-r--r--src/librustc_typeck/check/wf.rs66
-rw-r--r--src/librustc_typeck/coherence/mod.rs3
-rw-r--r--src/librustc_typeck/collect.rs920
-rw-r--r--src/librustc_typeck/lib.rs13
-rw-r--r--src/librustdoc/clean/inline.rs20
-rw-r--r--src/librustdoc/clean/mod.rs19
-rw-r--r--src/librustdoc/lib.rs6
-rw-r--r--src/librustdoc/passes.rs6
-rw-r--r--src/libserialize/collection_impls.rs4
-rw-r--r--src/libserialize/lib.rs1
-rw-r--r--src/libstd/dynamic_lib.rs2
-rw-r--r--src/libstd/env.rs169
-rw-r--r--src/libstd/lib.rs10
-rw-r--r--src/libstd/net/addr.rs592
-rw-r--r--src/libstd/net/ip.rs449
-rw-r--r--src/libstd/net/mod.rs99
-rw-r--r--src/libstd/net/parser.rs330
-rw-r--r--src/libstd/net/tcp.rs792
-rw-r--r--src/libstd/net/test.rs39
-rw-r--r--src/libstd/net/udp.rs291
-rw-r--r--src/libstd/old_io/mem.rs1
-rw-r--r--src/libstd/old_io/mod.rs41
-rw-r--r--src/libstd/old_io/stdio.rs9
-rw-r--r--src/libstd/os.rs11
-rwxr-xr-xsrc/libstd/path.rs3
-rw-r--r--src/libstd/rt/backtrace.rs2
-rw-r--r--src/libstd/rt/unwind.rs2
-rw-r--r--src/libstd/rt/util.rs4
-rw-r--r--src/libstd/sync/mpsc/select.rs6
-rw-r--r--src/libstd/sync/mpsc/shared.rs12
-rw-r--r--src/libstd/sync/mpsc/stream.rs8
-rw-r--r--src/libstd/sync/once.rs8
-rw-r--r--src/libstd/sys/common/mod.rs1
-rw-r--r--src/libstd/sys/common/net2.rs393
-rw-r--r--src/libstd/sys/common/thread.rs4
-rw-r--r--src/libstd/sys/common/thread_local.rs5
-rw-r--r--src/libstd/sys/unix/c.rs9
-rw-r--r--src/libstd/sys/unix/ext.rs14
-rw-r--r--src/libstd/sys/unix/fd.rs7
-rw-r--r--src/libstd/sys/unix/fs2.rs2
-rw-r--r--src/libstd/sys/unix/mod.rs4
-rw-r--r--src/libstd/sys/unix/net.rs74
-rw-r--r--src/libstd/sys/windows/c.rs42
-rw-r--r--src/libstd/sys/windows/ext.rs11
-rw-r--r--src/libstd/sys/windows/mod.rs1
-rw-r--r--src/libstd/sys/windows/net.rs121
-rw-r--r--src/libstd/thread_local/mod.rs9
-rw-r--r--src/libstd/thread_local/scoped.rs26
-rw-r--r--src/libsyntax/ast.rs8
-rw-r--r--src/libsyntax/ext/env.rs4
-rw-r--r--src/libsyntax/feature_gate.rs10
-rw-r--r--src/libsyntax/test.rs22
-rw-r--r--src/libterm/lib.rs1
-rw-r--r--src/libterm/terminfo/mod.rs4
-rw-r--r--src/libterm/terminfo/searcher.rs4
-rw-r--r--src/libtest/lib.rs9
-rw-r--r--src/libunicode/lib.rs2
-rw-r--r--src/test/auxiliary/i8.rs13
-rw-r--r--src/test/auxiliary/issue-10028.rs2
-rw-r--r--src/test/auxiliary/issue-2631-a.rs3
-rw-r--r--src/test/bench/shootout-k-nucleotide.rs4
-rw-r--r--src/test/bench/sudoku.rs4
-rw-r--r--src/test/compile-fail/borrowck-partial-reinit-1.rs49
-rw-r--r--src/test/compile-fail/borrowck-partial-reinit-2.rs34
-rw-r--r--src/test/compile-fail/borrowck-partial-reinit-3.rs22
-rw-r--r--src/test/compile-fail/borrowck-partial-reinit-4.rs33
-rw-r--r--src/test/compile-fail/destructor-restrictions.rs21
-rw-r--r--src/test/compile-fail/dropck_arr_cycle_checked.rs115
-rw-r--r--src/test/compile-fail/dropck_direct_cycle_with_drop.rs55
-rw-r--r--src/test/compile-fail/dropck_tarena_cycle_checked.rs130
-rw-r--r--src/test/compile-fail/dropck_tarena_unsound_drop.rs54
-rw-r--r--src/test/compile-fail/dropck_vec_cycle_checked.rs122
-rw-r--r--src/test/compile-fail/feature-gate-simd-ffi.rs2
-rw-r--r--src/test/compile-fail/issue-20427.rs66
-rw-r--r--src/test/compile-fail/lint-stability.rs4
-rw-r--r--src/test/compile-fail/lint-stability2.rs23
-rw-r--r--src/test/compile-fail/lint-stability3.rs25
-rw-r--r--src/test/compile-fail/lint-unexported-no-mangle.rs17
-rw-r--r--src/test/compile-fail/macro-reexport-undef.rs20
-rw-r--r--src/test/compile-fail/macro-use-undef.rs19
-rw-r--r--src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs135
-rw-r--r--src/test/compile-fail/vec_refs_data_with_early_death.rs31
-rw-r--r--src/test/run-make/empty-file/Makefile5
-rw-r--r--src/test/run-make/empty-file/empty.rs0
-rw-r--r--src/test/run-pass/arr_cycle.rs39
-rw-r--r--src/test/run-pass/associated-types-issue-20220.rs36
-rw-r--r--src/test/run-pass/associated-types-stream.rs47
-rw-r--r--src/test/run-pass/astconv-cycle-between-trait-and-type.rs36
-rw-r--r--src/test/run-pass/attr-no-drop-flag-size.rs1
-rw-r--r--src/test/run-pass/dropck_tarena_sound_drop.rs51
-rw-r--r--src/test/run-pass/env-vars.rs4
-rw-r--r--src/test/run-pass/issue-10734.rs2
-rw-r--r--src/test/run-pass/issue-13304.rs3
-rw-r--r--src/test/run-pass/issue-14456.rs3
-rw-r--r--src/test/run-pass/issue-20343.rs38
-rw-r--r--src/test/run-pass/issue-22036.rs33
-rw-r--r--src/test/run-pass/multidispatch-conditional-impl-not-considered.rs2
-rw-r--r--src/test/run-pass/nondrop-cycle.rs38
-rw-r--r--src/test/run-pass/overloaded-autoderef.rs3
-rw-r--r--src/test/run-pass/regions-refcell.rs53
-rw-r--r--src/test/run-pass/regions-trait-object-1.rs43
-rw-r--r--src/test/run-pass/trait-object-with-lifetime-bound.rs42
-rw-r--r--src/test/run-pass/vec_cycle.rs47
-rw-r--r--src/test/run-pass/vec_cycle_wrapped.rs58
-rw-r--r--src/test/run-pass/zero-size-type-destructors.rs2
196 files changed, 7417 insertions, 1394 deletions
diff --git a/src/compiletest/compiletest.rs b/src/compiletest/compiletest.rs
index 3c92fa02f20..385f1b9e791 100644
--- a/src/compiletest/compiletest.rs
+++ b/src/compiletest/compiletest.rs
@@ -14,7 +14,6 @@
 #![feature(collections)]
 #![feature(int_uint)]
 #![feature(io)]
-#![feature(os)]
 #![feature(path)]
 #![feature(rustc_private)]
 #![feature(slicing_syntax, unboxed_closures)]
@@ -48,8 +47,7 @@ pub mod common;
 pub mod errors;
 
 pub fn main() {
-    let args = env::args().map(|s| s.into_string().unwrap()).collect();;
-    let config = parse_config(args);
+    let config = parse_config(env::args().collect());
 
     if config.valgrind_path.is_none() && config.force_valgrind {
         panic!("Can't find Valgrind to run Valgrind tests");
diff --git a/src/compiletest/util.rs b/src/compiletest/util.rs
index 078eb7bba20..c046a89cba5 100644
--- a/src/compiletest/util.rs
+++ b/src/compiletest/util.rs
@@ -40,7 +40,7 @@ pub fn make_new_path(path: &str) -> String {
 
     // Windows just uses PATH as the library search path, so we have to
     // maintain the current value while adding our own
-    match env::var_string(lib_path_env_var()) {
+    match env::var(lib_path_env_var()) {
       Ok(curr) => {
         format!("{}{}{}", path, path_div(), curr)
       }
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 0e6266f9cbc..87106041c69 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -71,6 +71,7 @@
 #![feature(box_syntax)]
 #![feature(optin_builtin_traits)]
 #![feature(unboxed_closures)]
+#![feature(unsafe_no_drop_flag)]
 #![feature(core)]
 #![feature(hash)]
 #![cfg_attr(all(not(feature = "external_funcs"), not(feature = "external_crate")),
diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs
index 223c5111f8f..4cd3d587580 100644
--- a/src/libarena/lib.rs
+++ b/src/libarena/lib.rs
@@ -42,6 +42,7 @@ use std::cell::{Cell, RefCell};
 use std::cmp;
 use std::intrinsics::{TyDesc, get_tydesc};
 use std::intrinsics;
+use std::marker;
 use std::mem;
 use std::num::{Int, UnsignedInt};
 use std::ptr;
@@ -88,27 +89,29 @@ impl Chunk {
 /// than objects without destructors. This reduces overhead when initializing
 /// plain-old-data (`Copy` types) and means we don't need to waste time running
 /// their destructors.
-pub struct Arena {
+pub struct Arena<'longer_than_self> {
     // The head is separated out from the list as a unbenchmarked
     // microoptimization, to avoid needing to case on the list to access the
     // head.
     head: RefCell<Chunk>,
     copy_head: RefCell<Chunk>,
     chunks: RefCell<Vec<Chunk>>,
+    _invariant: marker::InvariantLifetime<'longer_than_self>,
 }
 
-impl Arena {
+impl<'a> Arena<'a> {
     /// Allocates a new Arena with 32 bytes preallocated.
-    pub fn new() -> Arena {
+    pub fn new() -> Arena<'a> {
         Arena::new_with_size(32)
     }
 
     /// Allocates a new Arena with `initial_size` bytes preallocated.
-    pub fn new_with_size(initial_size: usize) -> Arena {
+    pub fn new_with_size(initial_size: usize) -> Arena<'a> {
         Arena {
             head: RefCell::new(chunk(initial_size, false)),
             copy_head: RefCell::new(chunk(initial_size, true)),
             chunks: RefCell::new(Vec::new()),
+            _invariant: marker::InvariantLifetime,
         }
     }
 }
@@ -122,7 +125,7 @@ fn chunk(size: usize, is_copy: bool) -> Chunk {
 }
 
 #[unsafe_destructor]
-impl Drop for Arena {
+impl<'longer_than_self> Drop for Arena<'longer_than_self> {
     fn drop(&mut self) {
         unsafe {
             destroy_chunk(&*self.head.borrow());
@@ -180,7 +183,7 @@ fn un_bitpack_tydesc_ptr(p: usize) -> (*const TyDesc, bool) {
     ((p & !1) as *const TyDesc, p & 1 == 1)
 }
 
-impl Arena {
+impl<'longer_than_self> Arena<'longer_than_self> {
     fn chunk_size(&self) -> usize {
         self.copy_head.borrow().capacity()
     }
@@ -293,7 +296,7 @@ impl Arena {
     /// Allocates a new item in the arena, using `op` to initialize the value,
     /// and returns a reference to it.
     #[inline]
-    pub fn alloc<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
+    pub fn alloc<T:'longer_than_self, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
         unsafe {
             if intrinsics::needs_drop::<T>() {
                 self.alloc_noncopy(op)
@@ -318,20 +321,6 @@ fn test_arena_destructors() {
 }
 
 #[test]
-fn test_arena_alloc_nested() {
-    struct Inner { value: usize }
-    struct Outer<'a> { inner: &'a Inner }
-
-    let arena = Arena::new();
-
-    let result = arena.alloc(|| Outer {
-        inner: arena.alloc(|| Inner { value: 10 })
-    });
-
-    assert_eq!(result.inner.value, 10);
-}
-
-#[test]
 #[should_fail]
 fn test_arena_destructors_fail() {
     let arena = Arena::new();
@@ -365,6 +354,10 @@ pub struct TypedArena<T> {
 
     /// A pointer to the first arena segment.
     first: RefCell<*mut TypedArenaChunk<T>>,
+
+    /// Marker indicating that dropping the arena causes its owned
+    /// instances of `T` to be dropped.
+    _own: marker::PhantomData<T>,
 }
 
 struct TypedArenaChunk<T> {
@@ -460,6 +453,7 @@ impl<T> TypedArena<T> {
                 ptr: Cell::new((*chunk).start() as *const T),
                 end: Cell::new((*chunk).end() as *const T),
                 first: RefCell::new(chunk),
+                _own: marker::PhantomData,
             }
         }
     }
@@ -524,6 +518,41 @@ mod tests {
     }
 
     #[test]
+    fn test_arena_alloc_nested() {
+        struct Inner { value: u8 }
+        struct Outer<'a> { inner: &'a Inner }
+        enum EI<'e> { I(Inner), O(Outer<'e>) }
+
+        struct Wrap<'a>(TypedArena<EI<'a>>);
+
+        impl<'a> Wrap<'a> {
+            fn alloc_inner<F:Fn() -> Inner>(&self, f: F) -> &Inner {
+                let r: &EI = self.0.alloc(EI::I(f()));
+                if let &EI::I(ref i) = r {
+                    i
+                } else {
+                    panic!("mismatch");
+                }
+            }
+            fn alloc_outer<F:Fn() -> Outer<'a>>(&self, f: F) -> &Outer {
+                let r: &EI = self.0.alloc(EI::O(f()));
+                if let &EI::O(ref o) = r {
+                    o
+                } else {
+                    panic!("mismatch");
+                }
+            }
+        }
+
+        let arena = Wrap(TypedArena::new());
+
+        let result = arena.alloc_outer(|| Outer {
+            inner: arena.alloc_inner(|| Inner { value: 10 }) });
+
+        assert_eq!(result.inner.value, 10);
+    }
+
+    #[test]
     pub fn test_copy() {
         let arena = TypedArena::new();
         for _ in 0..100000 {
diff --git a/src/libcollections/bench.rs b/src/libcollections/bench.rs
index b0a5911720a..107f6031c11 100644
--- a/src/libcollections/bench.rs
+++ b/src/libcollections/bench.rs
@@ -8,103 +8,115 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use prelude::*;
-use std::rand;
-use std::rand::Rng;
-use test::{Bencher, black_box};
-
-pub fn insert_rand_n<M, I, R>(n: usize,
-                              map: &mut M,
-                              b: &mut Bencher,
-                              mut insert: I,
-                              mut remove: R) where
-    I: FnMut(&mut M, usize),
-    R: FnMut(&mut M, usize),
-{
-    // setup
-    let mut rng = rand::weak_rng();
-
-    for _ in 0..n {
-        insert(map, rng.gen::<usize>() % n);
-    }
-
-    // measure
-    b.iter(|| {
-        let k = rng.gen::<usize>() % n;
-        insert(map, k);
-        remove(map, k);
-    });
-    black_box(map);
+macro_rules! map_insert_rand_bench {
+    ($name: ident, $n: expr, $map: ident) => (
+        #[bench]
+        pub fn $name(b: &mut ::test::Bencher) {
+            use std::rand;
+            use std::rand::Rng;
+            use test::black_box;
+
+            let n: usize = $n;
+            let mut map = $map::new();
+            // setup
+            let mut rng = rand::weak_rng();
+
+            for _ in 0..n {
+                let i = rng.gen() % n;
+                map.insert(i, i);
+            }
+
+            // measure
+            b.iter(|| {
+                let k = rng.gen() % n;
+                map.insert(k, k);
+                map.remove(&k);
+            });
+            black_box(map);
+        }
+    )
 }
 
-pub fn insert_seq_n<M, I, R>(n: usize,
-                             map: &mut M,
-                             b: &mut Bencher,
-                             mut insert: I,
-                             mut remove: R) where
-    I: FnMut(&mut M, usize),
-    R: FnMut(&mut M, usize),
-{
-    // setup
-    for i in 0..n {
-        insert(map, i * 2);
-    }
-
-    // measure
-    let mut i = 1;
-    b.iter(|| {
-        insert(map, i);
-        remove(map, i);
-        i = (i + 2) % n;
-    });
-    black_box(map);
+macro_rules! map_insert_seq_bench {
+    ($name: ident, $n: expr, $map: ident) => (
+        #[bench]
+        pub fn $name(b: &mut ::test::Bencher) {
+            use test::black_box;
+
+            let mut map = $map::new();
+            let n: usize = $n;
+            // setup
+            for i in 0..n {
+                map.insert(i * 2, i * 2);
+            }
+
+            // measure
+            let mut i = 1;
+            b.iter(|| {
+                map.insert(i, i);
+                map.remove(&i);
+                i = (i + 2) % n;
+            });
+            black_box(map);
+        }
+    )
 }
 
-pub fn find_rand_n<M, T, I, F>(n: usize,
-                               map: &mut M,
-                               b: &mut Bencher,
-                               mut insert: I,
-                               mut find: F) where
-    I: FnMut(&mut M, usize),
-    F: FnMut(&M, usize) -> T,
-{
-    // setup
-    let mut rng = rand::weak_rng();
-    let mut keys: Vec<_> = (0..n).map(|_| rng.gen::<usize>() % n).collect();
-
-    for k in &keys {
-        insert(map, *k);
-    }
-
-    rng.shuffle(&mut keys);
-
-    // measure
-    let mut i = 0;
-    b.iter(|| {
-        let t = find(map, keys[i]);
-        i = (i + 1) % n;
-        black_box(t);
-    })
+macro_rules! map_find_rand_bench {
+    ($name: ident, $n: expr, $map: ident) => (
+        #[bench]
+        pub fn $name(b: &mut ::test::Bencher) {
+            use std::rand;
+            use std::iter::IteratorExt;
+            use std::rand::Rng;
+            use test::black_box;
+            use vec::Vec;
+
+            let mut map = $map::new();
+            let n: usize = $n;
+
+            // setup
+            let mut rng = rand::weak_rng();
+            let mut keys: Vec<_> = (0..n).map(|_| rng.gen() % n).collect();
+
+            for &k in &keys {
+                map.insert(k, k);
+            }
+
+            rng.shuffle(&mut keys);
+
+            // measure
+            let mut i = 0;
+            b.iter(|| {
+                let t = map.get(&keys[i]);
+                i = (i + 1) % n;
+                black_box(t);
+            })
+        }
+    )
 }
 
-pub fn find_seq_n<M, T, I, F>(n: usize,
-                              map: &mut M,
-                              b: &mut Bencher,
-                              mut insert: I,
-                              mut find: F) where
-    I: FnMut(&mut M, usize),
-    F: FnMut(&M, usize) -> T,
-{
-    // setup
-    for i in 0..n {
-        insert(map, i);
-    }
-
-    // measure
-    let mut i = 0;
-    b.iter(|| {
-        let x = find(map, i);
-        i = (i + 1) % n;
-        black_box(x);
-    })
+macro_rules! map_find_seq_bench {
+    ($name: ident, $n: expr, $map: ident) => (
+        #[bench]
+        pub fn $name(b: &mut ::test::Bencher) {
+            use test::black_box;
+
+            let mut map = $map::new();
+            let n: usize = $n;
+
+            // setup
+            for i in 0..n {
+                map.insert(i, i);
+            }
+
+            // measure
+            let mut i = 0;
+            b.iter(|| {
+                let x = map.get(&i);
+                i = (i + 1) % n;
+                black_box(x);
+            })
+        }
+    )
 }
diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs
index 2cef08725a2..0e4a4002d6a 100644
--- a/src/libcollections/btree/map.rs
+++ b/src/libcollections/btree/map.rs
@@ -1843,74 +1843,18 @@ mod bench {
     use test::{Bencher, black_box};
 
     use super::BTreeMap;
-    use bench::{insert_rand_n, insert_seq_n, find_rand_n, find_seq_n};
 
-    #[bench]
-    pub fn insert_rand_100(b: &mut Bencher) {
-        let mut m = BTreeMap::new();
-        insert_rand_n(100, &mut m, b,
-                      |m, i| { m.insert(i, 1); },
-                      |m, i| { m.remove(&i); });
-    }
-
-    #[bench]
-    pub fn insert_rand_10_000(b: &mut Bencher) {
-        let mut m = BTreeMap::new();
-        insert_rand_n(10_000, &mut m, b,
-                      |m, i| { m.insert(i, 1); },
-                      |m, i| { m.remove(&i); });
-    }
-
-    // Insert seq
-    #[bench]
-    pub fn insert_seq_100(b: &mut Bencher) {
-        let mut m = BTreeMap::new();
-        insert_seq_n(100, &mut m, b,
-                     |m, i| { m.insert(i, 1); },
-                     |m, i| { m.remove(&i); });
-    }
-
-    #[bench]
-    pub fn insert_seq_10_000(b: &mut Bencher) {
-        let mut m = BTreeMap::new();
-        insert_seq_n(10_000, &mut m, b,
-                     |m, i| { m.insert(i, 1); },
-                     |m, i| { m.remove(&i); });
-    }
+    map_insert_rand_bench!{insert_rand_100,    100,    BTreeMap}
+    map_insert_rand_bench!{insert_rand_10_000, 10_000, BTreeMap}
 
-    // Find rand
-    #[bench]
-    pub fn find_rand_100(b: &mut Bencher) {
-        let mut m = BTreeMap::new();
-        find_rand_n(100, &mut m, b,
-                    |m, i| { m.insert(i, 1); },
-                    |m, i| { m.get(&i); });
-    }
-
-    #[bench]
-    pub fn find_rand_10_000(b: &mut Bencher) {
-        let mut m = BTreeMap::new();
-        find_rand_n(10_000, &mut m, b,
-                    |m, i| { m.insert(i, 1); },
-                    |m, i| { m.get(&i); });
-    }
+    map_insert_seq_bench!{insert_seq_100,    100,    BTreeMap}
+    map_insert_seq_bench!{insert_seq_10_000, 10_000, BTreeMap}
 
-    // Find seq
-    #[bench]
-    pub fn find_seq_100(b: &mut Bencher) {
-        let mut m = BTreeMap::new();
-        find_seq_n(100, &mut m, b,
-                   |m, i| { m.insert(i, 1); },
-                   |m, i| { m.get(&i); });
-    }
+    map_find_rand_bench!{find_rand_100,    100,    BTreeMap}
+    map_find_rand_bench!{find_rand_10_000, 10_000, BTreeMap}
 
-    #[bench]
-    pub fn find_seq_10_000(b: &mut Bencher) {
-        let mut m = BTreeMap::new();
-        find_seq_n(10_000, &mut m, b,
-                   |m, i| { m.insert(i, 1); },
-                   |m, i| { m.get(&i); });
-    }
+    map_find_seq_bench!{find_seq_100,    100,    BTreeMap}
+    map_find_seq_bench!{find_seq_10_000, 10_000, BTreeMap}
 
     fn bench_iter(b: &mut Bencher, size: i32) {
         let mut map = BTreeMap::<i32, i32>::new();
diff --git a/src/libcollections/btree/node.rs b/src/libcollections/btree/node.rs
index bfe74cc6fb4..24523d4dcc9 100644
--- a/src/libcollections/btree/node.rs
+++ b/src/libcollections/btree/node.rs
@@ -278,7 +278,7 @@ impl<T> Drop for RawItems<T> {
 #[unsafe_destructor]
 impl<K, V> Drop for Node<K, V> {
     fn drop(&mut self) {
-        if self.keys.0.is_null() {
+        if self.keys.ptr.is_null() {
             // We have already cleaned up this node.
             return;
         }
@@ -292,7 +292,7 @@ impl<K, V> Drop for Node<K, V> {
             self.destroy();
         }
 
-        self.keys.0 = ptr::null_mut();
+        self.keys.ptr = ptr::null_mut();
     }
 }
 
@@ -337,18 +337,18 @@ impl<K, V> Node<K, V> {
     unsafe fn destroy(&mut self) {
         let (alignment, size) =
                 calculate_allocation_generic::<K, V>(self.capacity(), self.is_leaf());
-        heap::deallocate(self.keys.0 as *mut u8, size, alignment);
+        heap::deallocate(self.keys.ptr as *mut u8, size, alignment);
     }
 
     #[inline]
     pub fn as_slices<'a>(&'a self) -> (&'a [K], &'a [V]) {
         unsafe {(
             mem::transmute(raw::Slice {
-                data: self.keys.0,
+                data: self.keys.ptr,
                 len: self.len()
             }),
             mem::transmute(raw::Slice {
-                data: self.vals.0,
+                data: self.vals.ptr,
                 len: self.len()
             })
         )}
@@ -368,7 +368,7 @@ impl<K, V> Node<K, V> {
         } else {
             unsafe {
                 mem::transmute(raw::Slice {
-                    data: self.edges.0,
+                    data: self.edges.ptr,
                     len: self.len() + 1
                 })
             }
@@ -586,7 +586,7 @@ impl <K, V> Node<K, V> {
 
     /// If the node has any children
     pub fn is_leaf(&self) -> bool {
-        self.edges.0.is_null()
+        self.edges.ptr.is_null()
     }
 
     /// if the node has too few elements
@@ -1064,7 +1064,7 @@ impl<K, V> Node<K, V> {
                     vals: RawItems::from_slice(self.vals()),
                     edges: RawItems::from_slice(self.edges()),
 
-                    ptr: self.keys.0 as *mut u8,
+                    ptr: self.keys.ptr as *mut u8,
                     capacity: self.capacity(),
                     is_leaf: self.is_leaf()
                 },
diff --git a/src/libcollections/fmt.rs b/src/libcollections/fmt.rs
index 5f337528d78..8f02f9fd580 100644
--- a/src/libcollections/fmt.rs
+++ b/src/libcollections/fmt.rs
@@ -401,7 +401,7 @@
 //! them with the same character. For example, the `{` character is escaped with
 //! `{{` and the `}` character is escaped with `}}`.
 
-#![unstable(feature = "std_misc")]
+#![stable(feature = "rust1", since = "1.0.0")]
 
 pub use core::fmt::{Formatter, Result, Writer, rt};
 pub use core::fmt::{Show, String, Octal, Binary};
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index 0dd48fcfab6..460c897b6ad 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -27,10 +27,12 @@
 #![feature(box_patterns)]
 #![feature(core)]
 #![feature(hash)]
+#![feature(slicing_syntax)]
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
 #![feature(unicode)]
-#![feature(unsafe_destructor, slicing_syntax)]
+#![feature(unsafe_destructor)]
+#![feature(unsafe_no_drop_flag)]
 #![cfg_attr(test, feature(rand, rustc_private, test))]
 #![cfg_attr(test, allow(deprecated))] // rand
 
@@ -65,6 +67,8 @@ pub use alloc::boxed;
 #[macro_use]
 mod macros;
 
+#[cfg(test)] #[macro_use] mod bench;
+
 pub mod binary_heap;
 mod bit;
 mod btree;
@@ -102,8 +106,6 @@ pub mod btree_set {
 }
 
 
-#[cfg(test)] mod bench;
-
 // FIXME(#14344) this shouldn't be necessary
 #[doc(hidden)]
 pub fn fixme_14344_be_sure_to_link_to_collections() {}
diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs
index 679754be749..b3f398b9cdf 100644
--- a/src/libcollections/slice.rs
+++ b/src/libcollections/slice.rs
@@ -2508,6 +2508,18 @@ mod tests {
         let wins: &[&[_]] = &[&[1,2,3], &[2,3,4]];
         assert_eq!(v.windows(3).collect::<Vec<_>>(), wins);
         assert!(v.windows(6).next().is_none());
+
+        let wins: &[&[_]] = &[&[3,4], &[2,3], &[1,2]];
+        assert_eq!(v.windows(2).rev().collect::<Vec<&[_]>>(), wins);
+        let mut it = v.windows(2);
+        assert_eq!(it.indexable(), 3);
+        let win: &[_] = &[1,2];
+        assert_eq!(it.idx(0).unwrap(), win);
+        let win: &[_] = &[2,3];
+        assert_eq!(it.idx(1).unwrap(), win);
+        let win: &[_] = &[3,4];
+        assert_eq!(it.idx(2).unwrap(), win);
+        assert_eq!(it.idx(3), None);
     }
 
     #[test]
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index 7c7d783d129..cebde59634b 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -57,7 +57,7 @@ use core::default::Default;
 use core::fmt;
 use core::hash::{self, Hash};
 use core::iter::{repeat, FromIterator, IntoIterator};
-use core::marker::{ContravariantLifetime, InvariantType};
+use core::marker::{self, ContravariantLifetime, InvariantType};
 use core::mem;
 use core::nonzero::NonZero;
 use core::num::{Int, UnsignedInt};
@@ -140,6 +140,7 @@ pub struct Vec<T> {
     ptr: NonZero<*mut T>,
     len: usize,
     cap: usize,
+    _own: marker::PhantomData<T>,
 }
 
 unsafe impl<T: Send> Send for Vec<T> { }
@@ -166,7 +167,7 @@ impl<T> Vec<T> {
         // non-null value which is fine since we never call deallocate on the ptr
         // if cap is 0. The reason for this is because the pointer of a slice
         // being NULL would break the null pointer optimization for enums.
-        Vec { ptr: unsafe { NonZero::new(EMPTY as *mut T) }, len: 0, cap: 0 }
+        unsafe { Vec::from_raw_parts(EMPTY as *mut T, 0, 0) }
     }
 
     /// Constructs a new, empty `Vec<T>` with the specified capacity.
@@ -198,7 +199,7 @@ impl<T> Vec<T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn with_capacity(capacity: usize) -> Vec<T> {
         if mem::size_of::<T>() == 0 {
-            Vec { ptr: unsafe { NonZero::new(EMPTY as *mut T) }, len: 0, cap: usize::MAX }
+            unsafe { Vec::from_raw_parts(EMPTY as *mut T, 0, usize::MAX) }
         } else if capacity == 0 {
             Vec::new()
         } else {
@@ -206,7 +207,7 @@ impl<T> Vec<T> {
                                .expect("capacity overflow");
             let ptr = unsafe { allocate(size, mem::min_align_of::<T>()) };
             if ptr.is_null() { ::alloc::oom() }
-            Vec { ptr: unsafe { NonZero::new(ptr as *mut T) }, len: 0, cap: capacity }
+            unsafe { Vec::from_raw_parts(ptr as *mut T, 0, capacity) }
         }
     }
 
@@ -247,7 +248,12 @@ impl<T> Vec<T> {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub unsafe fn from_raw_parts(ptr: *mut T, length: usize,
                                  capacity: usize) -> Vec<T> {
-        Vec { ptr: NonZero::new(ptr), len: length, cap: capacity }
+        Vec {
+            ptr: NonZero::new(ptr),
+            len: length,
+            cap: capacity,
+            _own: marker::PhantomData,
+        }
     }
 
     /// Creates a vector by copying the elements from a raw pointer.
@@ -1636,7 +1642,7 @@ impl<T> IntoIter<T> {
             for _x in self.by_ref() { }
             let IntoIter { allocation, cap, ptr: _ptr, end: _end } = self;
             mem::forget(self);
-            Vec { ptr: NonZero::new(allocation), cap: cap, len: 0 }
+            Vec::from_raw_parts(allocation, 0, cap)
         }
     }
 }
diff --git a/src/libcollections/vec_map.rs b/src/libcollections/vec_map.rs
index 93d02de9b55..ba358ada0ad 100644
--- a/src/libcollections/vec_map.rs
+++ b/src/libcollections/vec_map.rs
@@ -1321,74 +1321,17 @@ mod test_map {
 
 #[cfg(test)]
 mod bench {
-    use test::Bencher;
     use super::VecMap;
-    use bench::{insert_rand_n, insert_seq_n, find_rand_n, find_seq_n};
 
-    #[bench]
-    pub fn insert_rand_100(b: &mut Bencher) {
-        let mut m = VecMap::new();
-        insert_rand_n(100, &mut m, b,
-                      |m, i| { m.insert(i, 1); },
-                      |m, i| { m.remove(&i); });
-    }
-
-    #[bench]
-    pub fn insert_rand_10_000(b: &mut Bencher) {
-        let mut m = VecMap::new();
-        insert_rand_n(10_000, &mut m, b,
-                      |m, i| { m.insert(i, 1); },
-                      |m, i| { m.remove(&i); });
-    }
-
-    // Insert seq
-    #[bench]
-    pub fn insert_seq_100(b: &mut Bencher) {
-        let mut m = VecMap::new();
-        insert_seq_n(100, &mut m, b,
-                     |m, i| { m.insert(i, 1); },
-                     |m, i| { m.remove(&i); });
-    }
-
-    #[bench]
-    pub fn insert_seq_10_000(b: &mut Bencher) {
-        let mut m = VecMap::new();
-        insert_seq_n(10_000, &mut m, b,
-                     |m, i| { m.insert(i, 1); },
-                     |m, i| { m.remove(&i); });
-    }
+    map_insert_rand_bench!{insert_rand_100,    100,    VecMap}
+    map_insert_rand_bench!{insert_rand_10_000, 10_000, VecMap}
 
-    // Find rand
-    #[bench]
-    pub fn find_rand_100(b: &mut Bencher) {
-        let mut m = VecMap::new();
-        find_rand_n(100, &mut m, b,
-                    |m, i| { m.insert(i, 1); },
-                    |m, i| { m.get(&i); });
-    }
-
-    #[bench]
-    pub fn find_rand_10_000(b: &mut Bencher) {
-        let mut m = VecMap::new();
-        find_rand_n(10_000, &mut m, b,
-                    |m, i| { m.insert(i, 1); },
-                    |m, i| { m.get(&i); });
-    }
+    map_insert_seq_bench!{insert_seq_100,    100,    VecMap}
+    map_insert_seq_bench!{insert_seq_10_000, 10_000, VecMap}
 
-    // Find seq
-    #[bench]
-    pub fn find_seq_100(b: &mut Bencher) {
-        let mut m = VecMap::new();
-        find_seq_n(100, &mut m, b,
-                   |m, i| { m.insert(i, 1); },
-                   |m, i| { m.get(&i); });
-    }
+    map_find_rand_bench!{find_rand_100,    100,    VecMap}
+    map_find_rand_bench!{find_rand_10_000, 10_000, VecMap}
 
-    #[bench]
-    pub fn find_seq_10_000(b: &mut Bencher) {
-        let mut m = VecMap::new();
-        find_seq_n(10_000, &mut m, b,
-                   |m, i| { m.insert(i, 1); },
-                   |m, i| { m.get(&i); });
-    }
+    map_find_seq_bench!{find_seq_100,    100,    VecMap}
+    map_find_seq_bench!{find_seq_10_000, 10_000, VecMap}
 }
diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs
index 0357b723b3c..f940300a269 100644
--- a/src/libcore/fmt/mod.rs
+++ b/src/libcore/fmt/mod.rs
@@ -268,6 +268,7 @@ pub trait Debug {
     fn fmt(&self, &mut Formatter) -> Result;
 }
 
+#[allow(deprecated)]
 impl<T: Show + ?Sized> Debug for T {
     #[allow(deprecated)]
     fn fmt(&self, f: &mut Formatter) -> Result { Show::fmt(self, f) }
@@ -295,6 +296,7 @@ pub trait Display {
     fn fmt(&self, &mut Formatter) -> Result;
 }
 
+#[allow(deprecated)]
 impl<T: String + ?Sized> Display for T {
     #[allow(deprecated)]
     fn fmt(&self, f: &mut Formatter) -> Result { String::fmt(self, f) }
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 5562845e11d..050c144b742 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -262,11 +262,12 @@ extern "rust-intrinsic" {
     ///
     /// # Safety
     ///
-    /// Beyond requiring that both regions of memory be allocated, it is Undefined Behaviour
-    /// for source and destination to overlap. Care must also be taken with the ownership of
-    /// `src` and `dst`. This method semantically moves the values of `src` into `dst`.
-    /// However it does not drop the contents of `dst`, or prevent the contents of `src`
-    /// from being dropped or used.
+    /// Beyond requiring that the program must be allowed to access both regions
+    /// of memory, it is Undefined Behaviour for source and destination to
+    /// overlap. Care must also be taken with the ownership of `src` and
+    /// `dst`. This method semantically moves the values of `src` into `dst`.
+    /// However it does not drop the contents of `dst`, or prevent the contents
+    /// of `src` from being dropped or used.
     ///
     /// # Examples
     ///
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index bf9e6bccc71..da93d4f6ca4 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -202,6 +202,24 @@ pub unsafe trait Sync {
     // Empty
 }
 
+/// A marker type that indicates to the compiler that the instances
+/// of the type itself owns instances of the type parameter `T`.
+///
+/// This is used to indicate that one or more instances of the type
+/// `T` could be dropped when instances of the type itself is dropped,
+/// though that may not be apparent from the other structure of the
+/// type itself. For example, the type may hold a `*mut T`, which the
+/// compiler does not automatically treat as owned.
+#[unstable(feature = "core",
+           reason = "Newly added to deal with scoping and destructor changes")]
+#[lang="phantom_data"]
+#[derive(PartialEq, Eq, PartialOrd, Ord)]
+pub struct PhantomData<T: ?Sized>;
+
+impl<T: ?Sized> Copy for PhantomData<T> {}
+impl<T: ?Sized> Clone for PhantomData<T> {
+    fn clone(&self) -> PhantomData<T> { *self }
+}
 
 /// A marker type whose type parameter `T` is considered to be
 /// covariant with respect to the type itself. This is (typically)
diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs
index 782483a34fc..a46536e341e 100644
--- a/src/libcore/ops.rs
+++ b/src/libcore/ops.rs
@@ -1119,8 +1119,7 @@ impl<'a, T: ?Sized> DerefMut for &'a mut T {
 
 /// A version of the call operator that takes an immutable receiver.
 #[lang="fn"]
-#[unstable(feature = "core",
-           reason = "uncertain about variadic generics, input versus associated types")]
+#[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_paren_sugar]
 pub trait Fn<Args> {
     type Output;
@@ -1131,8 +1130,7 @@ pub trait Fn<Args> {
 
 /// A version of the call operator that takes a mutable receiver.
 #[lang="fn_mut"]
-#[unstable(feature = "core",
-           reason = "uncertain about variadic generics, input versus associated types")]
+#[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_paren_sugar]
 pub trait FnMut<Args> {
     type Output;
@@ -1143,8 +1141,7 @@ pub trait FnMut<Args> {
 
 /// A version of the call operator that takes a by-value receiver.
 #[lang="fn_once"]
-#[unstable(feature = "core",
-           reason = "uncertain about variadic generics, input versus associated types")]
+#[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_paren_sugar]
 pub trait FnOnce<Args> {
     type Output;
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index bf801a88ca5..1b8ec048f8d 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -92,7 +92,7 @@ use mem;
 use clone::Clone;
 use intrinsics;
 use option::Option::{self, Some, None};
-use marker::{Send, Sized, Sync};
+use marker::{self, Send, Sized, Sync};
 
 use cmp::{PartialEq, Eq, Ord, PartialOrd};
 use cmp::Ordering::{self, Less, Equal, Greater};
@@ -522,7 +522,11 @@ impl<T> PartialOrd for *mut T {
 /// Useful for building abstractions like `Vec<T>` or `Box<T>`, which
 /// internally use raw pointers to manage the memory that they own.
 #[unstable(feature = "core", reason = "recently added to this module")]
-pub struct Unique<T: ?Sized>(pub *mut T);
+pub struct Unique<T: ?Sized> {
+    /// The wrapped `*mut T`.
+    pub ptr: *mut T,
+    _own: marker::PhantomData<T>,
+}
 
 /// `Unique` pointers are `Send` if `T` is `Send` because the data they
 /// reference is unaliased. Note that this aliasing invariant is
@@ -550,6 +554,13 @@ impl<T> Unique<T> {
     #[unstable(feature = "core",
                reason = "recently added to this module")]
     pub unsafe fn offset(self, offset: int) -> *mut T {
-        self.0.offset(offset)
+        self.ptr.offset(offset)
     }
 }
+
+/// Creates a `Unique` wrapped around `ptr`, taking ownership of the
+/// data referenced by `ptr`.
+#[allow(non_snake_case)]
+pub fn Unique<T: ?Sized>(ptr: *mut T) -> Unique<T> {
+    Unique { ptr: ptr, _own: marker::PhantomData }
+}
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index 459addb09fd..cf1df4ac423 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -41,7 +41,6 @@ use cmp::Ordering::{Less, Equal, Greater};
 use cmp;
 use default::Default;
 use iter::*;
-use num::Int;
 use ops::{FnMut, self, Index};
 use ops::RangeFull;
 use option::Option;
@@ -1179,8 +1178,42 @@ impl<'a, T> Iterator for Windows<'a, T> {
         if self.size > self.v.len() {
             (0, Some(0))
         } else {
-            let x = self.v.len() - self.size;
-            (x.saturating_add(1), x.checked_add(1))
+            let size = self.v.len() - self.size + 1;
+            (size, Some(size))
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> DoubleEndedIterator for Windows<'a, T> {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T]> {
+        if self.size > self.v.len() {
+            None
+        } else {
+            let ret = Some(&self.v[self.v.len()-self.size..]);
+            self.v = &self.v[..self.v.len()-1];
+            ret
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, T> ExactSizeIterator for Windows<'a, T> {}
+
+#[unstable(feature = "core", reason = "trait is experimental")]
+impl<'a, T> RandomAccessIterator for Windows<'a, T> {
+    #[inline]
+    fn indexable(&self) -> uint {
+        self.size_hint().0
+    }
+
+    #[inline]
+    fn idx(&mut self, index: uint) -> Option<&'a [T]> {
+        if index + self.size > self.v.len() {
+            None
+        } else {
+            Some(&self.v[index .. index+self.size])
         }
     }
 }
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 013b7f27839..747152a8244 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -34,7 +34,7 @@ use ptr::PtrExt;
 use raw::{Repr, Slice};
 use result::Result::{self, Ok, Err};
 use slice::{self, SliceExt};
-use uint;
+use usize;
 
 macro_rules! delegate_iter {
     (exact $te:ty : $ti:ty) => {
@@ -783,7 +783,7 @@ impl TwoWaySearcher {
                 byteset: byteset,
 
                 position: 0,
-                memory: uint::MAX // Dummy value to signify that the period is long
+                memory: usize::MAX // Dummy value to signify that the period is long
             }
         }
     }
@@ -911,7 +911,7 @@ impl Searcher {
             Naive(NaiveSearcher::new())
         } else {
             let searcher = TwoWaySearcher::new(needle);
-            if searcher.memory == uint::MAX { // If the period is long
+            if searcher.memory == usize::MAX { // If the period is long
                 TwoWayLong(searcher)
             } else {
                 TwoWay(searcher)
diff --git a/src/libcoretest/any.rs b/src/libcoretest/any.rs
index 5ad3833a5ef..2156a99c332 100644
--- a/src/libcoretest/any.rs
+++ b/src/libcoretest/any.rs
@@ -18,11 +18,11 @@ static TEST: &'static str = "Test";
 
 #[test]
 fn any_referenced() {
-    let (a, b, c) = (&5u as &Any, &TEST as &Any, &Test as &Any);
+    let (a, b, c) = (&5 as &Any, &TEST as &Any, &Test as &Any);
 
-    assert!(a.is::<uint>());
-    assert!(!b.is::<uint>());
-    assert!(!c.is::<uint>());
+    assert!(a.is::<i32>());
+    assert!(!b.is::<i32>());
+    assert!(!c.is::<i32>());
 
     assert!(!a.is::<&'static str>());
     assert!(b.is::<&'static str>());
@@ -35,7 +35,7 @@ fn any_referenced() {
 
 #[test]
 fn any_owning() {
-    let (a, b, c) = (box 5u as Box<Any>, box TEST as Box<Any>, box Test as Box<Any>);
+    let (a, b, c) = (box 5us as Box<Any>, box TEST as Box<Any>, box Test as Box<Any>);
 
     assert!(a.is::<uint>());
     assert!(!b.is::<uint>());
@@ -52,7 +52,7 @@ fn any_owning() {
 
 #[test]
 fn any_downcast_ref() {
-    let a = &5u as &Any;
+    let a = &5us as &Any;
 
     match a.downcast_ref::<uint>() {
         Some(&5) => {}
@@ -67,8 +67,8 @@ fn any_downcast_ref() {
 
 #[test]
 fn any_downcast_mut() {
-    let mut a = 5u;
-    let mut b = box 7u;
+    let mut a = 5us;
+    let mut b = box 7us;
 
     let a_r = &mut a as &mut Any;
     let tmp: &mut uint = &mut *b;
@@ -76,7 +76,7 @@ fn any_downcast_mut() {
 
     match a_r.downcast_mut::<uint>() {
         Some(x) => {
-            assert_eq!(*x, 5u);
+            assert_eq!(*x, 5);
             *x = 612;
         }
         x => panic!("Unexpected value {:?}", x)
@@ -84,7 +84,7 @@ fn any_downcast_mut() {
 
     match b_r.downcast_mut::<uint>() {
         Some(x) => {
-            assert_eq!(*x, 7u);
+            assert_eq!(*x, 7);
             *x = 413;
         }
         x => panic!("Unexpected value {:?}", x)
@@ -113,7 +113,7 @@ fn any_downcast_mut() {
 
 #[test]
 fn any_fixed_vec() {
-    let test = [0u; 8];
+    let test = [0us; 8];
     let test = &test as &Any;
     assert!(test.is::<[uint; 8]>());
     assert!(!test.is::<[uint; 10]>());
diff --git a/src/libcoretest/cell.rs b/src/libcoretest/cell.rs
index 8939bd61fe4..317ef3a5701 100644
--- a/src/libcoretest/cell.rs
+++ b/src/libcoretest/cell.rs
@@ -134,21 +134,21 @@ fn clone_ref_updates_flag() {
 
 #[test]
 fn as_unsafe_cell() {
-    let c1: Cell<uint> = Cell::new(0u);
-    c1.set(1u);
-    assert_eq!(1u, unsafe { *c1.as_unsafe_cell().get() });
+    let c1: Cell<uint> = Cell::new(0);
+    c1.set(1);
+    assert_eq!(1, unsafe { *c1.as_unsafe_cell().get() });
 
-    let c2: Cell<uint> = Cell::new(0u);
-    unsafe { *c2.as_unsafe_cell().get() = 1u; }
-    assert_eq!(1u, c2.get());
+    let c2: Cell<uint> = Cell::new(0);
+    unsafe { *c2.as_unsafe_cell().get() = 1; }
+    assert_eq!(1, c2.get());
 
-    let r1: RefCell<uint> = RefCell::new(0u);
-    *r1.borrow_mut() = 1u;
-    assert_eq!(1u, unsafe { *r1.as_unsafe_cell().get() });
+    let r1: RefCell<uint> = RefCell::new(0);
+    *r1.borrow_mut() = 1;
+    assert_eq!(1, unsafe { *r1.as_unsafe_cell().get() });
 
-    let r2: RefCell<uint> = RefCell::new(0u);
-    unsafe { *r2.as_unsafe_cell().get() = 1u; }
-    assert_eq!(1u, *r2.borrow());
+    let r2: RefCell<uint> = RefCell::new(0);
+    unsafe { *r2.as_unsafe_cell().get() = 1; }
+    assert_eq!(1, *r2.borrow());
 }
 
 #[test]
diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs
index 9ba9c2c4a9c..32dc6440b13 100644
--- a/src/libcoretest/char.rs
+++ b/src/libcoretest/char.rs
@@ -41,18 +41,18 @@ fn test_is_whitespace() {
 
 #[test]
 fn test_to_digit() {
-    assert_eq!('0'.to_digit(10u), Some(0u));
-    assert_eq!('1'.to_digit(2u), Some(1u));
-    assert_eq!('2'.to_digit(3u), Some(2u));
-    assert_eq!('9'.to_digit(10u), Some(9u));
-    assert_eq!('a'.to_digit(16u), Some(10u));
-    assert_eq!('A'.to_digit(16u), Some(10u));
-    assert_eq!('b'.to_digit(16u), Some(11u));
-    assert_eq!('B'.to_digit(16u), Some(11u));
-    assert_eq!('z'.to_digit(36u), Some(35u));
-    assert_eq!('Z'.to_digit(36u), Some(35u));
-    assert_eq!(' '.to_digit(10u), None);
-    assert_eq!('$'.to_digit(36u), None);
+    assert_eq!('0'.to_digit(10), Some(0));
+    assert_eq!('1'.to_digit(2), Some(1));
+    assert_eq!('2'.to_digit(3), Some(2));
+    assert_eq!('9'.to_digit(10), Some(9));
+    assert_eq!('a'.to_digit(16), Some(10));
+    assert_eq!('A'.to_digit(16), Some(10));
+    assert_eq!('b'.to_digit(16), Some(11));
+    assert_eq!('B'.to_digit(16), Some(11));
+    assert_eq!('z'.to_digit(36), Some(35));
+    assert_eq!('Z'.to_digit(36), Some(35));
+    assert_eq!(' '.to_digit(10), None);
+    assert_eq!('$'.to_digit(36), None);
 }
 
 #[test]
diff --git a/src/libcoretest/iter.rs b/src/libcoretest/iter.rs
index 3f8e330b332..7eb0fb97bed 100644
--- a/src/libcoretest/iter.rs
+++ b/src/libcoretest/iter.rs
@@ -79,8 +79,8 @@ fn test_counter_from_iter() {
 
 #[test]
 fn test_iterator_chain() {
-    let xs = [0u, 1, 2, 3, 4, 5];
-    let ys = [30u, 40, 50, 60];
+    let xs = [0, 1, 2, 3, 4, 5];
+    let ys = [30, 40, 50, 60];
     let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
     let mut it = xs.iter().chain(ys.iter());
     let mut i = 0;
@@ -90,7 +90,7 @@ fn test_iterator_chain() {
     }
     assert_eq!(i, expected.len());
 
-    let ys = count(30u, 10).take(4);
+    let ys = count(30, 10).take(4);
     let mut it = xs.iter().map(|&x| x).chain(ys);
     let mut i = 0;
     for x in it {
@@ -102,14 +102,14 @@ fn test_iterator_chain() {
 
 #[test]
 fn test_filter_map() {
-    let it = count(0u, 1u).take(10)
+    let it = count(0, 1).take(10)
         .filter_map(|x| if x % 2 == 0 { Some(x*x) } else { None });
     assert!(it.collect::<Vec<uint>>() == vec![0*0, 2*2, 4*4, 6*6, 8*8]);
 }
 
 #[test]
 fn test_iterator_enumerate() {
-    let xs = [0u, 1, 2, 3, 4, 5];
+    let xs = [0, 1, 2, 3, 4, 5];
     let mut it = xs.iter().enumerate();
     for (i, &x) in it {
         assert_eq!(i, x);
@@ -118,7 +118,7 @@ fn test_iterator_enumerate() {
 
 #[test]
 fn test_iterator_peekable() {
-    let xs = vec![0u, 1, 2, 3, 4, 5];
+    let xs = vec![0, 1, 2, 3, 4, 5];
     let mut it = xs.iter().map(|&x|x).peekable();
 
     assert_eq!(it.len(), 6);
@@ -150,9 +150,9 @@ fn test_iterator_peekable() {
 
 #[test]
 fn test_iterator_take_while() {
-    let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19];
-    let ys = [0u, 1, 2, 3, 5, 13];
-    let mut it = xs.iter().take_while(|&x| *x < 15u);
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
+    let ys = [0, 1, 2, 3, 5, 13];
+    let mut it = xs.iter().take_while(|&x| *x < 15);
     let mut i = 0;
     for x in it {
         assert_eq!(*x, ys[i]);
@@ -163,9 +163,9 @@ fn test_iterator_take_while() {
 
 #[test]
 fn test_iterator_skip_while() {
-    let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19];
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
     let ys = [15, 16, 17, 19];
-    let mut it = xs.iter().skip_while(|&x| *x < 15u);
+    let mut it = xs.iter().skip_while(|&x| *x < 15);
     let mut i = 0;
     for x in it {
         assert_eq!(*x, ys[i]);
@@ -176,7 +176,7 @@ fn test_iterator_skip_while() {
 
 #[test]
 fn test_iterator_skip() {
-    let xs = [0u, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19, 20, 30];
     let ys = [13, 15, 16, 17, 19, 20, 30];
     let mut it = xs.iter().skip(5);
     let mut i = 0;
@@ -191,8 +191,8 @@ fn test_iterator_skip() {
 
 #[test]
 fn test_iterator_take() {
-    let xs = [0us, 1, 2, 3, 5, 13, 15, 16, 17, 19];
-    let ys = [0us, 1, 2, 3, 5];
+    let xs = [0, 1, 2, 3, 5, 13, 15, 16, 17, 19];
+    let ys = [0, 1, 2, 3, 5];
     let mut it = xs.iter().take(5);
     let mut i = 0;
     assert_eq!(it.len(), 5);
@@ -207,8 +207,8 @@ fn test_iterator_take() {
 
 #[test]
 fn test_iterator_take_short() {
-    let xs = [0us, 1, 2, 3];
-    let ys = [0us, 1, 2, 3];
+    let xs = [0, 1, 2, 3];
+    let ys = [0, 1, 2, 3];
     let mut it = xs.iter().take(5);
     let mut i = 0;
     assert_eq!(it.len(), 4);
@@ -228,7 +228,7 @@ fn test_iterator_scan() {
         *old += *new as int;
         Some(*old as f64)
     }
-    let xs = [0u, 1, 2, 3, 4];
+    let xs = [0, 1, 2, 3, 4];
     let ys = [0f64, 1.0, 3.0, 6.0, 10.0];
 
     let mut it = xs.iter().scan(0, add);
@@ -242,8 +242,8 @@ fn test_iterator_scan() {
 
 #[test]
 fn test_iterator_flat_map() {
-    let xs = [0u, 3, 6];
-    let ys = [0u, 1, 2, 3, 4, 5, 6, 7, 8];
+    let xs = [0, 3, 6];
+    let ys = [0, 1, 2, 3, 4, 5, 6, 7, 8];
     let mut it = xs.iter().flat_map(|&x| count(x, 1).take(3));
     let mut i = 0;
     for x in it {
@@ -255,8 +255,8 @@ fn test_iterator_flat_map() {
 
 #[test]
 fn test_inspect() {
-    let xs = [1u, 2, 3, 4];
-    let mut n = 0u;
+    let xs = [1, 2, 3, 4];
+    let mut n = 0;
 
     let ys = xs.iter()
                .map(|&x| x)
@@ -291,13 +291,13 @@ fn test_unfoldr() {
 #[test]
 fn test_cycle() {
     let cycle_len = 3;
-    let it = count(0u, 1).take(cycle_len).cycle();
+    let it = count(0, 1).take(cycle_len).cycle();
     assert_eq!(it.size_hint(), (uint::MAX, None));
     for (i, x) in it.take(100).enumerate() {
         assert_eq!(i % cycle_len, x);
     }
 
-    let mut it = count(0u, 1).take(0).cycle();
+    let mut it = count(0, 1).take(0).cycle();
     assert_eq!(it.size_hint(), (0, Some(0)));
     assert_eq!(it.next(), None);
 }
@@ -305,7 +305,7 @@ fn test_cycle() {
 #[test]
 fn test_iterator_nth() {
     let v: &[_] = &[0, 1, 2, 3, 4];
-    for i in 0u..v.len() {
+    for i in 0..v.len() {
         assert_eq!(v.iter().nth(i).unwrap(), &v[i]);
     }
     assert_eq!(v.iter().nth(v.len()), None);
@@ -574,7 +574,7 @@ fn test_rposition() {
     fn g(xy: &(int, char)) -> bool { let (_x, y) = *xy; y == 'd' }
     let v = [(0, 'a'), (1, 'b'), (2, 'c'), (3, 'b')];
 
-    assert_eq!(v.iter().rposition(f), Some(3u));
+    assert_eq!(v.iter().rposition(f), Some(3));
     assert!(v.iter().rposition(g).is_none());
 }
 
@@ -601,7 +601,7 @@ fn check_randacc_iter<A, T>(a: T, len: uint) where
 {
     let mut b = a.clone();
     assert_eq!(len, b.indexable());
-    let mut n = 0u;
+    let mut n = 0;
     for (i, elt) in a.enumerate() {
         assert!(Some(elt) == b.idx(i));
         n += 1;
@@ -618,8 +618,8 @@ fn check_randacc_iter<A, T>(a: T, len: uint) where
 
 #[test]
 fn test_double_ended_flat_map() {
-    let u = [0u,1];
-    let v = [5u,6,7,8];
+    let u = [0,1];
+    let v = [5,6,7,8];
     let mut it = u.iter().flat_map(|x| v[*x..v.len()].iter());
     assert_eq!(it.next_back().unwrap(), &8);
     assert_eq!(it.next().unwrap(),      &5);
@@ -849,30 +849,30 @@ fn test_min_max_result() {
 
 #[test]
 fn test_iterate() {
-    let mut it = iterate(1u, |x| x * 2);
-    assert_eq!(it.next(), Some(1u));
-    assert_eq!(it.next(), Some(2u));
-    assert_eq!(it.next(), Some(4u));
-    assert_eq!(it.next(), Some(8u));
+    let mut it = iterate(1, |x| x * 2);
+    assert_eq!(it.next(), Some(1));
+    assert_eq!(it.next(), Some(2));
+    assert_eq!(it.next(), Some(4));
+    assert_eq!(it.next(), Some(8));
 }
 
 #[test]
 fn test_repeat() {
-    let mut it = repeat(42u);
-    assert_eq!(it.next(), Some(42u));
-    assert_eq!(it.next(), Some(42u));
-    assert_eq!(it.next(), Some(42u));
+    let mut it = repeat(42);
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), Some(42));
+    assert_eq!(it.next(), Some(42));
 }
 
 #[test]
 fn test_fuse() {
-    let mut it = 0us..3;
+    let mut it = 0..3;
     assert_eq!(it.len(), 3);
-    assert_eq!(it.next(), Some(0us));
+    assert_eq!(it.next(), Some(0));
     assert_eq!(it.len(), 2);
-    assert_eq!(it.next(), Some(1us));
+    assert_eq!(it.next(), Some(1));
     assert_eq!(it.len(), 1);
-    assert_eq!(it.next(), Some(2us));
+    assert_eq!(it.next(), Some(2));
     assert_eq!(it.len(), 0);
     assert_eq!(it.next(), None);
     assert_eq!(it.len(), 0);
@@ -884,7 +884,7 @@ fn test_fuse() {
 
 #[bench]
 fn bench_rposition(b: &mut Bencher) {
-    let it: Vec<uint> = (0u..300).collect();
+    let it: Vec<uint> = (0..300).collect();
     b.iter(|| {
         it.iter().rposition(|&x| x <= 150);
     });
@@ -893,7 +893,7 @@ fn bench_rposition(b: &mut Bencher) {
 #[bench]
 fn bench_skip_while(b: &mut Bencher) {
     b.iter(|| {
-        let it = 0u..100;
+        let it = 0..100;
         let mut sum = 0;
         it.skip_while(|&x| { sum += x; sum < 4000 }).all(|_| true);
     });
@@ -901,10 +901,10 @@ fn bench_skip_while(b: &mut Bencher) {
 
 #[bench]
 fn bench_multiple_take(b: &mut Bencher) {
-    let mut it = (0u..42).cycle();
+    let mut it = (0..42).cycle();
     b.iter(|| {
         let n = it.next().unwrap();
-        for _ in 0u..n {
+        for _ in 0..n {
             it.clone().take(it.next().unwrap()).all(|_| true);
         }
     });
diff --git a/src/libcoretest/mem.rs b/src/libcoretest/mem.rs
index fd9dc696bdf..421ce76caaf 100644
--- a/src/libcoretest/mem.rs
+++ b/src/libcoretest/mem.rs
@@ -12,24 +12,24 @@ use test::Bencher;
 
 #[test]
 fn size_of_basic() {
-    assert_eq!(size_of::<u8>(), 1u);
-    assert_eq!(size_of::<u16>(), 2u);
-    assert_eq!(size_of::<u32>(), 4u);
-    assert_eq!(size_of::<u64>(), 8u);
+    assert_eq!(size_of::<u8>(), 1);
+    assert_eq!(size_of::<u16>(), 2);
+    assert_eq!(size_of::<u32>(), 4);
+    assert_eq!(size_of::<u64>(), 8);
 }
 
 #[test]
 #[cfg(target_pointer_width = "32")]
 fn size_of_32() {
-    assert_eq!(size_of::<uint>(), 4u);
-    assert_eq!(size_of::<*const uint>(), 4u);
+    assert_eq!(size_of::<uint>(), 4);
+    assert_eq!(size_of::<*const uint>(), 4);
 }
 
 #[test]
 #[cfg(target_pointer_width = "64")]
 fn size_of_64() {
-    assert_eq!(size_of::<uint>(), 8u);
-    assert_eq!(size_of::<*const uint>(), 8u);
+    assert_eq!(size_of::<uint>(), 8);
+    assert_eq!(size_of::<*const uint>(), 8);
 }
 
 #[test]
@@ -42,30 +42,30 @@ fn size_of_val_basic() {
 
 #[test]
 fn align_of_basic() {
-    assert_eq!(align_of::<u8>(), 1u);
-    assert_eq!(align_of::<u16>(), 2u);
-    assert_eq!(align_of::<u32>(), 4u);
+    assert_eq!(align_of::<u8>(), 1);
+    assert_eq!(align_of::<u16>(), 2);
+    assert_eq!(align_of::<u32>(), 4);
 }
 
 #[test]
 #[cfg(target_pointer_width = "32")]
 fn align_of_32() {
-    assert_eq!(align_of::<uint>(), 4u);
-    assert_eq!(align_of::<*const uint>(), 4u);
+    assert_eq!(align_of::<uint>(), 4);
+    assert_eq!(align_of::<*const uint>(), 4);
 }
 
 #[test]
 #[cfg(target_pointer_width = "64")]
 fn align_of_64() {
-    assert_eq!(align_of::<uint>(), 8u);
-    assert_eq!(align_of::<*const uint>(), 8u);
+    assert_eq!(align_of::<uint>(), 8);
+    assert_eq!(align_of::<*const uint>(), 8);
 }
 
 #[test]
 fn align_of_val_basic() {
-    assert_eq!(align_of_val(&1u8), 1u);
-    assert_eq!(align_of_val(&1u16), 2u);
-    assert_eq!(align_of_val(&1u32), 4u);
+    assert_eq!(align_of_val(&1u8), 1);
+    assert_eq!(align_of_val(&1u16), 2);
+    assert_eq!(align_of_val(&1u32), 4);
 }
 
 #[test]
@@ -87,7 +87,7 @@ fn test_replace() {
 
 #[test]
 fn test_transmute_copy() {
-    assert_eq!(1u, unsafe { transmute_copy(&1) });
+    assert_eq!(1, unsafe { transmute_copy(&1) });
 }
 
 #[test]
diff --git a/src/libcoretest/num/uint_macros.rs b/src/libcoretest/num/uint_macros.rs
index 04d8fb15cf5..5c6efc857f1 100644
--- a/src/libcoretest/num/uint_macros.rs
+++ b/src/libcoretest/num/uint_macros.rs
@@ -33,8 +33,8 @@ mod tests {
         assert!(0b1110 as $T == (0b1100 as $T).bitor(0b1010 as $T));
         assert!(0b1000 as $T == (0b1100 as $T).bitand(0b1010 as $T));
         assert!(0b0110 as $T == (0b1100 as $T).bitxor(0b1010 as $T));
-        assert!(0b1110 as $T == (0b0111 as $T).shl(1u));
-        assert!(0b0111 as $T == (0b1110 as $T).shr(1u));
+        assert!(0b1110 as $T == (0b0111 as $T).shl(1));
+        assert!(0b0111 as $T == (0b1110 as $T).shr(1));
         assert!(MAX - (0b1011 as $T) == (0b1011 as $T).not());
     }
 
@@ -119,8 +119,8 @@ mod tests {
 
     #[test]
     fn test_unsigned_checked_div() {
-        assert!(10u.checked_div(2) == Some(5));
-        assert!(5u.checked_div(0) == None);
+        assert!(10.checked_div(2) == Some(5));
+        assert!(5.checked_div(0) == None);
     }
 }
 
diff --git a/src/libcoretest/ops.rs b/src/libcoretest/ops.rs
index 3da572f65a6..0183e6a93cf 100644
--- a/src/libcoretest/ops.rs
+++ b/src/libcoretest/ops.rs
@@ -33,11 +33,11 @@ fn alloc_obj_with_dtor(b: &mut Bencher) {
 
 #[test]
 fn test_range() {
-    let r = Range { start: 2u, end: 10 };
-    let mut count = 0u;
+    let r = Range { start: 2, end: 10 };
+    let mut count = 0;
     for (i, ri) in r.enumerate() {
         assert!(ri == i + 2);
-        assert!(ri >= 2u && ri < 10u);
+        assert!(ri >= 2 && ri < 10);
         count += 1;
     }
     assert!(count == 8);
@@ -45,11 +45,11 @@ fn test_range() {
 
 #[test]
 fn test_range_from() {
-    let r = RangeFrom { start: 2u };
-    let mut count = 0u;
+    let r = RangeFrom { start: 2 };
+    let mut count = 0;
     for (i, ri) in r.take(10).enumerate() {
         assert!(ri == i + 2);
-        assert!(ri >= 2u && ri < 12u);
+        assert!(ri >= 2 && ri < 12);
         count += 1;
     }
     assert!(count == 10);
@@ -58,7 +58,7 @@ fn test_range_from() {
 #[test]
 fn test_range_to() {
     // Not much to test.
-    let _ = RangeTo { end: 42u };
+    let _ = RangeTo { end: 42 };
 }
 
 #[test]
diff --git a/src/libcoretest/ptr.rs b/src/libcoretest/ptr.rs
index 2365b907b3f..9c2e242c105 100644
--- a/src/libcoretest/ptr.rs
+++ b/src/libcoretest/ptr.rs
@@ -46,7 +46,7 @@ fn test() {
                  v1[1] == 32001u16 &&
                  v1[2] == 0u16));
         copy_memory(v1.as_mut_ptr().offset(2),
-                    v0.as_ptr(), 1u);
+                    v0.as_ptr(), 1);
         assert!((v1[0] == 32002u16 &&
                  v1[1] == 32001u16 &&
                  v1[2] == 32000u16));
@@ -172,7 +172,7 @@ fn test_set_memory() {
 fn test_unsized_unique() {
     let xs: &mut [_] = &mut [1, 2, 3];
     let ptr = Unique(xs as *mut [_]);
-    let ys = unsafe { &mut *ptr.0 };
+    let ys = unsafe { &mut *ptr.ptr };
     let zs: &mut [_] = &mut [1, 2, 3];
     assert!(ys == zs);
 }
diff --git a/src/libcoretest/tuple.rs b/src/libcoretest/tuple.rs
index 57844f5995f..4fe5e0a740b 100644
--- a/src/libcoretest/tuple.rs
+++ b/src/libcoretest/tuple.rs
@@ -19,7 +19,7 @@ fn test_clone() {
 
 #[test]
 fn test_tuple_cmp() {
-    let (small, big) = ((1u, 2u, 3u), (3u, 2u, 1u));
+    let (small, big) = ((1, 2, 3), (3, 2, 1));
 
     let nan = 0.0f64/0.0;
 
diff --git a/src/libflate/lib.rs b/src/libflate/lib.rs
index a81b8777af4..ff6400a11df 100644
--- a/src/libflate/lib.rs
+++ b/src/libflate/lib.rs
@@ -45,13 +45,13 @@ pub struct Bytes {
 impl Deref for Bytes {
     type Target = [u8];
     fn deref(&self) -> &[u8] {
-        unsafe { slice::from_raw_parts_mut(self.ptr.0, self.len) }
+        unsafe { slice::from_raw_parts_mut(self.ptr.ptr, self.len) }
     }
 }
 
 impl Drop for Bytes {
     fn drop(&mut self) {
-        unsafe { libc::free(self.ptr.0 as *mut _); }
+        unsafe { libc::free(self.ptr.ptr as *mut _); }
     }
 }
 
diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs
index 94e4012c5ee..1dec23059e5 100644
--- a/src/liblibc/lib.rs
+++ b/src/liblibc/lib.rs
@@ -2457,6 +2457,7 @@ pub mod consts {
             pub const SHUT_RDWR: c_int = 2;
         }
         pub mod extra {
+            use SOCKET;
             use types::os::arch::c95::{c_int, c_long};
             use types::os::arch::extra::{WORD, DWORD, BOOL, HANDLE};
 
@@ -2663,7 +2664,7 @@ pub mod consts {
 
             pub const MAX_PROTOCOL_CHAIN: DWORD = 7;
             pub const WSAPROTOCOL_LEN: DWORD = 255;
-            pub const INVALID_SOCKET: DWORD = !0;
+            pub const INVALID_SOCKET: SOCKET = !0;
 
             pub const DETACHED_PROCESS: DWORD = 0x00000008;
             pub const CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200;
diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs
index 15f50188919..1fedf49738c 100644
--- a/src/liblog/lib.rs
+++ b/src/liblog/lib.rs
@@ -397,7 +397,7 @@ fn enabled(level: u32,
 /// This is not threadsafe at all, so initialization is performed through a
 /// `Once` primitive (and this function is called from that primitive).
 fn init() {
-    let (mut directives, filter) = match env::var_string("RUST_LOG") {
+    let (mut directives, filter) = match env::var("RUST_LOG") {
         Ok(spec) => directive::parse_logging_spec(&spec[]),
         Err(..) => (Vec::new(), None),
     };
diff --git a/src/librbml/lib.rs b/src/librbml/lib.rs
index e204a2a6595..20af4dadfca 100644
--- a/src/librbml/lib.rs
+++ b/src/librbml/lib.rs
@@ -130,7 +130,7 @@ impl fmt::Display for Error {
 pub mod reader {
     use std::char;
 
-    use std::int;
+    use std::isize;
     use std::old_io::extensions::u64_from_be_bytes;
     use std::mem::transmute;
     use std::num::Int;
@@ -440,7 +440,7 @@ pub mod reader {
         fn read_u8 (&mut self) -> DecodeResult<u8 > { Ok(doc_as_u8 (try!(self.next_doc(EsU8 )))) }
         fn read_uint(&mut self) -> DecodeResult<uint> {
             let v = doc_as_u64(try!(self.next_doc(EsUint)));
-            if v > (::std::uint::MAX as u64) {
+            if v > (::std::usize::MAX as u64) {
                 Err(IntTooBig(v as uint))
             } else {
                 Ok(v as uint)
@@ -461,7 +461,7 @@ pub mod reader {
         }
         fn read_int(&mut self) -> DecodeResult<int> {
             let v = doc_as_u64(try!(self.next_doc(EsInt))) as i64;
-            if v > (int::MAX as i64) || v < (int::MIN as i64) {
+            if v > (isize::MAX as i64) || v < (isize::MIN as i64) {
                 debug!("FIXME \\#6122: Removing this makes this function miscompile");
                 Err(IntTooBig(v as uint))
             } else {
@@ -738,7 +738,6 @@ pub mod writer {
         })
     }
 
-    // FIXME (#2741): Provide a function to write the standard rbml header.
     impl<'a, W: Writer + Seek> Encoder<'a, W> {
         pub fn new(w: &'a mut W) -> Encoder<'a, W> {
             Encoder {
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 638ecf4572d..a415ff3ed71 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -1768,6 +1768,11 @@ impl LintPass for Stability {
         stability::check_expr(cx.tcx, e,
                               &mut |id, sp, stab| self.lint(cx, id, sp, stab));
     }
+
+    fn check_path(&mut self, cx: &Context, path: &ast::Path, id: ast::NodeId) {
+        stability::check_path(cx.tcx, path, id,
+                              &mut |id, sp, stab| self.lint(cx, id, sp, stab));
+    }
 }
 
 declare_lint! {
@@ -2080,12 +2085,26 @@ declare_lint! {
     "functions marked #[no_mangle] should be exported"
 }
 
+declare_lint! {
+    PRIVATE_NO_MANGLE_STATICS,
+    Warn,
+    "statics marked #[no_mangle] should be exported"
+}
+
+declare_lint! {
+    NO_MANGLE_CONST_ITEMS,
+    Deny,
+    "const items will not have their symbols exported"
+}
+
 #[derive(Copy)]
-pub struct PrivateNoMangleFns;
+pub struct InvalidNoMangleItems;
 
-impl LintPass for PrivateNoMangleFns {
+impl LintPass for InvalidNoMangleItems {
     fn get_lints(&self) -> LintArray {
-        lint_array!(PRIVATE_NO_MANGLE_FNS)
+        lint_array!(PRIVATE_NO_MANGLE_FNS,
+                    PRIVATE_NO_MANGLE_STATICS,
+                    NO_MANGLE_CONST_ITEMS)
     }
 
     fn check_item(&mut self, cx: &Context, it: &ast::Item) {
@@ -2098,6 +2117,23 @@ impl LintPass for PrivateNoMangleFns {
                     cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg);
                 }
             },
+            ast::ItemStatic(..) => {
+                if attr::contains_name(it.attrs.as_slice(), "no_mangle") &&
+                       !cx.exported_items.contains(&it.id) {
+                    let msg = format!("static {} is marked #[no_mangle], but not exported",
+                                      it.ident);
+                    cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, msg.as_slice());
+                }
+            },
+            ast::ItemConst(..) => {
+                if attr::contains_name(it.attrs.as_slice(), "no_mangle") {
+                    // Const items do not refer to a particular location in memory, and therefore
+                    // don't have anything to attach a symbol to
+                    let msg = "const items should never be #[no_mangle], consider instead using \
+                        `pub static`";
+                    cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg);
+                }
+            }
             _ => {},
         }
     }
diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs
index 18628f6903f..616af79326d 100644
--- a/src/librustc/lint/context.rs
+++ b/src/librustc/lint/context.rs
@@ -213,7 +213,7 @@ impl LintStore {
                      UnstableFeatures,
                      Stability,
                      UnconditionalRecursion,
-                     PrivateNoMangleFns,
+                     InvalidNoMangleItems,
         );
 
         add_builtin_with_new!(sess,
diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs
index f6cd0e5add2..30d7ec8be63 100644
--- a/src/librustc/metadata/creader.rs
+++ b/src/librustc/metadata/creader.rs
@@ -462,7 +462,7 @@ impl<'a> CrateReader<'a> {
                      name: s.to_string(),
                      ident: s.to_string(),
                      id: ast::DUMMY_NODE_ID,
-                     should_link: true,
+                     should_link: false,
                  }, sp)
             }
         };
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index b151856e309..7eeb0589118 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -233,6 +233,14 @@ pub fn get_trait_def<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId) -> ty::TraitDe
     decoder::get_trait_def(&*cdata, def.node, tcx)
 }
 
+pub fn get_predicates<'tcx>(tcx: &ty::ctxt<'tcx>, def: ast::DefId)
+                            -> ty::GenericPredicates<'tcx>
+{
+    let cstore = &tcx.sess.cstore;
+    let cdata = cstore.get_crate_data(def.krate);
+    decoder::get_predicates(&*cdata, def.node, tcx)
+}
+
 pub fn get_field_type<'tcx>(tcx: &ty::ctxt<'tcx>, class_id: ast::DefId,
                             def: ast::DefId) -> ty::TypeScheme<'tcx> {
     let cstore = &tcx.sess.cstore;
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index 3a70490771e..e5576de6e84 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -417,16 +417,22 @@ pub fn get_trait_def<'tcx>(cdata: Cmd,
     }
 }
 
-pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
-    -> ty::TypeScheme<'tcx> {
-
-    let item = lookup_item(id, cdata.data());
+pub fn get_predicates<'tcx>(cdata: Cmd,
+                            item_id: ast::NodeId,
+                            tcx: &ty::ctxt<'tcx>)
+                            -> ty::GenericPredicates<'tcx>
+{
+    let item_doc = lookup_item(item_id, cdata.data());
+    doc_predicates(item_doc, tcx, cdata, tag_item_generics)
+}
 
-    let t = item_type(ast::DefId { krate: cdata.cnum, node: id }, item, tcx,
+pub fn get_type<'tcx>(cdata: Cmd, id: ast::NodeId, tcx: &ty::ctxt<'tcx>)
+                      -> ty::TypeScheme<'tcx>
+{
+    let item_doc = lookup_item(id, cdata.data());
+    let t = item_type(ast::DefId { krate: cdata.cnum, node: id }, item_doc, tcx,
                       cdata);
-
-    let generics = doc_generics(item, tcx, cdata, tag_item_generics);
-
+    let generics = doc_generics(item_doc, tcx, cdata, tag_item_generics);
     ty::TypeScheme {
         generics: generics,
         ty: t
@@ -882,14 +888,15 @@ pub fn get_impl_or_trait_item<'tcx>(intr: Rc<IdentInterner>,
 
     match item_sort(method_doc) {
         'r' | 'p' => {
-            let generics = doc_generics(method_doc, tcx, cdata,
-                                        tag_method_ty_generics);
+            let generics = doc_generics(method_doc, tcx, cdata, tag_method_ty_generics);
+            let predicates = doc_predicates(method_doc, tcx, cdata, tag_method_ty_generics);
             let fty = doc_method_fty(method_doc, tcx, cdata);
             let explicit_self = get_explicit_self(method_doc);
             let provided_source = get_provided_source(method_doc, cdata);
 
             ty::MethodTraitItem(Rc::new(ty::Method::new(name,
                                                         generics,
+                                                        predicates,
                                                         fty,
                                                         explicit_self,
                                                         vis,
@@ -1520,6 +1527,17 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc,
         true
     });
 
+    ty::Generics { types: types, regions: regions }
+}
+
+fn doc_predicates<'tcx>(base_doc: rbml::Doc,
+                        tcx: &ty::ctxt<'tcx>,
+                        cdata: Cmd,
+                        tag: uint)
+                        -> ty::GenericPredicates<'tcx>
+{
+    let doc = reader::get_doc(base_doc, tag);
+
     let mut predicates = subst::VecPerParamSpace::empty();
     reader::tagged_docs(doc, tag_predicate, |predicate_doc| {
         let space_doc = reader::get_doc(predicate_doc, tag_predicate_space);
@@ -1533,7 +1551,7 @@ fn doc_generics<'tcx>(base_doc: rbml::Doc,
         true
     });
 
-    ty::Generics { types: types, regions: regions, predicates: predicates }
+    ty::GenericPredicates { predicates: predicates }
 }
 
 pub fn is_associated_type(cdata: Cmd, id: ast::NodeId) -> bool {
diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs
index ef0c3fbb252..3123fa31abd 100644
--- a/src/librustc/metadata/encoder.rs
+++ b/src/librustc/metadata/encoder.rs
@@ -139,11 +139,21 @@ fn encode_item_variances(rbml_w: &mut Encoder,
     rbml_w.end_tag();
 }
 
+fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder,
+                                             ecx: &EncodeContext<'a, 'tcx>,
+                                             id: ast::NodeId) {
+    encode_bounds_and_type(rbml_w,
+                           ecx,
+                           &ty::lookup_item_type(ecx.tcx, local_def(id)),
+                           &ty::lookup_predicates(ecx.tcx, local_def(id)));
+}
+
 fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder,
                                     ecx: &EncodeContext<'a, 'tcx>,
-                                    pty: &ty::TypeScheme<'tcx>) {
-    encode_generics(rbml_w, ecx, &pty.generics, tag_item_generics);
-    encode_type(ecx, rbml_w, pty.ty);
+                                    scheme: &ty::TypeScheme<'tcx>,
+                                    predicates: &ty::GenericPredicates<'tcx>) {
+    encode_generics(rbml_w, ecx, &scheme.generics, &predicates, tag_item_generics);
+    encode_type(ecx, rbml_w, scheme.ty);
 }
 
 fn encode_variant_id(rbml_w: &mut Encoder, vid: DefId) {
@@ -353,8 +363,7 @@ fn encode_enum_variant_info(ecx: &EncodeContext,
             encode_disr_val(ecx, rbml_w, (*vi)[i].disr_val);
             disr_val = (*vi)[i].disr_val;
         }
-        encode_bounds_and_type(rbml_w, ecx,
-                               &lookup_item_type(ecx.tcx, def_id));
+        encode_bounds_and_type_for_item(rbml_w, ecx, def_id.local_id());
 
         ecx.tcx.map.with_path(variant.node.id, |path| encode_path(rbml_w, path));
         rbml_w.end_tag();
@@ -698,8 +707,7 @@ fn encode_info_for_struct(ecx: &EncodeContext,
                token::get_name(nm), id);
         encode_struct_field_family(rbml_w, field.vis);
         encode_name(rbml_w, nm);
-        encode_bounds_and_type(rbml_w, ecx,
-                               &lookup_item_type(ecx.tcx, local_def(id)));
+        encode_bounds_and_type_for_item(rbml_w, ecx, id);
         encode_def_id(rbml_w, local_def(id));
 
         let stab = stability::lookup(ecx.tcx, field.id);
@@ -724,8 +732,7 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
     rbml_w.start_tag(tag_items_data_item);
     encode_def_id(rbml_w, local_def(ctor_id));
     encode_family(rbml_w, 'o');
-    encode_bounds_and_type(rbml_w, ecx,
-                           &lookup_item_type(ecx.tcx, local_def(ctor_id)));
+    encode_bounds_and_type_for_item(rbml_w, ecx, ctor_id);
     encode_name(rbml_w, name.name);
     ecx.tcx.map.with_path(ctor_id, |path| encode_path(rbml_w, path));
     encode_parent_item(rbml_w, local_def(struct_id));
@@ -749,6 +756,7 @@ fn encode_info_for_struct_ctor(ecx: &EncodeContext,
 fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
                              ecx: &EncodeContext<'a, 'tcx>,
                              generics: &ty::Generics<'tcx>,
+                             predicates: &ty::GenericPredicates<'tcx>,
                              tag: uint)
 {
     rbml_w.start_tag(tag);
@@ -790,7 +798,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
         rbml_w.end_tag();
     }
 
-    for (space, _, predicate) in generics.predicates.iter_enumerated() {
+    for (space, _, predicate) in predicates.predicates.iter_enumerated() {
         rbml_w.start_tag(tag_predicate);
 
         rbml_w.wr_tagged_u8(tag_predicate_space, space as u8);
@@ -810,7 +818,7 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                      method_ty: &ty::Method<'tcx>) {
     encode_def_id(rbml_w, method_ty.def_id);
     encode_name(rbml_w, method_ty.name);
-    encode_generics(rbml_w, ecx, &method_ty.generics,
+    encode_generics(rbml_w, ecx, &method_ty.generics, &method_ty.predicates,
                     tag_method_ty_generics);
     encode_method_fty(ecx, rbml_w, &method_ty.fty);
     encode_visibility(rbml_w, method_ty.vis);
@@ -844,15 +852,15 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
     encode_stability(rbml_w, stab);
 
     // The type for methods gets encoded twice, which is unfortunate.
-    let pty = lookup_item_type(ecx.tcx, m.def_id);
-    encode_bounds_and_type(rbml_w, ecx, &pty);
+    encode_bounds_and_type_for_item(rbml_w, ecx, m.def_id.local_id());
 
     let elem = ast_map::PathName(m.name);
     encode_path(rbml_w, impl_path.chain(Some(elem).into_iter()));
     match ast_item_opt {
         Some(&ast::MethodImplItem(ref ast_method)) => {
             encode_attributes(rbml_w, &ast_method.attrs[]);
-            let any_types = !pty.generics.types.is_empty();
+            let scheme = ty::lookup_item_type(ecx.tcx, m.def_id);
+            let any_types = !scheme.generics.types.is_empty();
             if any_types || is_default_impl || should_inline(&ast_method.attrs[]) {
                 encode_inlined_item(ecx, rbml_w, IIImplItemRef(local_def(parent_id),
                                                                ast_item_opt.unwrap()));
@@ -887,8 +895,7 @@ fn encode_info_for_associated_type(ecx: &EncodeContext,
     encode_parent_item(rbml_w, local_def(parent_id));
     encode_item_sort(rbml_w, 't');
 
-    let type_scheme = ty::lookup_item_type(ecx.tcx, associated_type.def_id);
-    encode_bounds_and_type(rbml_w, ecx, &type_scheme);
+    encode_bounds_and_type_for_item(rbml_w, ecx, associated_type.def_id.local_id());
 
     let stab = stability::lookup(ecx.tcx, associated_type.def_id);
     encode_stability(rbml_w, stab);
@@ -1027,7 +1034,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
         } else {
             encode_family(rbml_w, 'c');
         }
-        encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
+        encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
         encode_symbol(ecx, rbml_w, item.id);
         encode_name(rbml_w, item.ident.name);
         encode_path(rbml_w, path);
@@ -1041,7 +1048,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id(rbml_w, def_id);
         encode_family(rbml_w, 'C');
-        encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
+        encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
         encode_name(rbml_w, item.ident.name);
         encode_path(rbml_w, path);
         encode_attributes(rbml_w, &item.attrs);
@@ -1056,7 +1063,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
         encode_def_id(rbml_w, def_id);
         encode_family(rbml_w, FN_FAMILY);
         let tps_len = generics.ty_params.len();
-        encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
+        encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
         encode_name(rbml_w, item.ident.name);
         encode_path(rbml_w, path);
         encode_attributes(rbml_w, &item.attrs[]);
@@ -1105,7 +1112,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id(rbml_w, def_id);
         encode_family(rbml_w, 'y');
-        encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
+        encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
         encode_name(rbml_w, item.ident.name);
         encode_path(rbml_w, path);
         encode_visibility(rbml_w, vis);
@@ -1119,7 +1126,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
         encode_def_id(rbml_w, def_id);
         encode_family(rbml_w, 't');
         encode_item_variances(rbml_w, ecx, item.id);
-        encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
+        encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
         encode_name(rbml_w, item.ident.name);
         encode_attributes(rbml_w, &item.attrs[]);
         encode_repr_attrs(rbml_w, ecx, &item.attrs[]);
@@ -1161,7 +1168,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id(rbml_w, def_id);
         encode_family(rbml_w, 'S');
-        encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
+        encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
 
         encode_item_variances(rbml_w, ecx, item.id);
         encode_name(rbml_w, item.ident.name);
@@ -1204,7 +1211,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id(rbml_w, def_id);
         encode_family(rbml_w, 'i');
-        encode_bounds_and_type(rbml_w, ecx, &lookup_item_type(tcx, def_id));
+        encode_bounds_and_type_for_item(rbml_w, ecx, item.id);
         encode_name(rbml_w, item.ident.name);
         encode_attributes(rbml_w, &item.attrs[]);
         encode_unsafety(rbml_w, unsafety);
@@ -1305,10 +1312,11 @@ fn encode_info_for_item(ecx: &EncodeContext,
         encode_family(rbml_w, 'I');
         encode_item_variances(rbml_w, ecx, item.id);
         let trait_def = ty::lookup_trait_def(tcx, def_id);
+        let trait_predicates = ty::lookup_predicates(tcx, def_id);
         encode_unsafety(rbml_w, trait_def.unsafety);
         encode_paren_sugar(rbml_w, trait_def.paren_sugar);
         encode_associated_type_names(rbml_w, &trait_def.associated_type_names);
-        encode_generics(rbml_w, ecx, &trait_def.generics, tag_item_generics);
+        encode_generics(rbml_w, ecx, &trait_def.generics, &trait_predicates, tag_item_generics);
         encode_trait_ref(rbml_w, ecx, &*trait_def.trait_ref, tag_item_trait_ref);
         encode_name(rbml_w, item.ident.name);
         encode_attributes(rbml_w, &item.attrs[]);
@@ -1384,9 +1392,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
                                           METHOD_FAMILY);
                         }
                     }
-                    let pty = ty::lookup_item_type(tcx,
-                                                   method_def_id);
-                    encode_bounds_and_type(rbml_w, ecx, &pty);
+                    encode_bounds_and_type_for_item(rbml_w, ecx, method_def_id.local_id());
 
                     is_nonstatic_method = method_ty.explicit_self !=
                         ty::StaticExplicitSelfCategory;
@@ -1415,8 +1421,7 @@ fn encode_info_for_item(ecx: &EncodeContext,
                 if is_nonstatic_method {
                     // FIXME: I feel like there is something funny
                     // going on.
-                    let pty = ty::lookup_item_type(tcx, item_def_id.def_id());
-                    encode_bounds_and_type(rbml_w, ecx, &pty);
+                    encode_bounds_and_type_for_item(rbml_w, ecx, item_def_id.def_id().local_id());
                 }
             };
             match trait_item {
@@ -1468,8 +1473,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
     match nitem.node {
       ast::ForeignItemFn(ref fndecl, _) => {
         encode_family(rbml_w, FN_FAMILY);
-        encode_bounds_and_type(rbml_w, ecx,
-                               &lookup_item_type(ecx.tcx,local_def(nitem.id)));
+        encode_bounds_and_type_for_item(rbml_w, ecx, nitem.id);
         encode_name(rbml_w, nitem.ident.name);
         if abi == abi::RustIntrinsic {
             encode_inlined_item(ecx, rbml_w, IIForeignRef(nitem));
@@ -1486,8 +1490,7 @@ fn encode_info_for_foreign_item(ecx: &EncodeContext,
         } else {
             encode_family(rbml_w, 'c');
         }
-        encode_bounds_and_type(rbml_w, ecx,
-                               &lookup_item_type(ecx.tcx,local_def(nitem.id)));
+        encode_bounds_and_type_for_item(rbml_w, ecx, nitem.id);
         encode_attributes(rbml_w, &*nitem.attrs);
         let stab = stability::lookup(ecx.tcx, ast_util::local_def(nitem.id));
         encode_stability(rbml_w, stab);
diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs
index 1b2d82e68c1..3caa0f5b4db 100644
--- a/src/librustc/metadata/filesearch.rs
+++ b/src/librustc/metadata/filesearch.rs
@@ -207,7 +207,7 @@ static PATH_ENTRY_SEPARATOR: &'static str = ":";
 
 /// Returns RUST_PATH as a string, without default paths added
 pub fn get_rust_path() -> Option<String> {
-    env::var_string("RUST_PATH").ok()
+    env::var("RUST_PATH").ok()
 }
 
 /// Returns the value of RUST_PATH, as a list
diff --git a/src/librustc/metadata/tydecode.rs b/src/librustc/metadata/tydecode.rs
index 7cc7e49b6d2..9962f49dfcf 100644
--- a/src/librustc/metadata/tydecode.rs
+++ b/src/librustc/metadata/tydecode.rs
@@ -349,7 +349,7 @@ fn parse_region_<F>(st: &mut PState, conv: &mut F) -> ty::Region where
       }
       'f' => {
         assert_eq!(next(st), '[');
-        let scope = parse_scope(st);
+        let scope = parse_destruction_scope_data(st);
         assert_eq!(next(st), '|');
         let br = parse_bound_region_(st, conv);
         assert_eq!(next(st), ']');
@@ -377,6 +377,10 @@ fn parse_scope(st: &mut PState) -> region::CodeExtent {
             let node_id = parse_uint(st) as ast::NodeId;
             region::CodeExtent::Misc(node_id)
         }
+        'D' => {
+            let node_id = parse_uint(st) as ast::NodeId;
+            region::CodeExtent::DestructionScope(node_id)
+        }
         'B' => {
             let node_id = parse_uint(st) as ast::NodeId;
             let first_stmt_index = parse_uint(st);
@@ -389,6 +393,11 @@ fn parse_scope(st: &mut PState) -> region::CodeExtent {
     }
 }
 
+fn parse_destruction_scope_data(st: &mut PState) -> region::DestructionScopeData {
+    let node_id = parse_uint(st) as ast::NodeId;
+    region::DestructionScopeData::new(node_id)
+}
+
 fn parse_opt<'a, 'tcx, T, F>(st: &mut PState<'a, 'tcx>, f: F) -> Option<T> where
     F: FnOnce(&mut PState<'a, 'tcx>) -> T,
 {
diff --git a/src/librustc/metadata/tyencode.rs b/src/librustc/metadata/tyencode.rs
index f8081e2c309..640b9649286 100644
--- a/src/librustc/metadata/tyencode.rs
+++ b/src/librustc/metadata/tyencode.rs
@@ -251,7 +251,7 @@ pub fn enc_region(w: &mut SeekableMemWriter, cx: &ctxt, r: ty::Region) {
         }
         ty::ReFree(ref fr) => {
             mywrite!(w, "f[");
-            enc_scope(w, cx, fr.scope);
+            enc_destruction_scope_data(w, fr.scope);
             mywrite!(w, "|");
             enc_bound_region(w, cx, fr.bound_region);
             mywrite!(w, "]");
@@ -279,9 +279,15 @@ fn enc_scope(w: &mut SeekableMemWriter, _cx: &ctxt, scope: region::CodeExtent) {
         region::CodeExtent::Misc(node_id) => mywrite!(w, "M{}", node_id),
         region::CodeExtent::Remainder(region::BlockRemainder {
             block: b, first_statement_index: i }) => mywrite!(w, "B{}{}", b, i),
+        region::CodeExtent::DestructionScope(node_id) => mywrite!(w, "D{}", node_id),
     }
 }
 
+fn enc_destruction_scope_data(w: &mut SeekableMemWriter,
+                              d: region::DestructionScopeData) {
+    mywrite!(w, "{}", d.node_id);
+}
+
 fn enc_bound_region(w: &mut SeekableMemWriter, cx: &ctxt, br: ty::BoundRegion) {
     match br {
         ty::BrAnon(idx) => {
diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs
index b0fe743b683..423032d1287 100644
--- a/src/librustc/middle/astencode.rs
+++ b/src/librustc/middle/astencode.rs
@@ -499,6 +499,12 @@ impl tr for region::CodeExtent {
     }
 }
 
+impl tr for region::DestructionScopeData {
+    fn tr(&self, dcx: &DecodeContext) -> region::DestructionScopeData {
+        region::DestructionScopeData { node_id: dcx.tr_id(self.node_id) }
+    }
+}
+
 impl tr for ty::BoundRegion {
     fn tr(&self, dcx: &DecodeContext) -> ty::BoundRegion {
         match *self {
@@ -945,11 +951,6 @@ impl<'a, 'tcx> rbml_writer_helpers<'tcx> for Encoder<'a> {
                         Ok(encode_vec_per_param_space(
                             this, &type_scheme.generics.regions,
                             |this, def| def.encode(this).unwrap()))
-                    });
-                    this.emit_struct_field("predicates", 2, |this| {
-                        Ok(encode_vec_per_param_space(
-                            this, &type_scheme.generics.predicates,
-                            |this, def| this.emit_predicate(ecx, def)))
                     })
                 })
             });
@@ -1568,7 +1569,7 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
 
     fn read_type_scheme<'b, 'c>(&mut self, dcx: &DecodeContext<'b, 'c, 'tcx>)
                                 -> ty::TypeScheme<'tcx> {
-        self.read_struct("TypeScheme", 2, |this| {
+        self.read_struct("TypeScheme", 3, |this| {
             Ok(ty::TypeScheme {
                 generics: this.read_struct_field("generics", 0, |this| {
                     this.read_struct("Generics", 2, |this| {
@@ -1584,12 +1585,6 @@ impl<'a, 'tcx> rbml_decoder_decoder_helpers<'tcx> for reader::Decoder<'a> {
                                 Ok(this.read_vec_per_param_space(
                                     |this| Decodable::decode(this).unwrap()))
                             }).unwrap(),
-
-                            predicates:
-                            this.read_struct_field("predicates", 2, |this| {
-                                Ok(this.read_vec_per_param_space(
-                                    |this| this.read_predicate(dcx)))
-                            }).unwrap(),
                         })
                     })
                 }).unwrap(),
diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs
index 7ba83c62496..b792a44d4d8 100644
--- a/src/librustc/middle/dataflow.rs
+++ b/src/librustc/middle/dataflow.rs
@@ -20,7 +20,7 @@ use middle::cfg;
 use middle::cfg::CFGIndex;
 use middle::ty;
 use std::old_io;
-use std::uint;
+use std::usize;
 use std::iter::repeat;
 use syntax::ast;
 use syntax::ast_util::IdRange;
@@ -48,7 +48,7 @@ pub struct DataFlowContext<'a, 'tcx: 'a, O> {
     bits_per_id: uint,
 
     /// number of words we will use to store bits_per_id.
-    /// equal to bits_per_id/uint::BITS rounded up.
+    /// equal to bits_per_id/usize::BITS rounded up.
     words_per_id: uint,
 
     // mapping from node to cfg node index
@@ -193,7 +193,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
                oper: O,
                id_range: IdRange,
                bits_per_id: uint) -> DataFlowContext<'a, 'tcx, O> {
-        let words_per_id = (bits_per_id + uint::BITS - 1) / uint::BITS;
+        let words_per_id = (bits_per_id + usize::BITS - 1) / usize::BITS;
         let num_nodes = cfg.graph.all_nodes().len();
 
         debug!("DataFlowContext::new(analysis_name: {}, id_range={:?}, \
@@ -202,7 +202,7 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
                analysis_name, id_range, bits_per_id, words_per_id,
                num_nodes);
 
-        let entry = if oper.initial_value() { uint::MAX } else {0};
+        let entry = if oper.initial_value() { usize::MAX } else {0};
 
         let gens: Vec<_> = repeat(0).take(num_nodes * words_per_id).collect();
         let kills: Vec<_> = repeat(0).take(num_nodes * words_per_id).collect();
@@ -351,13 +351,13 @@ impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
 
         for (word_index, &word) in words.iter().enumerate() {
             if word != 0 {
-                let base_index = word_index * uint::BITS;
-                for offset in 0..uint::BITS {
+                let base_index = word_index * usize::BITS;
+                for offset in 0..usize::BITS {
                     let bit = 1 << offset;
                     if (word & bit) != 0 {
                         // NB: we round up the total number of bits
                         // that we store in any given bit set so that
-                        // it is an even multiple of uint::BITS.  This
+                        // it is an even multiple of usize::BITS.  This
                         // means that there may be some stray bits at
                         // the end that do not correspond to any
                         // actual value.  So before we callback, check
@@ -500,7 +500,7 @@ impl<'a, 'b, 'tcx, O:DataFlowOperator> PropagationContext<'a, 'b, 'tcx, O> {
     }
 
     fn reset(&mut self, bits: &mut [uint]) {
-        let e = if self.dfcx.oper.initial_value() {uint::MAX} else {0};
+        let e = if self.dfcx.oper.initial_value() {usize::MAX} else {0};
         for b in bits {
             *b = e;
         }
@@ -552,7 +552,7 @@ fn bits_to_string(words: &[uint]) -> String {
 
     for &word in words {
         let mut v = word;
-        for _ in 0..uint::BYTES {
+        for _ in 0..usize::BYTES {
             result.push(sep);
             result.push_str(&format!("{:02x}", v & 0xFF)[]);
             v >>= 8;
@@ -581,8 +581,8 @@ fn bitwise<Op:BitwiseOperator>(out_vec: &mut [uint],
 fn set_bit(words: &mut [uint], bit: uint) -> bool {
     debug!("set_bit: words={} bit={}",
            mut_bits_to_string(words), bit_str(bit));
-    let word = bit / uint::BITS;
-    let bit_in_word = bit % uint::BITS;
+    let word = bit / usize::BITS;
+    let bit_in_word = bit % usize::BITS;
     let bit_mask = 1 << bit_in_word;
     debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, word);
     let oldv = words[word];
diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs
index a157d5d712b..b2335f91ad9 100644
--- a/src/librustc/middle/dead.rs
+++ b/src/librustc/middle/dead.rs
@@ -234,7 +234,7 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> {
             ast_map::NodeImplItem(impl_item) => {
                 match *impl_item {
                     ast::MethodImplItem(ref method) => {
-                        visit::walk_block(self, method.pe_body());
+                        visit::walk_method_helper(self, method);
                     }
                     ast::TypeImplItem(_) => {}
                 }
diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs
index b5904f23ef3..0ce9db1c80f 100644
--- a/src/librustc/middle/entry.rs
+++ b/src/librustc/middle/entry.rs
@@ -50,10 +50,7 @@ pub fn find_entry_point(session: &Session, ast_map: &ast_map::Map) {
     let any_exe = session.crate_types.borrow().iter().any(|ty| {
         *ty == config::CrateTypeExecutable
     });
-    let emit_link = session.opts.output_types.iter().any(|ty| {
-        *ty == config::OutputTypeExe
-    });
-    if !any_exe || !emit_link {
+    if !any_exe {
         // No need to find a main function
         return
     }
diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs
index 989efdd235d..4dd7a4a2266 100644
--- a/src/librustc/middle/graph.rs
+++ b/src/librustc/middle/graph.rs
@@ -33,7 +33,7 @@
 #![allow(dead_code)] // still WIP
 
 use std::fmt::{Formatter, Error, Debug};
-use std::uint;
+use std::usize;
 use std::collections::BitvSet;
 
 pub struct Graph<N,E> {
@@ -64,12 +64,12 @@ impl<E: Debug> Debug for Edge<E> {
 #[derive(Clone, Copy, PartialEq, Debug)]
 pub struct NodeIndex(pub uint);
 #[allow(non_upper_case_globals)]
-pub const InvalidNodeIndex: NodeIndex = NodeIndex(uint::MAX);
+pub const InvalidNodeIndex: NodeIndex = NodeIndex(usize::MAX);
 
 #[derive(Copy, PartialEq, Debug)]
 pub struct EdgeIndex(pub uint);
 #[allow(non_upper_case_globals)]
-pub const InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::MAX);
+pub const InvalidEdgeIndex: EdgeIndex = EdgeIndex(usize::MAX);
 
 // Use a private field here to guarantee no more instances are created:
 #[derive(Copy, Debug)]
diff --git a/src/librustc/middle/infer/error_reporting.rs b/src/librustc/middle/infer/error_reporting.rs
index 99896535442..5d7a56ef0e6 100644
--- a/src/librustc/middle/infer/error_reporting.rs
+++ b/src/librustc/middle/infer/error_reporting.rs
@@ -242,7 +242,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
                     }
                 }
                 SubSupConflict(var_origin, _, sub_r, _, sup_r) => {
-                    debug!("processing SubSupConflict");
+                    debug!("processing SubSupConflict sub: {:?} sup: {:?}", sub_r, sup_r);
                     match free_regions_from_same_fn(self.tcx, sub_r, sup_r) {
                         Some(ref same_frs) => {
                             var_origins.push(var_origin);
@@ -304,7 +304,7 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
                         return None
                     }
                     assert!(fr1.scope == fr2.scope);
-                    (fr1.scope.node_id(), fr1, fr2)
+                    (fr1.scope.node_id, fr1, fr2)
                 },
                 _ => return None
             };
@@ -709,6 +709,23 @@ impl<'a, 'tcx> ErrorReporting<'tcx> for InferCtxt<'a, 'tcx> {
                     sup,
                     "");
             }
+            infer::SafeDestructor(span) => {
+                self.tcx.sess.span_err(
+                    span,
+                    "unsafe use of destructor: destructor might be called \
+                     while references are dead");
+                // FIXME (22171): terms "super/subregion" are suboptimal
+                note_and_explain_region(
+                    self.tcx,
+                    "superregion: ",
+                    sup,
+                    "");
+                note_and_explain_region(
+                    self.tcx,
+                    "subregion: ",
+                    sub,
+                    "");
+            }
             infer::BindingTypeIsNotValidAtDecl(span) => {
                 self.tcx.sess.span_err(
                     span,
@@ -1629,6 +1646,12 @@ impl<'a, 'tcx> ErrorReportingHelpers<'tcx> for InferCtxt<'a, 'tcx> {
                     &format!("...so that the declared lifetime parameter bounds \
                                 are satisfied")[]);
             }
+            infer::SafeDestructor(span) => {
+                self.tcx.sess.span_note(
+                    span,
+                    "...so that references are valid when the destructor \
+                     runs")
+            }
         }
     }
 }
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index f8dae3e92da..41310f05588 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -215,6 +215,9 @@ pub enum SubregionOrigin<'tcx> {
 
     // An auto-borrow that does not enclose the expr where it occurs
     AutoBorrow(Span),
+
+    // Region constraint arriving from destructor safety
+    SafeDestructor(Span),
 }
 
 /// Times when we replace late-bound regions with variables:
@@ -1197,6 +1200,7 @@ impl<'tcx> SubregionOrigin<'tcx> {
             CallReturn(a) => a,
             AddrOf(a) => a,
             AutoBorrow(a) => a,
+            SafeDestructor(a) => a,
         }
     }
 }
@@ -1259,6 +1263,7 @@ impl<'tcx> Repr<'tcx> for SubregionOrigin<'tcx> {
             CallReturn(a) => format!("CallReturn({})", a.repr(tcx)),
             AddrOf(a) => format!("AddrOf({})", a.repr(tcx)),
             AutoBorrow(a) => format!("AutoBorrow({})", a.repr(tcx)),
+            SafeDestructor(a) => format!("SafeDestructor({})", a.repr(tcx)),
         }
     }
 }
diff --git a/src/librustc/middle/infer/region_inference/graphviz.rs b/src/librustc/middle/infer/region_inference/graphviz.rs
index 362919755c3..67875ae2252 100644
--- a/src/librustc/middle/infer/region_inference/graphviz.rs
+++ b/src/librustc/middle/infer/region_inference/graphviz.rs
@@ -61,13 +61,13 @@ pub fn maybe_print_constraints_for<'a, 'tcx>(region_vars: &RegionVarBindings<'a,
     }
 
     let requested_node : Option<ast::NodeId> =
-        env::var_string("RUST_REGION_GRAPH_NODE").ok().and_then(|s| s.parse().ok());
+        env::var("RUST_REGION_GRAPH_NODE").ok().and_then(|s| s.parse().ok());
 
     if requested_node.is_some() && requested_node != Some(subject_node) {
         return;
     }
 
-    let requested_output = env::var_string("RUST_REGION_GRAPH").ok();
+    let requested_output = env::var("RUST_REGION_GRAPH").ok();
     debug!("requested_output: {:?} requested_node: {:?}",
            requested_output, requested_node);
 
diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs
index 1a7308a4f18..3dba8045d60 100644
--- a/src/librustc/middle/infer/region_inference/mod.rs
+++ b/src/librustc/middle/infer/region_inference/mod.rs
@@ -760,11 +760,12 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
             // A "free" region can be interpreted as "some region
             // at least as big as the block fr.scope_id".  So, we can
             // reasonably compare free regions and scopes:
-            match self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id) {
+            let fr_scope = fr.scope.to_code_extent();
+            match self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) {
               // if the free region's scope `fr.scope_id` is bigger than
               // the scope region `s_id`, then the LUB is the free
               // region itself:
-              Some(r_id) if r_id == fr.scope => f,
+              Some(r_id) if r_id == fr_scope => f,
 
               // otherwise, we don't know what the free region is,
               // so we must conservatively say the LUB is static:
@@ -865,8 +866,9 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                 // than the scope `s_id`, then we can say that the GLB
                 // is the scope `s_id`.  Otherwise, as we do not know
                 // big the free region is precisely, the GLB is undefined.
-                match self.tcx.region_maps.nearest_common_ancestor(fr.scope, s_id) {
-                    Some(r_id) if r_id == fr.scope => Ok(s),
+                let fr_scope = fr.scope.to_code_extent();
+                match self.tcx.region_maps.nearest_common_ancestor(fr_scope, s_id) {
+                    Some(r_id) if r_id == fr_scope => Ok(s),
                     _ => Err(ty::terr_regions_no_overlap(b, a))
                 }
             }
@@ -915,7 +917,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
                 Ok(ty::ReFree(*b))
             } else {
                 this.intersect_scopes(ty::ReFree(*a), ty::ReFree(*b),
-                                      a.scope, b.scope)
+                                      a.scope.to_code_extent(),
+                                      b.scope.to_code_extent())
             }
         }
     }
@@ -1396,6 +1399,8 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
             for upper_bound in &upper_bounds {
                 if !self.is_subregion_of(lower_bound.region,
                                          upper_bound.region) {
+                    debug!("pushing SubSupConflict sub: {:?} sup: {:?}",
+                           lower_bound.region, upper_bound.region);
                     errors.push(SubSupConflict(
                         (*self.var_origins.borrow())[node_idx.index as uint].clone(),
                         lower_bound.origin.clone(),
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 05969d4ea43..ef72c2242c1 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -312,6 +312,8 @@ lets_do_this! {
     ExchangeHeapLangItem,            "exchange_heap",           exchange_heap;
     OwnedBoxLangItem,                "owned_box",               owned_box;
 
+    PhantomDataItem,                 "phantom_data",            phantom_data;
+
     CovariantTypeItem,               "covariant_type",          covariant_type;
     ContravariantTypeItem,           "contravariant_type",      contravariant_type;
     InvariantTypeItem,               "invariant_type",          invariant_type;
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index fcc5d70a7a5..d4fe0979313 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -112,7 +112,7 @@ use self::VarKind::*;
 use middle::def::*;
 use middle::mem_categorization::Typer;
 use middle::pat_util;
-use middle::region::CodeExtent;
+use middle::region;
 use middle::ty;
 use middle::ty::ClosureTyper;
 use lint;
@@ -1514,7 +1514,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         let fn_ret =
             ty::liberate_late_bound_regions(
                 self.ir.tcx,
-                CodeExtent::from_node_id(body.id),
+                region::DestructionScopeData::new(body.id),
                 &self.fn_ret(id));
 
         match fn_ret {
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 58492c817fd..fed2f7d9245 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -760,7 +760,10 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
 
         // Region of environment pointer
         let env_region = ty::ReFree(ty::FreeRegion {
-            scope: region::CodeExtent::from_node_id(fn_body_id),
+            // The environment of a closure is guaranteed to
+            // outlive any bindings introduced in the body of the
+            // closure itself.
+            scope: region::DestructionScopeData::new(fn_body_id),
             bound_region: ty::BrEnv
         });
 
diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs
index 037b1c31a17..2f0462ab8c3 100644
--- a/src/librustc/middle/region.rs
+++ b/src/librustc/middle/region.rs
@@ -27,11 +27,66 @@ use syntax::{ast, visit};
 use syntax::ast::{Block, Item, FnDecl, NodeId, Arm, Pat, Stmt, Expr, Local};
 use syntax::ast_util::{stmt_id};
 use syntax::ast_map;
+use syntax::ptr::P;
 use syntax::visit::{Visitor, FnKind};
 
 /// CodeExtent represents a statically-describable extent that can be
 /// used to bound the lifetime/region for values.
 ///
+/// `Misc(node_id)`: Any AST node that has any extent at all has the
+/// `Misc(node_id)` extent. Other variants represent special cases not
+/// immediately derivable from the abstract syntax tree structure.
+///
+/// `DestructionScope(node_id)` represents the extent of destructors
+/// implicitly-attached to `node_id` that run immediately after the
+/// expression for `node_id` itself. Not every AST node carries a
+/// `DestructionScope`, but those that are `terminating_scopes` do;
+/// see discussion with `RegionMaps`.
+///
+/// `Remainder(BlockRemainder { block, statement_index })` represents
+/// the extent of user code running immediately after the initializer
+/// expression for the indexed statement, until the end of the block.
+///
+/// So: the following code can be broken down into the extents beneath:
+/// ```
+/// let a = f().g( 'b: { let x = d(); let y = d(); x.h(y)  }   ) ;
+/// ```
+///
+///                                                              +-+ (D12.)
+///                                                        +-+       (D11.)
+///                                              +---------+         (R10.)
+///                                              +-+                  (D9.)
+///                                   +----------+                    (M8.)
+///                                 +----------------------+          (R7.)
+///                                 +-+                               (D6.)
+///                      +----------+                                 (M5.)
+///                    +-----------------------------------+          (M4.)
+///         +--------------------------------------------------+      (M3.)
+///         +--+                                                      (M2.)
+/// +-----------------------------------------------------------+     (M1.)
+///
+///  (M1.): Misc extent of the whole `let a = ...;` statement.
+///  (M2.): Misc extent of the `f()` expression.
+///  (M3.): Misc extent of the `f().g(..)` expression.
+///  (M4.): Misc extent of the block labelled `'b:`.
+///  (M5.): Misc extent of the `let x = d();` statement
+///  (D6.): DestructionScope for temporaries created during M5.
+///  (R7.): Remainder extent for block `'b:`, stmt 0 (let x = ...).
+///  (M8.): Misc Extent of the `let y = d();` statement.
+///  (D9.): DestructionScope for temporaries created during M8.
+/// (R10.): Remainder extent for block `'b:`, stmt 1 (let y = ...).
+/// (D11.): DestructionScope for temporaries and bindings from block `'b:`.
+/// (D12.): DestructionScope for temporaries created during M1 (e.g. f()).
+///
+/// Note that while the above picture shows the destruction scopes
+/// as following their corresponding misc extents, in the internal
+/// data structures of the compiler the destruction scopes are
+/// represented as enclosing parents. This is sound because we use the
+/// enclosing parent relationship just to ensure that referenced
+/// values live long enough; phrased another way, the starting point
+/// of each range is not really the important thing in the above
+/// picture, but rather the ending point.
+///
 /// FIXME (pnkfelix): This currently derives `PartialOrd` and `Ord` to
 /// placate the same deriving in `ty::FreeRegion`, but we may want to
 /// actually attach a more meaningful ordering to scopes than the one
@@ -40,7 +95,24 @@ use syntax::visit::{Visitor, FnKind};
            RustcDecodable, Debug, Copy)]
 pub enum CodeExtent {
     Misc(ast::NodeId),
-    Remainder(BlockRemainder),
+    DestructionScope(ast::NodeId), // extent of destructors for temporaries of node-id
+    Remainder(BlockRemainder)
+}
+
+/// extent of destructors for temporaries of node-id
+#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
+           RustcDecodable, Debug, Copy)]
+pub struct DestructionScopeData {
+    pub node_id: ast::NodeId
+}
+
+impl DestructionScopeData {
+    pub fn new(node_id: ast::NodeId) -> DestructionScopeData {
+        DestructionScopeData { node_id: node_id }
+    }
+    pub fn to_code_extent(&self) -> CodeExtent {
+        CodeExtent::DestructionScope(self.node_id)
+    }
 }
 
 /// Represents a subscope of `block` for a binding that is introduced
@@ -82,6 +154,7 @@ impl CodeExtent {
         match *self {
             CodeExtent::Misc(node_id) => node_id,
             CodeExtent::Remainder(br) => br.block,
+            CodeExtent::DestructionScope(node_id) => node_id,
         }
     }
 
@@ -95,6 +168,8 @@ impl CodeExtent {
             CodeExtent::Remainder(br) =>
                 CodeExtent::Remainder(BlockRemainder {
                     block: f_id(br.block), first_statement_index: br.first_statement_index }),
+            CodeExtent::DestructionScope(node_id) =>
+                CodeExtent::DestructionScope(f_id(node_id)),
         }
     }
 
@@ -105,7 +180,8 @@ impl CodeExtent {
         match ast_map.find(self.node_id()) {
             Some(ast_map::NodeBlock(ref blk)) => {
                 match *self {
-                    CodeExtent::Misc(_) => Some(blk.span),
+                    CodeExtent::Misc(_) |
+                    CodeExtent::DestructionScope(_) => Some(blk.span),
 
                     CodeExtent::Remainder(r) => {
                         assert_eq!(r.block, blk.id);
@@ -455,7 +531,7 @@ impl RegionMaps {
                 }
 
                 (ty::ReScope(sub_scope), ty::ReFree(ref fr)) => {
-                    self.is_subscope_of(sub_scope, fr.scope)
+                    self.is_subscope_of(sub_scope, fr.scope.to_code_extent())
                 }
 
                 (ty::ReFree(sub_fr), ty::ReFree(super_fr)) => {
@@ -567,7 +643,18 @@ fn resolve_block(visitor: &mut RegionResolutionVisitor, blk: &ast::Block) {
     let prev_cx = visitor.cx;
 
     let blk_scope = CodeExtent::Misc(blk.id);
-    record_superlifetime(visitor, blk_scope, blk.span);
+    // If block was previously marked as a terminating scope during
+    // the recursive visit of its parent node in the AST, then we need
+    // to account for the destruction scope representing the extent of
+    // the destructors that run immediately after the the block itself
+    // completes.
+    if visitor.region_maps.terminating_scopes.borrow().contains(&blk_scope) {
+        let dtor_scope = CodeExtent::DestructionScope(blk.id);
+        record_superlifetime(visitor, dtor_scope, blk.span);
+        visitor.region_maps.record_encl_scope(blk_scope, dtor_scope);
+    } else {
+        record_superlifetime(visitor, blk_scope, blk.span);
+    }
 
     // We treat the tail expression in the block (if any) somewhat
     // differently from the statements. The issue has to do with
@@ -675,7 +762,9 @@ fn resolve_stmt(visitor: &mut RegionResolutionVisitor, stmt: &ast::Stmt) {
     // statement plus its destructors, and thus the extent for which
     // regions referenced by the destructors need to survive.
     visitor.region_maps.mark_as_terminating_scope(stmt_scope);
-    record_superlifetime(visitor, stmt_scope, stmt.span);
+    let dtor_scope = CodeExtent::DestructionScope(stmt_id);
+    visitor.region_maps.record_encl_scope(stmt_scope, dtor_scope);
+    record_superlifetime(visitor, dtor_scope, stmt.span);
 
     let prev_parent = visitor.cx.parent;
     visitor.cx.parent = InnermostEnclosingExpr::Some(stmt_id);
@@ -687,15 +776,30 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) {
     debug!("resolve_expr(expr.id={:?})", expr.id);
 
     let expr_scope = CodeExtent::Misc(expr.id);
-    record_superlifetime(visitor, expr_scope, expr.span);
+    // If expr was previously marked as a terminating scope during the
+    // recursive visit of its parent node in the AST, then we need to
+    // account for the destruction scope representing the extent of
+    // the destructors that run immediately after the the expression
+    // itself completes.
+    if visitor.region_maps.terminating_scopes.borrow().contains(&expr_scope) {
+        let dtor_scope = CodeExtent::DestructionScope(expr.id);
+        record_superlifetime(visitor, dtor_scope, expr.span);
+        visitor.region_maps.record_encl_scope(expr_scope, dtor_scope);
+    } else {
+        record_superlifetime(visitor, expr_scope, expr.span);
+    }
 
     let prev_cx = visitor.cx;
     visitor.cx.parent = InnermostEnclosingExpr::Some(expr.id);
 
     {
         let region_maps = &mut visitor.region_maps;
-        let terminating = |id| {
-            let scope = CodeExtent::from_node_id(id);
+        let terminating = |e: &P<ast::Expr>| {
+            let scope = CodeExtent::from_node_id(e.id);
+            region_maps.mark_as_terminating_scope(scope)
+        };
+        let terminating_block = |b: &P<ast::Block>| {
+            let scope = CodeExtent::from_node_id(b.id);
             region_maps.mark_as_terminating_scope(scope)
         };
         match expr.node {
@@ -707,26 +811,26 @@ fn resolve_expr(visitor: &mut RegionResolutionVisitor, expr: &ast::Expr) {
             ast::ExprBinary(codemap::Spanned { node: ast::BiOr, .. }, _, ref r) => {
                 // For shortcircuiting operators, mark the RHS as a terminating
                 // scope since it only executes conditionally.
-                terminating(r.id);
+                terminating(r);
             }
 
             ast::ExprIf(_, ref then, Some(ref otherwise)) => {
-                terminating(then.id);
-                terminating(otherwise.id);
+                terminating_block(then);
+                terminating(otherwise);
             }
 
             ast::ExprIf(ref expr, ref then, None) => {
-                terminating(expr.id);
-                terminating(then.id);
+                terminating(expr);
+                terminating_block(then);
             }
 
             ast::ExprLoop(ref body, _) => {
-                terminating(body.id);
+                terminating_block(body);
             }
 
             ast::ExprWhile(ref expr, ref body, _) => {
-                terminating(expr.id);
-                terminating(body.id);
+                terminating(expr);
+                terminating_block(body);
             }
 
             ast::ExprMatch(..) => {
@@ -1021,6 +1125,9 @@ fn resolve_fn(visitor: &mut RegionResolutionVisitor,
 
     let body_scope = CodeExtent::from_node_id(body.id);
     visitor.region_maps.mark_as_terminating_scope(body_scope);
+    let dtor_scope = CodeExtent::DestructionScope(body.id);
+    visitor.region_maps.record_encl_scope(body_scope, dtor_scope);
+    record_superlifetime(visitor, dtor_scope, body.span);
 
     let outer_cx = visitor.cx;
 
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 6f38dc81064..e91d7d8c52c 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -41,7 +41,7 @@ pub enum DefRegion {
                         /* lifetime decl */ ast::NodeId),
     DefLateBoundRegion(ty::DebruijnIndex,
                        /* lifetime decl */ ast::NodeId),
-    DefFreeRegion(/* block scope */ region::CodeExtent,
+    DefFreeRegion(/* block scope */ region::DestructionScopeData,
                   /* lifetime decl */ ast::NodeId),
 }
 
@@ -81,7 +81,7 @@ enum ScopeChain<'a> {
     LateScope(&'a Vec<ast::LifetimeDef>, Scope<'a>),
     /// lifetimes introduced by items within a code block are scoped
     /// to that block.
-    BlockScope(region::CodeExtent, Scope<'a>),
+    BlockScope(region::DestructionScopeData, Scope<'a>),
     RootScope
 }
 
@@ -191,7 +191,8 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> {
     }
 
     fn visit_block(&mut self, b: &ast::Block) {
-        self.with(BlockScope(region::CodeExtent::from_node_id(b.id), self.scope),
+        self.with(BlockScope(region::DestructionScopeData::new(b.id),
+                             self.scope),
                   |_, this| visit::walk_block(this, b));
     }
 
@@ -393,9 +394,13 @@ impl<'a> LifetimeContext<'a> {
     }
 
     fn resolve_free_lifetime_ref(&mut self,
-                                 scope_data: region::CodeExtent,
+                                 scope_data: region::DestructionScopeData,
                                  lifetime_ref: &ast::Lifetime,
                                  scope: Scope) {
+        debug!("resolve_free_lifetime_ref \
+                scope_data: {:?} lifetime_ref: {:?} scope: {:?}",
+               scope_data, lifetime_ref, scope);
+
         // Walk up the scope chain, tracking the outermost free scope,
         // until we encounter a scope that contains the named lifetime
         // or we run out of scopes.
@@ -403,6 +408,9 @@ impl<'a> LifetimeContext<'a> {
         let mut scope = scope;
         let mut search_result = None;
         loop {
+            debug!("resolve_free_lifetime_ref \
+                    scope_data: {:?} scope: {:?} search_result: {:?}",
+                   scope_data, scope, search_result);
             match *scope {
                 BlockScope(blk_scope_data, s) => {
                     scope_data = blk_scope_data;
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 0ed672baf56..a086e91f4d9 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -13,6 +13,7 @@
 
 use session::Session;
 use lint;
+use middle::def;
 use middle::ty;
 use middle::privacy::PublicItems;
 use metadata::csearch;
@@ -277,6 +278,11 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
 
 impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
     fn visit_item(&mut self, item: &ast::Item) {
+        // When compiling with --test we don't enforce stability on the
+        // compiler-generated test module, demarcated with `DUMMY_SP` plus the
+        // name `__test`
+        if item.span == DUMMY_SP && item.ident.as_str() == "__test" { return }
+
         check_item(self.tcx, item,
                    &mut |id, sp, stab| self.check(id, sp, stab));
         visit::walk_item(self, item);
@@ -287,6 +293,12 @@ impl<'a, 'v, 'tcx> Visitor<'v> for Checker<'a, 'tcx> {
                    &mut |id, sp, stab| self.check(id, sp, stab));
         visit::walk_expr(self, ex);
     }
+
+    fn visit_path(&mut self, path: &ast::Path, id: ast::NodeId) {
+        check_path(self.tcx, path, id,
+                   &mut |id, sp, stab| self.check(id, sp, stab));
+        visit::walk_path(self, path)
+    }
 }
 
 /// Helper for discovering nodes to check for stability
@@ -304,18 +316,6 @@ pub fn check_item(tcx: &ty::ctxt, item: &ast::Item,
             let id = ast::DefId { krate: cnum, node: ast::CRATE_NODE_ID };
             maybe_do_stability_check(tcx, id, item.span, cb);
         }
-        ast::ItemTrait(_, _, ref supertraits, _) => {
-            for t in &**supertraits {
-                if let ast::TraitTyParamBound(ref t, _) = *t {
-                    let id = ty::trait_ref_to_def_id(tcx, &t.trait_ref);
-                    maybe_do_stability_check(tcx, id, t.trait_ref.path.span, cb);
-                }
-            }
-        }
-        ast::ItemImpl(_, _, _, Some(ref t), _, _) => {
-            let id = ty::trait_ref_to_def_id(tcx, t);
-            maybe_do_stability_check(tcx, id, t.path.span, cb);
-        }
         _ => (/* pass */)
     }
 }
@@ -325,15 +325,8 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
                   cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
     if is_internal(tcx, e.span) { return; }
 
-    let mut span = e.span;
-
+    let span;
     let id = match e.node {
-        ast::ExprPath(..) | ast::ExprQPath(..) | ast::ExprStruct(..) => {
-            match tcx.def_map.borrow().get(&e.id) {
-                Some(&def) => def.def_id(),
-                None => return
-            }
-        }
         ast::ExprMethodCall(i, _, _) => {
             span = i.span;
             let method_call = ty::MethodCall::expr(e.id);
@@ -369,6 +362,16 @@ pub fn check_expr(tcx: &ty::ctxt, e: &ast::Expr,
     maybe_do_stability_check(tcx, id, span, cb);
 }
 
+pub fn check_path(tcx: &ty::ctxt, path: &ast::Path, id: ast::NodeId,
+                  cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
+    let did = match tcx.def_map.borrow().get(&id) {
+        Some(&def::DefPrimTy(..)) => return,
+        Some(def) => def.def_id(),
+        None => return
+    };
+    maybe_do_stability_check(tcx, did, path.span, cb)
+}
+
 fn maybe_do_stability_check(tcx: &ty::ctxt, id: ast::DefId, span: Span,
                             cb: &mut FnMut(ast::DefId, Span, &Option<Stability>)) {
     if !is_staged_api(tcx, id) { return  }
diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs
index 8cb0447e732..e20968a9ac9 100644
--- a/src/librustc/middle/subst.rs
+++ b/src/librustc/middle/subst.rs
@@ -18,6 +18,7 @@ use middle::ty_fold::{self, TypeFoldable, TypeFolder};
 use util::ppaux::Repr;
 
 use std::fmt;
+use std::iter::IntoIterator;
 use std::slice::Iter;
 use std::vec::{Vec, IntoIter};
 use syntax::codemap::{Span, DUMMY_SP};
@@ -529,6 +530,23 @@ impl<'a,T> Iterator for EnumeratedItems<'a,T> {
     }
 }
 
+impl<T> IntoIterator for VecPerParamSpace<T> {
+    type IntoIter = IntoIter<T>;
+
+    fn into_iter(self) -> IntoIter<T> {
+        self.into_vec().into_iter()
+    }
+}
+
+impl<'a,T> IntoIterator for &'a VecPerParamSpace<T> {
+    type IntoIter = Iter<'a, T>;
+
+    fn into_iter(self) -> Iter<'a, T> {
+        self.as_slice().into_iter()
+    }
+}
+
+
 ///////////////////////////////////////////////////////////////////////////
 // Public trait `Subst`
 //
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index f69bf31626f..395e486059e 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -63,7 +63,7 @@ mod util;
 /// either identifying an `impl` (e.g., `impl Eq for int`) that
 /// provides the required vtable, or else finding a bound that is in
 /// scope. The eventual result is usually a `Selection` (defined below).
-#[derive(Clone)]
+#[derive(Clone, PartialEq, Eq)]
 pub struct Obligation<'tcx, T> {
     pub cause: ObligationCause<'tcx>,
     pub recursion_depth: uint,
@@ -74,7 +74,7 @@ pub type PredicateObligation<'tcx> = Obligation<'tcx, ty::Predicate<'tcx>>;
 pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>;
 
 /// Why did we incur this obligation? Used for error reporting.
-#[derive(Clone)]
+#[derive(Clone, PartialEq, Eq)]
 pub struct ObligationCause<'tcx> {
     pub span: Span,
 
@@ -89,7 +89,7 @@ pub struct ObligationCause<'tcx> {
     pub code: ObligationCauseCode<'tcx>
 }
 
-#[derive(Clone)]
+#[derive(Clone, PartialEq, Eq)]
 pub enum ObligationCauseCode<'tcx> {
     /// Not well classified or should be obvious from span.
     MiscObligation,
@@ -129,7 +129,7 @@ pub enum ObligationCauseCode<'tcx> {
     CompareImplMethodObligation,
 }
 
-#[derive(Clone)]
+#[derive(Clone, PartialEq, Eq)]
 pub struct DerivedObligationCause<'tcx> {
     /// The trait reference of the parent obligation that led to the
     /// current obligation. Note that only trait obligations lead to
@@ -251,7 +251,7 @@ pub enum Vtable<'tcx, N> {
 /// is `Obligation`, as one might expect. During trans, however, this
 /// is `()`, because trans only requires a shallow resolution of an
 /// impl, and nested obligations are satisfied later.
-#[derive(Clone)]
+#[derive(Clone, PartialEq, Eq)]
 pub struct VtableImplData<'tcx, N> {
     pub impl_def_id: ast::DefId,
     pub substs: subst::Substs<'tcx>,
@@ -283,7 +283,7 @@ pub fn overlapping_impls(infcx: &InferCtxt,
 /// Creates predicate obligations from the generic bounds.
 pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
                                      cause: ObligationCause<'tcx>,
-                                     generic_bounds: &ty::GenericBounds<'tcx>)
+                                     generic_bounds: &ty::InstantiatedPredicates<'tcx>)
                                      -> PredicateObligations<'tcx>
 {
     util::predicates_for_generics(tcx, cause, 0, generic_bounds)
diff --git a/src/librustc/middle/traits/object_safety.rs b/src/librustc/middle/traits/object_safety.rs
index c88e58266a0..b2701ae875c 100644
--- a/src/librustc/middle/traits/object_safety.rs
+++ b/src/librustc/middle/traits/object_safety.rs
@@ -130,7 +130,10 @@ fn trait_has_sized_self<'tcx>(tcx: &ty::ctxt<'tcx>,
     // Search for a predicate like `Self : Sized` amongst the trait bounds.
     let trait_def = ty::lookup_trait_def(tcx, trait_def_id);
     let free_substs = ty::construct_free_substs(tcx, &trait_def.generics, ast::DUMMY_NODE_ID);
-    let predicates = trait_def.generics.to_bounds(tcx, &free_substs).predicates.into_vec();
+
+    let trait_predicates = ty::lookup_predicates(tcx, trait_def_id);
+    let predicates = trait_predicates.instantiate(tcx, &free_substs).predicates.into_vec();
+
     elaborate_predicates(tcx, predicates)
         .any(|predicate| {
             match predicate {
diff --git a/src/librustc/middle/traits/project.rs b/src/librustc/middle/traits/project.rs
index 9d3ad28e613..13f309e129a 100644
--- a/src/librustc/middle/traits/project.rs
+++ b/src/librustc/middle/traits/project.rs
@@ -54,6 +54,7 @@ pub struct MismatchedProjectionTypes<'tcx> {
     pub err: ty::type_err<'tcx>
 }
 
+#[derive(PartialEq, Eq)]
 enum ProjectionTyCandidate<'tcx> {
     ParamEnv(ty::PolyProjectionPredicate<'tcx>),
     Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
@@ -481,6 +482,25 @@ fn project_type<'cx,'tcx>(
 
     // We probably need some winnowing logic similar to select here.
 
+    // Drop duplicates.
+    //
+    // Note: `candidates.vec` seems to be on the critical path of the
+    // compiler. Replacing it with an hash set was also tried, which would
+    // render the following dedup unnecessary. It led to cleaner code but
+    // prolonged compiling time of `librustc` from 5m30s to 6m in one test, or
+    // ~9% performance lost.
+    if candidates.vec.len() > 1 {
+        let mut i = 0;
+        while i < candidates.vec.len() {
+            let has_dup = (0..i).any(|j| candidates.vec[i] == candidates.vec[j]);
+            if has_dup {
+                candidates.vec.swap_remove(i);
+            } else {
+                i += 1;
+            }
+        }
+    }
+
     if candidates.ambiguous || candidates.vec.len() > 1 {
         return Err(ProjectionTyError::TooManyCandidates);
     }
@@ -541,8 +561,8 @@ fn assemble_candidates_from_trait_def<'cx,'tcx>(
     };
 
     // If so, extract what we know from the trait and try to come up with a good answer.
-    let trait_def = ty::lookup_trait_def(selcx.tcx(), trait_ref.def_id);
-    let bounds = trait_def.generics.to_bounds(selcx.tcx(), trait_ref.substs);
+    let trait_predicates = ty::lookup_predicates(selcx.tcx(), trait_ref.def_id);
+    let bounds = trait_predicates.instantiate(selcx.tcx(), trait_ref.substs);
     assemble_candidates_from_predicates(selcx, obligation, obligation_trait_ref,
                                         candidate_set, bounds.predicates.into_vec());
 }
diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs
index 5323a322436..5f659aa303e 100644
--- a/src/librustc/middle/traits/select.rs
+++ b/src/librustc/middle/traits/select.rs
@@ -923,8 +923,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 projection_trait_ref={}",
                projection_trait_ref.repr(self.tcx()));
 
-        let trait_def = ty::lookup_trait_def(self.tcx(), projection_trait_ref.def_id);
-        let bounds = trait_def.generics.to_bounds(self.tcx(), projection_trait_ref.substs);
+        let trait_predicates = ty::lookup_predicates(self.tcx(), projection_trait_ref.def_id);
+        let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs);
         debug!("match_projection_obligation_against_bounds_from_trait: \
                 bounds={}",
                bounds.repr(self.tcx()));
@@ -2314,8 +2314,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         snapshot: &infer::CombinedSnapshot)
                         -> VecPerParamSpace<PredicateObligation<'tcx>>
     {
-        let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics;
-        let bounds = impl_generics.to_bounds(self.tcx(), impl_substs);
+        let impl_bounds = ty::lookup_predicates(self.tcx(), impl_def_id);
+        let bounds = impl_bounds.instantiate(self.tcx(), impl_substs);
         let normalized_bounds =
             project::normalize_with_depth(self, cause.clone(), recursion_depth, &bounds);
         let normalized_bounds =
diff --git a/src/librustc/middle/traits/util.rs b/src/librustc/middle/traits/util.rs
index 573efa72756..6c54da1c134 100644
--- a/src/librustc/middle/traits/util.rs
+++ b/src/librustc/middle/traits/util.rs
@@ -290,7 +290,7 @@ impl<'tcx> fmt::Debug for super::VtableObjectData<'tcx> {
 pub fn predicates_for_generics<'tcx>(tcx: &ty::ctxt<'tcx>,
                                      cause: ObligationCause<'tcx>,
                                      recursion_depth: uint,
-                                     generic_bounds: &ty::GenericBounds<'tcx>)
+                                     generic_bounds: &ty::InstantiatedPredicates<'tcx>)
                                      -> VecPerParamSpace<PredicateObligation<'tcx>>
 {
     debug!("predicates_for_generics(generic_bounds={})",
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 97e6517a615..6026359ddac 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -72,6 +72,8 @@ use std::cell::{Cell, RefCell};
 use std::cmp;
 use std::fmt;
 use std::hash::{Hash, Writer, SipHasher, Hasher};
+#[cfg(stage0)]
+use std::marker;
 use std::mem;
 use std::ops;
 use std::rc::Rc;
@@ -190,7 +192,8 @@ impl ImplOrTraitItemId {
 #[derive(Clone, Debug)]
 pub struct Method<'tcx> {
     pub name: ast::Name,
-    pub generics: ty::Generics<'tcx>,
+    pub generics: Generics<'tcx>,
+    pub predicates: GenericPredicates<'tcx>,
     pub fty: BareFnTy<'tcx>,
     pub explicit_self: ExplicitSelfCategory,
     pub vis: ast::Visibility,
@@ -204,6 +207,7 @@ pub struct Method<'tcx> {
 impl<'tcx> Method<'tcx> {
     pub fn new(name: ast::Name,
                generics: ty::Generics<'tcx>,
+               predicates: GenericPredicates<'tcx>,
                fty: BareFnTy<'tcx>,
                explicit_self: ExplicitSelfCategory,
                vis: ast::Visibility,
@@ -214,6 +218,7 @@ impl<'tcx> Method<'tcx> {
        Method {
             name: name,
             generics: generics,
+            predicates: predicates,
             fty: fty,
             explicit_self: explicit_self,
             vis: vis,
@@ -708,6 +713,10 @@ pub struct ctxt<'tcx> {
     pub trait_refs: RefCell<NodeMap<Rc<TraitRef<'tcx>>>>,
     pub trait_defs: RefCell<DefIdMap<Rc<TraitDef<'tcx>>>>,
 
+    /// Maps from the def-id of an item (trait/struct/enum/fn) to its
+    /// associated predicates.
+    pub predicates: RefCell<DefIdMap<GenericPredicates<'tcx>>>,
+
     /// Maps from node-id of a trait object cast (like `foo as
     /// Box<Trait>`) to the trait reference.
     pub object_cast_map: ObjectCastMap<'tcx>,
@@ -931,6 +940,26 @@ pub struct TyS<'tcx> {
 
     // the maximal depth of any bound regions appearing in this type.
     region_depth: u32,
+
+    // force the lifetime to be invariant to work-around
+    // region-inference issues with a covariant lifetime.
+    #[cfg(stage0)]
+    marker: ShowInvariantLifetime<'tcx>,
+}
+
+#[cfg(stage0)]
+struct ShowInvariantLifetime<'a>(marker::InvariantLifetime<'a>);
+#[cfg(stage0)]
+impl<'a> ShowInvariantLifetime<'a> {
+    fn new() -> ShowInvariantLifetime<'a> {
+        ShowInvariantLifetime(marker::InvariantLifetime)
+    }
+}
+#[cfg(stage0)]
+impl<'a> fmt::Debug for ShowInvariantLifetime<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "InvariantLifetime")
+    }
 }
 
 impl fmt::Debug for TypeFlags {
@@ -939,11 +968,20 @@ impl fmt::Debug for TypeFlags {
     }
 }
 
+#[cfg(stage0)]
 impl<'tcx> PartialEq for TyS<'tcx> {
-    fn eq(&self, other: &TyS<'tcx>) -> bool {
+    fn eq<'a,'b>(&'a self, other: &'b TyS<'tcx>) -> bool {
+        let other: &'a TyS<'tcx> = unsafe { mem::transmute(other) };
         (self as *const _) == (other as *const _)
     }
 }
+#[cfg(not(stage0))]
+impl<'tcx> PartialEq for TyS<'tcx> {
+    fn eq(&self, other: &TyS<'tcx>) -> bool {
+        // (self as *const _) == (other as *const _)
+        (self as *const TyS<'tcx>) == (other as *const TyS<'tcx>)
+    }
+}
 impl<'tcx> Eq for TyS<'tcx> {}
 
 impl<'tcx, S: Writer + Hasher> Hash<S> for TyS<'tcx> {
@@ -1174,7 +1212,9 @@ pub enum Region {
     /// region parameters.
     ReFree(FreeRegion),
 
-    /// A concrete region naming some expression within the current function.
+    /// A concrete region naming some statically determined extent
+    /// (e.g. an expression or sequence of statements) within the
+    /// current function.
     ReScope(region::CodeExtent),
 
     /// Static data that has an "infinite" lifetime. Top in the region lattice.
@@ -1296,7 +1336,7 @@ impl Region {
 /// A "free" region `fr` can be interpreted as "some region
 /// at least as big as the scope `fr.scope`".
 pub struct FreeRegion {
-    pub scope: region::CodeExtent,
+    pub scope: region::DestructionScopeData,
     pub bound_region: BoundRegion
 }
 
@@ -1749,7 +1789,6 @@ impl RegionParameterDef {
 pub struct Generics<'tcx> {
     pub types: VecPerParamSpace<TypeParameterDef<'tcx>>,
     pub regions: VecPerParamSpace<RegionParameterDef>,
-    pub predicates: VecPerParamSpace<Predicate<'tcx>>,
 }
 
 impl<'tcx> Generics<'tcx> {
@@ -1757,10 +1796,13 @@ impl<'tcx> Generics<'tcx> {
         Generics {
             types: VecPerParamSpace::empty(),
             regions: VecPerParamSpace::empty(),
-            predicates: VecPerParamSpace::empty(),
         }
     }
 
+    pub fn is_empty(&self) -> bool {
+        self.types.is_empty() && self.regions.is_empty()
+    }
+
     pub fn has_type_params(&self, space: subst::ParamSpace) -> bool {
         !self.types.is_empty_in(space)
     }
@@ -1768,14 +1810,24 @@ impl<'tcx> Generics<'tcx> {
     pub fn has_region_params(&self, space: subst::ParamSpace) -> bool {
         !self.regions.is_empty_in(space)
     }
+}
 
-    pub fn is_empty(&self) -> bool {
-        self.types.is_empty() && self.regions.is_empty()
+/// Bounds on generics.
+#[derive(Clone, Debug)]
+pub struct GenericPredicates<'tcx> {
+    pub predicates: VecPerParamSpace<Predicate<'tcx>>,
+}
+
+impl<'tcx> GenericPredicates<'tcx> {
+    pub fn empty() -> GenericPredicates<'tcx> {
+        GenericPredicates {
+            predicates: VecPerParamSpace::empty(),
+        }
     }
 
-    pub fn to_bounds(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>)
-                     -> GenericBounds<'tcx> {
-        GenericBounds {
+    pub fn instantiate(&self, tcx: &ty::ctxt<'tcx>, substs: &Substs<'tcx>)
+                       -> InstantiatedPredicates<'tcx> {
+        InstantiatedPredicates {
             predicates: self.predicates.subst(tcx, substs),
         }
     }
@@ -1989,11 +2041,11 @@ impl<'tcx> Predicate<'tcx> {
 
 /// Represents the bounds declared on a particular set of type
 /// parameters.  Should eventually be generalized into a flag list of
-/// where clauses.  You can obtain a `GenericBounds` list from a
-/// `Generics` by using the `to_bounds` method. Note that this method
-/// reflects an important semantic invariant of `GenericBounds`: while
-/// the bounds in a `Generics` are expressed in terms of the bound type
-/// parameters of the impl/trait/whatever, a `GenericBounds` instance
+/// where clauses.  You can obtain a `InstantiatedPredicates` list from a
+/// `GenericPredicates` by using the `instantiate` method. Note that this method
+/// reflects an important semantic invariant of `InstantiatedPredicates`: while
+/// the `GenericPredicates` are expressed in terms of the bound type
+/// parameters of the impl/trait/whatever, an `InstantiatedPredicates` instance
 /// represented a set of bounds for some particular instantiation,
 /// meaning that the generic parameters have been substituted with
 /// their values.
@@ -2002,18 +2054,18 @@ impl<'tcx> Predicate<'tcx> {
 ///
 ///     struct Foo<T,U:Bar<T>> { ... }
 ///
-/// Here, the `Generics` for `Foo` would contain a list of bounds like
+/// Here, the `GenericPredicates` for `Foo` would contain a list of bounds like
 /// `[[], [U:Bar<T>]]`.  Now if there were some particular reference
-/// like `Foo<int,uint>`, then the `GenericBounds` would be `[[],
+/// like `Foo<int,uint>`, then the `InstantiatedPredicates` would be `[[],
 /// [uint:Bar<int>]]`.
 #[derive(Clone, Debug)]
-pub struct GenericBounds<'tcx> {
+pub struct InstantiatedPredicates<'tcx> {
     pub predicates: VecPerParamSpace<Predicate<'tcx>>,
 }
 
-impl<'tcx> GenericBounds<'tcx> {
-    pub fn empty() -> GenericBounds<'tcx> {
-        GenericBounds { predicates: VecPerParamSpace::empty() }
+impl<'tcx> InstantiatedPredicates<'tcx> {
+    pub fn empty() -> InstantiatedPredicates<'tcx> {
+        InstantiatedPredicates { predicates: VecPerParamSpace::empty() }
     }
 
     pub fn has_escaping_regions(&self) -> bool {
@@ -2101,10 +2153,12 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                         match ty::impl_or_trait_item(cx, method_def_id) {
                             MethodTraitItem(ref method_ty) => {
                                 let method_generics = &method_ty.generics;
+                                let method_bounds = &method_ty.predicates;
                                 construct_parameter_environment(
                                     cx,
                                     method.span,
                                     method_generics,
+                                    method_bounds,
                                     method.pe_body().id)
                             }
                             TypeTraitItem(_) => {
@@ -2136,10 +2190,12 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                         match ty::impl_or_trait_item(cx, method_def_id) {
                             MethodTraitItem(ref method_ty) => {
                                 let method_generics = &method_ty.generics;
+                                let method_bounds = &method_ty.predicates;
                                 construct_parameter_environment(
                                     cx,
                                     method.span,
                                     method_generics,
+                                    method_bounds,
                                     method.pe_body().id)
                             }
                             TypeTraitItem(_) => {
@@ -2162,11 +2218,13 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                     ast::ItemFn(_, _, _, _, ref body) => {
                         // We assume this is a function.
                         let fn_def_id = ast_util::local_def(id);
-                        let fn_pty = ty::lookup_item_type(cx, fn_def_id);
+                        let fn_scheme = lookup_item_type(cx, fn_def_id);
+                        let fn_predicates = lookup_predicates(cx, fn_def_id);
 
                         construct_parameter_environment(cx,
                                                         item.span,
-                                                        &fn_pty.generics,
+                                                        &fn_scheme.generics,
+                                                        &fn_predicates,
                                                         body.id)
                     }
                     ast::ItemEnum(..) |
@@ -2175,8 +2233,13 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
                     ast::ItemConst(..) |
                     ast::ItemStatic(..) => {
                         let def_id = ast_util::local_def(id);
-                        let pty = ty::lookup_item_type(cx, def_id);
-                        construct_parameter_environment(cx, item.span, &pty.generics, id)
+                        let scheme = lookup_item_type(cx, def_id);
+                        let predicates = lookup_predicates(cx, def_id);
+                        construct_parameter_environment(cx,
+                                                        item.span,
+                                                        &scheme.generics,
+                                                        &predicates,
+                                                        id)
                     }
                     _ => {
                         cx.sess.span_bug(item.span,
@@ -2215,10 +2278,13 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
 /// stray references in a comment or something). We try to reserve the
 /// "poly" prefix to refer to higher-ranked things, as in
 /// `PolyTraitRef`.
+///
+/// Note that each item also comes with predicates, see
+/// `lookup_predicates`.
 #[derive(Clone, Debug)]
 pub struct TypeScheme<'tcx> {
     pub generics: Generics<'tcx>,
-    pub ty: Ty<'tcx>
+    pub ty: Ty<'tcx>,
 }
 
 /// As `TypeScheme` but for a trait ref.
@@ -2360,6 +2426,7 @@ pub fn mk_ctxt<'tcx>(s: Session,
         item_substs: RefCell::new(NodeMap()),
         trait_refs: RefCell::new(NodeMap()),
         trait_defs: RefCell::new(DefIdMap()),
+        predicates: RefCell::new(DefIdMap()),
         object_cast_map: RefCell::new(NodeMap()),
         map: map,
         intrinsic_defs: RefCell::new(DefIdMap()),
@@ -2473,11 +2540,17 @@ fn intern_ty<'tcx>(type_arena: &'tcx TypedArena<TyS<'tcx>>,
 
     let flags = FlagComputation::for_sty(&st);
 
-    let ty = type_arena.alloc(TyS {
-        sty: st,
-        flags: flags.flags,
-        region_depth: flags.depth,
-    });
+    let ty = match () {
+        #[cfg(stage0)]
+        () => type_arena.alloc(TyS { sty: st,
+                                     flags: flags.flags,
+                                     region_depth: flags.depth,
+                                     marker: ShowInvariantLifetime::new(), }),
+        #[cfg(not(stage0))]
+        () => type_arena.alloc(TyS { sty: st,
+                                     flags: flags.flags,
+                                     region_depth: flags.depth, }),
+    };
 
     debug!("Interned type: {:?} Pointer: {:?}",
            ty, ty as *const _);
@@ -4192,12 +4265,16 @@ pub fn ty_region(tcx: &ctxt,
     }
 }
 
-pub fn free_region_from_def(free_id: ast::NodeId, def: &RegionParameterDef)
+pub fn free_region_from_def(outlives_extent: region::DestructionScopeData,
+                            def: &RegionParameterDef)
     -> ty::Region
 {
-    ty::ReFree(ty::FreeRegion { scope: region::CodeExtent::from_node_id(free_id),
-                                bound_region: ty::BrNamed(def.def_id,
-                                                          def.name) })
+    let ret =
+        ty::ReFree(ty::FreeRegion { scope: outlives_extent,
+                                    bound_region: ty::BrNamed(def.def_id,
+                                                              def.name) });
+    debug!("free_region_from_def returns {:?}", ret);
+    ret
 }
 
 // Returns the type of a pattern as a monotype. Like @expr_ty, this function
@@ -5335,13 +5412,23 @@ pub fn lookup_item_type<'tcx>(cx: &ctxt<'tcx>,
 
 /// Given the did of a trait, returns its canonical trait ref.
 pub fn lookup_trait_def<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
-                              -> Rc<ty::TraitDef<'tcx>> {
+                              -> Rc<TraitDef<'tcx>> {
     memoized(&cx.trait_defs, did, |did: DefId| {
         assert!(did.krate != ast::LOCAL_CRATE);
         Rc::new(csearch::get_trait_def(cx, did))
     })
 }
 
+/// Given the did of a trait, returns its full set of predicates.
+pub fn lookup_predicates<'tcx>(cx: &ctxt<'tcx>, did: ast::DefId)
+                                -> GenericPredicates<'tcx>
+{
+    memoized(&cx.predicates, did, |did: DefId| {
+        assert!(did.krate != ast::LOCAL_CRATE);
+        csearch::get_predicates(cx, did)
+    })
+}
+
 /// Given a reference to a trait, returns the "superbounds" declared
 /// on the trait, with appropriate substitutions applied. Basically,
 /// this applies a filter to the where clauses on the trait, returning
@@ -6244,7 +6331,7 @@ pub fn empty_parameter_environment<'a,'tcx>(cx: &'a ctxt<'tcx>) -> ParameterEnvi
 /// parameters in the same way, this only has an effect on regions.
 pub fn construct_free_substs<'a,'tcx>(
     tcx: &'a ctxt<'tcx>,
-    generics: &ty::Generics<'tcx>,
+    generics: &Generics<'tcx>,
     free_id: ast::NodeId)
     -> Substs<'tcx>
 {
@@ -6252,9 +6339,11 @@ pub fn construct_free_substs<'a,'tcx>(
     let mut types = VecPerParamSpace::empty();
     push_types_from_defs(tcx, &mut types, generics.types.as_slice());
 
+    let free_id_outlive = region::DestructionScopeData::new(free_id);
+
     // map bound 'a => free 'a
     let mut regions = VecPerParamSpace::empty();
-    push_region_params(&mut regions, free_id, generics.regions.as_slice());
+    push_region_params(&mut regions, free_id_outlive, generics.regions.as_slice());
 
     return Substs {
         types: types,
@@ -6262,11 +6351,11 @@ pub fn construct_free_substs<'a,'tcx>(
     };
 
     fn push_region_params(regions: &mut VecPerParamSpace<ty::Region>,
-                          free_id: ast::NodeId,
+                          all_outlive_extent: region::DestructionScopeData,
                           region_params: &[RegionParameterDef])
     {
         for r in region_params {
-            regions.push(r.space, ty::free_region_from_def(free_id, r));
+            regions.push(r.space, ty::free_region_from_def(all_outlive_extent, r));
         }
     }
 
@@ -6287,6 +6376,7 @@ pub fn construct_parameter_environment<'a,'tcx>(
     tcx: &'a ctxt<'tcx>,
     span: Span,
     generics: &ty::Generics<'tcx>,
+    generic_predicates: &ty::GenericPredicates<'tcx>,
     free_id: ast::NodeId)
     -> ParameterEnvironment<'a, 'tcx>
 {
@@ -6295,14 +6385,14 @@ pub fn construct_parameter_environment<'a,'tcx>(
     //
 
     let free_substs = construct_free_substs(tcx, generics, free_id);
-    let free_id_scope = region::CodeExtent::from_node_id(free_id);
+    let free_id_outlive = region::DestructionScopeData::new(free_id);
 
     //
     // Compute the bounds on Self and the type parameters.
     //
 
-    let bounds = generics.to_bounds(tcx, &free_substs);
-    let bounds = liberate_late_bound_regions(tcx, free_id_scope, &ty::Binder(bounds));
+    let bounds = generic_predicates.instantiate(tcx, &free_substs);
+    let bounds = liberate_late_bound_regions(tcx, free_id_outlive, &ty::Binder(bounds));
     let predicates = bounds.predicates.into_vec();
 
     //
@@ -6335,7 +6425,7 @@ pub fn construct_parameter_environment<'a,'tcx>(
     let unnormalized_env = ty::ParameterEnvironment {
         tcx: tcx,
         free_substs: free_substs,
-        implicit_region_bound: ty::ReScope(free_id_scope),
+        implicit_region_bound: ty::ReScope(free_id_outlive.to_code_extent()),
         caller_bounds: predicates,
         selection_cache: traits::SelectionCache::new(),
     };
@@ -6603,14 +6693,14 @@ impl<'tcx> AutoDerefRef<'tcx> {
 /// `scope_id`.
 pub fn liberate_late_bound_regions<'tcx, T>(
     tcx: &ty::ctxt<'tcx>,
-    scope: region::CodeExtent,
+    all_outlive_scope: region::DestructionScopeData,
     value: &Binder<T>)
     -> T
     where T : TypeFoldable<'tcx> + Repr<'tcx>
 {
     replace_late_bound_regions(
         tcx, value,
-        |br| ty::ReFree(ty::FreeRegion{scope: scope, bound_region: br})).0
+        |br| ty::ReFree(ty::FreeRegion{scope: all_outlive_scope, bound_region: br})).0
 }
 
 pub fn count_late_bound_regions<'tcx, T>(
@@ -6935,8 +7025,7 @@ impl<'tcx,T:RegionEscape> RegionEscape for VecPerParamSpace<T> {
 
 impl<'tcx> RegionEscape for TypeScheme<'tcx> {
     fn has_regions_escaping_depth(&self, depth: u32) -> bool {
-        self.ty.has_regions_escaping_depth(depth) ||
-            self.generics.has_regions_escaping_depth(depth)
+        self.ty.has_regions_escaping_depth(depth)
     }
 }
 
@@ -6946,7 +7035,7 @@ impl RegionEscape for Region {
     }
 }
 
-impl<'tcx> RegionEscape for Generics<'tcx> {
+impl<'tcx> RegionEscape for GenericPredicates<'tcx> {
     fn has_regions_escaping_depth(&self, depth: u32) -> bool {
         self.predicates.has_regions_escaping_depth(depth)
     }
@@ -7055,7 +7144,7 @@ impl<'tcx> HasProjectionTypes for ClosureUpvar<'tcx> {
     }
 }
 
-impl<'tcx> HasProjectionTypes for ty::GenericBounds<'tcx> {
+impl<'tcx> HasProjectionTypes for ty::InstantiatedPredicates<'tcx> {
     fn has_projection_types(&self) -> bool {
         self.predicates.has_projection_types()
     }
diff --git a/src/librustc/middle/ty_fold.rs b/src/librustc/middle/ty_fold.rs
index 69d32c3f5fc..645a7ab9440 100644
--- a/src/librustc/middle/ty_fold.rs
+++ b/src/librustc/middle/ty_fold.rs
@@ -400,6 +400,13 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
         ty::Generics {
             types: self.types.fold_with(folder),
             regions: self.regions.fold_with(folder),
+        }
+    }
+}
+
+impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::GenericPredicates<'tcx> {
+        ty::GenericPredicates {
             predicates: self.predicates.fold_with(folder),
         }
     }
@@ -440,9 +447,9 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ProjectionTy<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::GenericBounds<'tcx> {
-    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::GenericBounds<'tcx> {
-        ty::GenericBounds {
+impl<'tcx> TypeFoldable<'tcx> for ty::InstantiatedPredicates<'tcx> {
+    fn fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> ty::InstantiatedPredicates<'tcx> {
+        ty::InstantiatedPredicates {
             predicates: self.predicates.fold_with(folder),
         }
     }
diff --git a/src/librustc/plugin/load.rs b/src/librustc/plugin/load.rs
index a2ce474eda8..b46454bfdd0 100644
--- a/src/librustc/plugin/load.rs
+++ b/src/librustc/plugin/load.rs
@@ -17,7 +17,7 @@ use plugin::registry::Registry;
 use std::mem;
 use std::env;
 use std::dynamic_lib::DynamicLibrary;
-use std::collections::HashSet;
+use std::collections::{HashSet, HashMap};
 use std::borrow::ToOwned;
 use syntax::ast;
 use syntax::attr;
@@ -116,6 +116,8 @@ pub fn load_plugins(sess: &Session, krate: &ast::Crate,
     return loader.plugins;
 }
 
+pub type MacroSelection = HashMap<token::InternedString, Span>;
+
 // note that macros aren't expanded yet, and therefore macros can't add plugins.
 impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
     fn visit_item(&mut self, item: &ast::Item) {
@@ -128,9 +130,9 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
             }
         }
 
-        // Parse the attributes relating to macro / plugin loading.
-        let mut macro_selection = Some(HashSet::new());  // None => load all
-        let mut reexport = HashSet::new();
+        // Parse the attributes relating to macro loading.
+        let mut import = Some(HashMap::new());  // None => load all
+        let mut reexport = HashMap::new();
         for attr in &item.attrs {
             let mut used = true;
             match &attr.name()[] {
@@ -147,14 +149,14 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
                     let names = attr.meta_item_list();
                     if names.is_none() {
                         // no names => load all
-                        macro_selection = None;
+                        import = None;
                     }
-                    if let (Some(sel), Some(names)) = (macro_selection.as_mut(), names) {
-                        for name in names {
-                            if let ast::MetaWord(ref name) = name.node {
-                                sel.insert(name.clone());
+                    if let (Some(sel), Some(names)) = (import.as_mut(), names) {
+                        for attr in names {
+                            if let ast::MetaWord(ref name) = attr.node {
+                                sel.insert(name.clone(), attr.span);
                             } else {
-                                self.sess.span_err(name.span, "bad macro import");
+                                self.sess.span_err(attr.span, "bad macro import");
                             }
                         }
                     }
@@ -168,11 +170,11 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
                         }
                     };
 
-                    for name in names {
-                        if let ast::MetaWord(ref name) = name.node {
-                            reexport.insert(name.clone());
+                    for attr in names {
+                        if let ast::MetaWord(ref name) = attr.node {
+                            reexport.insert(name.clone(), attr.span);
                         } else {
-                            self.sess.span_err(name.span, "bad macro reexport");
+                            self.sess.span_err(attr.span, "bad macro reexport");
                         }
                     }
                 }
@@ -183,7 +185,7 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
             }
         }
 
-        self.load_macros(item, macro_selection, Some(reexport))
+        self.load_macros(item, import, reexport)
     }
 
     fn visit_mac(&mut self, _: &ast::Mac) {
@@ -195,10 +197,10 @@ impl<'a, 'v> Visitor<'v> for PluginLoader<'a> {
 impl<'a> PluginLoader<'a> {
     pub fn load_macros<'b>(&mut self,
                            vi: &ast::Item,
-                           macro_selection: Option<HashSet<token::InternedString>>,
-                           reexport: Option<HashSet<token::InternedString>>) {
-        if let (Some(sel), Some(re)) = (macro_selection.as_ref(), reexport.as_ref()) {
-            if sel.is_empty() && re.is_empty() {
+                           import: Option<MacroSelection>,
+                           reexport: MacroSelection) {
+        if let Some(sel) = import.as_ref() {
+            if sel.is_empty() && reexport.is_empty() {
                 return;
             }
         }
@@ -211,19 +213,32 @@ impl<'a> PluginLoader<'a> {
 
         let pmd = self.reader.read_plugin_metadata(CrateOrString::Krate(vi));
 
+        let mut seen = HashSet::new();
         for mut def in pmd.exported_macros() {
             let name = token::get_ident(def.ident);
-            def.use_locally = match macro_selection.as_ref() {
+            seen.insert(name.clone());
+
+            def.use_locally = match import.as_ref() {
                 None => true,
-                Some(sel) => sel.contains(&name),
-            };
-            def.export = if let Some(ref re) = reexport {
-                re.contains(&name)
-            } else {
-                false // Don't reexport macros from crates loaded from the command line
+                Some(sel) => sel.contains_key(&name),
             };
+            def.export = reexport.contains_key(&name);
             self.plugins.macros.push(def);
         }
+
+        if let Some(sel) = import.as_ref() {
+            for (name, span) in sel.iter() {
+                if !seen.contains(name) {
+                    self.sess.span_err(*span, "imported macro not found");
+                }
+            }
+        }
+
+        for (name, span) in reexport.iter() {
+            if !seen.contains(name) {
+                self.sess.span_err(*span, "reexported macro not found");
+            }
+        }
     }
 
     pub fn load_plugin<'b>(&mut self,
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 949fee45517..8340a49b92a 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1052,7 +1052,7 @@ pub fn get_unstable_features_setting() -> UnstableFeatures {
     // subverting the unstable features lints
     let bootstrap_secret_key = option_env!("CFG_BOOTSTRAP_KEY");
     // The matching key to the above, only known by the build system
-    let bootstrap_provided_key = env::var_string("RUSTC_BOOTSTRAP_KEY").ok();
+    let bootstrap_provided_key = env::var("RUSTC_BOOTSTRAP_KEY").ok();
     match (disable_unstable_features, bootstrap_secret_key, bootstrap_provided_key) {
         (_, Some(ref s), Some(ref p)) if s == p => UnstableFeatures::Cheat,
         (true, _, _) => UnstableFeatures::Disallow,
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index c72b7fdf7ad..0363978bada 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -113,6 +113,10 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
         };
         let scope_decorated_tag = match scope {
             region::CodeExtent::Misc(_) => tag,
+            region::CodeExtent::DestructionScope(_) => {
+                new_string = format!("destruction scope surrounding {}", tag);
+                new_string.as_slice()
+            }
             region::CodeExtent::Remainder(r) => {
                 new_string = format!("block suffix following statement {}",
                                      r.first_statement_index);
@@ -135,7 +139,7 @@ pub fn explain_region_and_span(cx: &ctxt, region: ty::Region)
           }
         };
 
-        match cx.map.find(fr.scope.node_id()) {
+        match cx.map.find(fr.scope.node_id) {
           Some(ast_map::NodeBlock(ref blk)) => {
               let (msg, opt_span) = explain_span(cx, "block", blk.span);
               (format!("{} {}", prefix, msg), opt_span)
@@ -391,8 +395,8 @@ pub fn ty_to_string<'tcx>(cx: &ctxt<'tcx>, typ: &ty::TyS<'tcx>) -> String {
         }
         ty_enum(did, substs) | ty_struct(did, substs) => {
             let base = ty::item_path_str(cx, did);
-            let generics = ty::lookup_item_type(cx, did).generics;
-            parameterized(cx, &base, substs, &generics, did, &[])
+            parameterized(cx, &base, substs, did, &[],
+                          || ty::lookup_item_type(cx, did).generics)
         }
         ty_trait(ref data) => {
             data.user_string(cx)
@@ -440,23 +444,40 @@ pub fn explicit_self_category_to_str(category: &ty::ExplicitSelfCategory)
     }
 }
 
-pub fn parameterized<'tcx>(cx: &ctxt<'tcx>,
-                           base: &str,
-                           substs: &subst::Substs<'tcx>,
-                           generics: &ty::Generics<'tcx>,
-                           did: ast::DefId,
-                           projections: &[ty::ProjectionPredicate<'tcx>])
-                           -> String
+pub fn parameterized<'tcx,GG>(cx: &ctxt<'tcx>,
+                              base: &str,
+                              substs: &subst::Substs<'tcx>,
+                              did: ast::DefId,
+                              projections: &[ty::ProjectionPredicate<'tcx>],
+                              get_generics: GG)
+                              -> String
+    where GG : FnOnce() -> ty::Generics<'tcx>
 {
     if cx.sess.verbose() {
-        if substs.is_noop() {
-            return format!("{}", base);
-        } else {
-            return format!("{}<{},{}>",
-                           base,
-                           substs.regions.repr(cx),
-                           substs.types.repr(cx));
+        let mut strings = vec![];
+        match substs.regions {
+            subst::ErasedRegions => {
+                strings.push(format!(".."));
+            }
+            subst::NonerasedRegions(ref regions) => {
+                for region in regions.iter() {
+                    strings.push(region.repr(cx));
+                }
+            }
+        }
+        for ty in substs.types.iter() {
+            strings.push(ty.repr(cx));
         }
+        for projection in projections.iter() {
+            strings.push(format!("{}={}",
+                                 projection.projection_ty.item_name.user_string(cx),
+                                 projection.ty.user_string(cx)));
+        }
+        return if strings.is_empty() {
+            format!("{}", base)
+        } else {
+            format!("{}<{}>", base, strings.connect(","))
+        };
     }
 
     let mut strs = Vec::new();
@@ -480,6 +501,13 @@ pub fn parameterized<'tcx>(cx: &ctxt<'tcx>,
         }
     }
 
+    // It is important to execute this conditionally, only if -Z
+    // verbose is false. Otherwise, debug logs can sometimes cause
+    // ICEs trying to fetch the generics early in the pipeline. This
+    // is kind of a hacky workaround in that -Z verbose is required to
+    // avoid those ICEs.
+    let generics = get_generics();
+
     let tps = substs.types.get_slice(subst::TypeSpace);
     let ty_params = generics.types.get_slice(subst::TypeSpace);
     let has_defaults = ty_params.last().map_or(false, |def| def.default.is_some());
@@ -641,13 +669,12 @@ impl<'tcx> UserString<'tcx> for TraitAndProjections<'tcx> {
     fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
         let &(ref trait_ref, ref projection_bounds) = self;
         let base = ty::item_path_str(tcx, trait_ref.def_id);
-        let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id);
         parameterized(tcx,
                       &base,
                       trait_ref.substs,
-                      &trait_def.generics,
                       trait_ref.def_id,
-                      &projection_bounds[])
+                      &projection_bounds[],
+                      || ty::lookup_trait_def(tcx, trait_ref.def_id).generics.clone())
     }
 }
 
@@ -683,10 +710,9 @@ impl<'tcx> UserString<'tcx> for ty::TyTrait<'tcx> {
 }
 
 impl<'tcx> Repr<'tcx> for ty::TypeParameterDef<'tcx> {
-    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("TypeParameterDef({:?}, {}, {:?}/{})",
+    fn repr(&self, _tcx: &ctxt<'tcx>) -> String {
+        format!("TypeParameterDef({:?}, {:?}/{})",
                 self.def_id,
-                self.bounds.repr(tcx),
                 self.space,
                 self.index)
     }
@@ -777,11 +803,8 @@ impl<'tcx> Repr<'tcx> for ty::TraitRef<'tcx> {
         // to enumerate the `for<...>` etc because the debruijn index
         // tells you everything you need to know.
         let base = ty::item_path_str(tcx, self.def_id);
-        let trait_def = ty::lookup_trait_def(tcx, self.def_id);
-        format!("TraitRef({}, {})",
-                self.substs.self_ty().repr(tcx),
-                parameterized(tcx, &base, self.substs,
-                              &trait_def.generics, self.def_id, &[]))
+        parameterized(tcx, &base, self.substs, self.def_id, &[],
+                      || ty::lookup_trait_def(tcx, self.def_id).generics.clone())
     }
 }
 
@@ -921,7 +944,7 @@ impl<'tcx> UserString<'tcx> for ty::Region {
 impl<'tcx> Repr<'tcx> for ty::FreeRegion {
     fn repr(&self, tcx: &ctxt) -> String {
         format!("ReFree({}, {})",
-                self.scope.node_id(),
+                self.scope.repr(tcx),
                 self.bound_region.repr(tcx))
     }
 }
@@ -931,12 +954,23 @@ impl<'tcx> Repr<'tcx> for region::CodeExtent {
         match *self {
             region::CodeExtent::Misc(node_id) =>
                 format!("Misc({})", node_id),
+            region::CodeExtent::DestructionScope(node_id) =>
+                format!("DestructionScope({})", node_id),
             region::CodeExtent::Remainder(rem) =>
                 format!("Remainder({}, {})", rem.block, rem.first_statement_index),
         }
     }
 }
 
+impl<'tcx> Repr<'tcx> for region::DestructionScopeData {
+    fn repr(&self, _tcx: &ctxt) -> String {
+        match *self {
+            region::DestructionScopeData{ node_id } =>
+                format!("DestructionScopeData {{ node_id: {} }}", node_id),
+        }
+    }
+}
+
 impl<'tcx> Repr<'tcx> for ast::DefId {
     fn repr(&self, tcx: &ctxt) -> String {
         // Unfortunately, there seems to be no way to attempt to print
@@ -972,16 +1006,22 @@ impl<'tcx> Repr<'tcx> for ty::TypeScheme<'tcx> {
 
 impl<'tcx> Repr<'tcx> for ty::Generics<'tcx> {
     fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("Generics(types: {}, regions: {}, predicates: {})",
+        format!("Generics(types: {}, regions: {})",
                 self.types.repr(tcx),
-                self.regions.repr(tcx),
+                self.regions.repr(tcx))
+    }
+}
+
+impl<'tcx> Repr<'tcx> for ty::GenericPredicates<'tcx> {
+    fn repr(&self, tcx: &ctxt<'tcx>) -> String {
+        format!("GenericPredicates(predicates: {})",
                 self.predicates.repr(tcx))
     }
 }
 
-impl<'tcx> Repr<'tcx> for ty::GenericBounds<'tcx> {
+impl<'tcx> Repr<'tcx> for ty::InstantiatedPredicates<'tcx> {
     fn repr(&self, tcx: &ctxt<'tcx>) -> String {
-        format!("GenericBounds({})",
+        format!("InstantiatedPredicates({})",
                 self.predicates.repr(tcx))
     }
 }
@@ -1234,9 +1274,8 @@ impl<'tcx, T> UserString<'tcx> for ty::Binder<T>
 impl<'tcx> UserString<'tcx> for ty::TraitRef<'tcx> {
     fn user_string(&self, tcx: &ctxt<'tcx>) -> String {
         let path_str = ty::item_path_str(tcx, self.def_id);
-        let trait_def = ty::lookup_trait_def(tcx, self.def_id);
-        parameterized(tcx, &path_str, self.substs,
-                      &trait_def.generics, self.def_id, &[])
+        parameterized(tcx, &path_str, self.substs, self.def_id, &[],
+                      || ty::lookup_trait_def(tcx, self.def_id).generics.clone())
     }
 }
 
diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs
index afb5c948f18..4d90c492fa2 100644
--- a/src/librustc_back/target/mod.rs
+++ b/src/librustc_back/target/mod.rs
@@ -384,7 +384,7 @@ impl Target {
             Path::new(target)
         };
 
-        let target_path = env::var("RUST_TARGET_PATH")
+        let target_path = env::var_os("RUST_TARGET_PATH")
                               .unwrap_or(OsString::from_str(""));
 
         // FIXME 16351: add a sane default search path?
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 91f1121deaa..a18e8b16e8b 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -699,6 +699,11 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                               lp: &Rc<LoanPath<'tcx>>) {
         debug!("check_if_path_is_moved(id={}, use_kind={:?}, lp={})",
                id, use_kind, lp.repr(self.bccx.tcx));
+
+        // FIXME (22079): if you find yourself tempted to cut and paste
+        // the body below and then specializing the error reporting,
+        // consider refactoring this instead!
+
         let base_lp = owned_ptr_base_path_rc(lp);
         self.move_data.each_move_of(id, &base_lp, |the_move, moved_lp| {
             self.bccx.report_use_of_moved_value(
@@ -745,6 +750,29 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                                                      use_kind, lp_base);
             }
             LpExtend(ref lp_base, _, LpInterior(InteriorField(_))) => {
+                match lp_base.to_type().sty {
+                    ty::ty_struct(def_id, _) | ty::ty_enum(def_id, _) => {
+                        if ty::has_dtor(self.tcx(), def_id) {
+                            // In the case where the owner implements drop, then
+                            // the path must be initialized to prevent a case of
+                            // partial reinitialization
+                            //
+                            // FIXME (22079): could refactor via hypothetical
+                            // generalized check_if_path_is_moved
+                            let loan_path = owned_ptr_base_path_rc(lp_base);
+                            self.move_data.each_move_of(id, &loan_path, |_, _| {
+                                self.bccx
+                                    .report_partial_reinitialization_of_uninitialized_structure(
+                                        span,
+                                        &*loan_path);
+                                false
+                            });
+                            return;
+                        }
+                    },
+                    _ => {},
+                }
+
                 // assigning to `P.f` is ok if assigning to `P` is ok
                 self.check_if_assigned_path_is_moved(id, span,
                                                      use_kind, lp_base);
@@ -775,10 +803,12 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                     mark_variable_as_used_mut(self, assignee_cmt);
                 }
             }
+
             return;
         }
 
-        // Initializations are OK.
+        // Initializations are OK if and only if they aren't partial
+        // reinitialization of a partially-uninitialized structure.
         if mode == euv::Init {
             return
         }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
index b1cc3a65120..4e308c5809f 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs
@@ -286,7 +286,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> {
                 let loan_scope = match loan_region {
                     ty::ReScope(scope) => scope,
 
-                    ty::ReFree(ref fr) => fr.scope,
+                    ty::ReFree(ref fr) => fr.scope.to_code_extent(),
 
                     ty::ReStatic => {
                         // If we get here, an error must have been
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 0bad5594882..7c055bc3118 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -686,6 +686,18 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> {
         }
     }
 
+    pub fn report_partial_reinitialization_of_uninitialized_structure(
+            &self,
+            span: Span,
+            lp: &LoanPath<'tcx>) {
+        self.tcx
+            .sess
+            .span_err(span,
+                      (format!("partial reinitialization of uninitialized \
+                               structure `{}`",
+                               self.loan_path_to_string(lp))).as_slice());
+    }
+
     pub fn report_reassigned_immutable_variable(&self,
                                                 span: Span,
                                                 lp: &LoanPath<'tcx>,
diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs
index 6607b5cac9c..9c5ddc06519 100644
--- a/src/librustc_borrowck/borrowck/move_data.rs
+++ b/src/librustc_borrowck/borrowck/move_data.rs
@@ -24,7 +24,7 @@ use rustc::util::nodemap::{FnvHashMap, NodeSet};
 use rustc::util::ppaux::Repr;
 use std::cell::RefCell;
 use std::rc::Rc;
-use std::uint;
+use std::usize;
 use syntax::ast;
 use syntax::ast_util;
 use syntax::codemap::Span;
@@ -92,7 +92,7 @@ impl Clone for MovePathIndex {
 
 #[allow(non_upper_case_globals)]
 static InvalidMovePathIndex: MovePathIndex =
-    MovePathIndex(uint::MAX);
+    MovePathIndex(usize::MAX);
 
 /// Index into `MoveData.moves`, used like a pointer
 #[derive(Copy, PartialEq)]
@@ -106,7 +106,7 @@ impl MoveIndex {
 
 #[allow(non_upper_case_globals)]
 static InvalidMoveIndex: MoveIndex =
-    MoveIndex(uint::MAX);
+    MoveIndex(usize::MAX);
 
 pub struct MovePath<'tcx> {
     /// Loan path corresponding to this move path
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index d82c160fdee..12f5041cad1 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -464,7 +464,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
             // compiler, not for the target.
             let mut _old_path = OsString::from_str("");
             if cfg!(windows) {
-                _old_path = env::var("PATH").unwrap_or(_old_path);
+                _old_path = env::var_os("PATH").unwrap_or(_old_path);
                 let mut new_path = sess.host_filesearch(PathKind::All).get_dylib_search_paths();
                 new_path.extend(env::split_paths(&_old_path));
                 env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap());
@@ -737,7 +737,7 @@ pub fn phase_5_run_llvm_passes(sess: &Session,
 pub fn phase_6_link_output(sess: &Session,
                            trans: &trans::CrateTranslation,
                            outputs: &OutputFilenames) {
-    let old_path = env::var("PATH").unwrap_or(OsString::from_str(""));
+    let old_path = env::var_os("PATH").unwrap_or(OsString::from_str(""));
     let mut new_path = sess.host_filesearch(PathKind::All).get_tools_search_paths();
     new_path.extend(env::split_paths(&old_path));
     env::set_var("PATH", &env::join_paths(new_path.iter()).unwrap());
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index ef6e84d3a76..b087c0c2aa1 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -771,7 +771,7 @@ pub fn monitor<F:FnOnce()+Send>(f: F) {
 
     // FIXME: Hacks on hacks. If the env is trying to override the stack size
     // then *don't* set it explicitly.
-    if env::var("RUST_MIN_STACK").is_none() {
+    if env::var_os("RUST_MIN_STACK").is_none() {
         cfg = cfg.stack_size(STACK_SIZE);
     }
 
@@ -835,8 +835,7 @@ pub fn diagnostics_registry() -> diagnostics::registry::Registry {
 }
 
 pub fn main() {
-    let args = env::args().map(|s| s.into_string().unwrap());
-    let result = run(args.collect());
+    let result = run(env::args().collect());
     std::env::set_exit_status(result as i32);
 }
 
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 9df90258462..7105a6cc488 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -15,7 +15,7 @@ use diagnostic::Emitter;
 use driver;
 use rustc_resolve as resolve;
 use rustc_typeck::middle::lang_items;
-use rustc_typeck::middle::region::{self, CodeExtent};
+use rustc_typeck::middle::region::{self, CodeExtent, DestructionScopeData};
 use rustc_typeck::middle::resolve_lifetime;
 use rustc_typeck::middle::stability;
 use rustc_typeck::middle::subst;
@@ -325,7 +325,7 @@ impl<'a, 'tcx> Env<'a, 'tcx> {
     }
 
     pub fn re_free(&self, nid: ast::NodeId, id: u32) -> ty::Region {
-        ty::ReFree(ty::FreeRegion { scope: CodeExtent::from_node_id(nid),
+        ty::ReFree(ty::FreeRegion { scope: DestructionScopeData::new(nid),
                                     bound_region: ty::BrAnon(id)})
     }
 
diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs
index 7b6ee3a7297..124aa392435 100644
--- a/src/librustc_resolve/diagnostics.rs
+++ b/src/librustc_resolve/diagnostics.rs
@@ -23,7 +23,8 @@ register_diagnostics! {
     E0257, // inherent implementations are only allowed on types defined in the current module
     E0258, // import conflicts with existing submodule
     E0259, // an extern crate has already been imported into this module
-    E0260 // name conflicts with an external crate that has been imported into this module
+    E0260, // name conflicts with an external crate that has been imported into this module
+    E0317 // user-defined types or type parameters cannot shadow the primitive types
 }
 
 __build_diagnostic_array! { DIAGNOSTICS }
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index a261599a706..848c3557b1b 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -101,7 +101,7 @@ use std::cell::{Cell, RefCell};
 use std::fmt;
 use std::mem::replace;
 use std::rc::{Rc, Weak};
-use std::uint;
+use std::usize;
 
 // NB: This module needs to be declared first so diagnostics are
 // registered before they are used.
@@ -2196,7 +2196,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         // Search for external modules.
         if namespace == TypeNS {
-            if let Some(module) = module_.external_module_children.borrow().get(&name).cloned() {
+            // FIXME (21114): In principle unclear `child` *has* to be lifted.
+            let child = module_.external_module_children.borrow().get(&name).cloned();
+            if let Some(module) = child {
                 let name_bindings =
                     Rc::new(Resolver::create_name_bindings_from_module(module));
                 debug!("lower name bindings succeeded");
@@ -2481,7 +2483,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         // Finally, search through external children.
         if namespace == TypeNS {
-            if let Some(module) = module_.external_module_children.borrow().get(&name).cloned() {
+            // FIXME (21114): In principle unclear `child` *has* to be lifted.
+            let child = module_.external_module_children.borrow().get(&name).cloned();
+            if let Some(module) = child {
                 let name_bindings =
                     Rc::new(Resolver::create_name_bindings_from_module(module));
                 return Success((Target::new(module_,
@@ -2784,6 +2788,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         visit::walk_crate(self, krate);
     }
 
+    fn check_if_primitive_type_name(&self, name: Name, span: Span) {
+        if let Some(_) = self.primitive_type_table.primitive_types.get(&name) {
+            span_err!(self.session, span, E0317,
+                "user-defined types or type parameters cannot shadow the primitive types");
+        }
+    }
+
     fn resolve_item(&mut self, item: &Item) {
         let name = item.ident.name;
 
@@ -2795,6 +2806,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             // enum item: resolve all the variants' discrs,
             // then resolve the ty params
             ItemEnum(ref enum_def, ref generics) => {
+                self.check_if_primitive_type_name(name, item.span);
+
                 for variant in &(*enum_def).variants {
                     if let Some(ref dis_expr) = variant.node.disr_expr {
                         // resolve the discriminator expr
@@ -2820,6 +2833,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
 
             ItemTy(_, ref generics) => {
+                self.check_if_primitive_type_name(name, item.span);
+
                 self.with_type_parameter_rib(HasTypeParameters(generics,
                                                                TypeSpace,
                                                                item.id,
@@ -2843,6 +2858,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
 
             ItemTrait(_, ref generics, ref bounds, ref trait_items) => {
+                self.check_if_primitive_type_name(name, item.span);
+
                 // Create a new rib for the self type.
                 let mut self_type_rib = Rib::new(ItemRibKind);
 
@@ -2915,6 +2932,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             }
 
             ItemStruct(ref struct_def, ref generics) => {
+                self.check_if_primitive_type_name(name, item.span);
+
                 self.resolve_struct(item.id,
                                     generics,
                                     &struct_def.fields[]);
@@ -2968,7 +2987,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 });
             }
 
-            ItemExternCrate(_) | ItemUse(_) | ItemMac(..) => {
+            ItemUse(ref view_path) => {
+                // check for imports shadowing primitive types
+                if let ast::ViewPathSimple(ident, _) = view_path.node {
+                    match self.def_map.borrow().get(&item.id) {
+                        Some(&DefTy(..)) | Some(&DefStruct(..)) | Some(&DefTrait(..)) | None => {
+                            self.check_if_primitive_type_name(ident.name, item.span);
+                        }
+                        _ => {}
+                    }
+                }
+            }
+
+            ItemExternCrate(_) | ItemMac(..) => {
                 // do nothing, these are just around to be encoded
             }
         }
@@ -3110,6 +3141,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
     fn resolve_type_parameter(&mut self,
                               type_parameter: &TyParam) {
+        self.check_if_primitive_type_name(type_parameter.ident.name, type_parameter.span);
         for bound in &*type_parameter.bounds {
             self.resolve_type_parameter_bound(type_parameter.id, bound,
                                               TraitBoundingTypeParameter);
@@ -4366,7 +4398,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         for rib in this.value_ribs.iter().rev() {
             for (&k, _) in &rib.bindings {
                 maybes.push(token::get_name(k));
-                values.push(uint::MAX);
+                values.push(usize::MAX);
             }
         }
 
@@ -4380,7 +4412,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         }
 
         if values.len() > 0 &&
-            values[smallest] != uint::MAX &&
+            values[smallest] != usize::MAX &&
             values[smallest] < name.len() + 2 &&
             values[smallest] <= max_distance &&
             name != &maybes[smallest][] {
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 8a30806f3b6..68f413eff85 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -658,14 +658,18 @@ pub fn run_passes(sess: &Session,
     }
 
     // Produce final compile outputs.
+    let copy_gracefully = |from: &Path, to: &Path| {
+        if let Err(e) = fs::copy(from, to) {
+            sess.err(&format!("could not copy {:?} to {:?}: {}", from, to, e));
+        }
+    };
 
     let copy_if_one_unit = |ext: &str, output_type: config::OutputType, keep_numbered: bool| {
         // Three cases:
         if sess.opts.cg.codegen_units == 1 {
             // 1) Only one codegen unit.  In this case it's no difficulty
             //    to copy `foo.0.x` to `foo.x`.
-            fs::copy(&crate_output.with_extension(ext),
-                     &crate_output.path(output_type)).unwrap();
+            copy_gracefully(&crate_output.with_extension(ext), &crate_output.path(output_type));
             if !sess.opts.cg.save_temps && !keep_numbered {
                 // The user just wants `foo.x`, not `foo.0.x`.
                 remove(sess, &crate_output.with_extension(ext));
@@ -687,8 +691,7 @@ pub fn run_passes(sess: &Session,
     let link_obj = |output_path: &Path| {
         // Running `ld -r` on a single input is kind of pointless.
         if sess.opts.cg.codegen_units == 1 {
-            fs::copy(&crate_output.with_extension("0.o"),
-                     output_path).unwrap();
+            copy_gracefully(&crate_output.with_extension("0.o"), output_path);
             // Leave the .0.o file around, to mimic the behavior of the normal
             // code path.
             return;
diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs
index e80564097df..cdcd917ee5e 100644
--- a/src/librustc_trans/save/mod.rs
+++ b/src/librustc_trans/save/mod.rs
@@ -1551,7 +1551,7 @@ pub fn process_crate(sess: &Session,
     info!("Dumping crate {}", cratename);
 
     // find a path to dump our data to
-    let mut root_path = match env::var_string("DXR_RUST_TEMP_FOLDER") {
+    let mut root_path = match env::var("DXR_RUST_TEMP_FOLDER") {
         Ok(val) => Path::new(val),
         Err(..) => match odir {
             Some(val) => val.join("dxr"),
diff --git a/src/librustc_trans/trans/cleanup.rs b/src/librustc_trans/trans/cleanup.rs
index bebba151a0d..f7e37b6f633 100644
--- a/src/librustc_trans/trans/cleanup.rs
+++ b/src/librustc_trans/trans/cleanup.rs
@@ -130,12 +130,17 @@ impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
         // this new AST scope had better be its immediate child.
         let top_scope = self.top_ast_scope();
         if top_scope.is_some() {
-            assert_eq!(self.ccx
-                           .tcx()
-                           .region_maps
-                           .opt_encl_scope(region::CodeExtent::from_node_id(debug_loc.id))
-                           .map(|s|s.node_id()),
-                       top_scope);
+            assert!((self.ccx
+                     .tcx()
+                     .region_maps
+                     .opt_encl_scope(region::CodeExtent::from_node_id(debug_loc.id))
+                     .map(|s|s.node_id()) == top_scope)
+                    ||
+                    (self.ccx
+                     .tcx()
+                     .region_maps
+                     .opt_encl_scope(region::CodeExtent::DestructionScope(debug_loc.id))
+                     .map(|s|s.node_id()) == top_scope));
         }
 
         self.push_scope(CleanupScope::new(AstScopeKind(debug_loc.id),
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 0dbb53e09b7..1951d9946bc 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -16,11 +16,12 @@
 //! somewhat differently during the collect and check phases,
 //! particularly with respect to looking up the types of top-level
 //! items.  In the collect phase, the crate context is used as the
-//! `AstConv` instance; in this phase, the `get_item_type_scheme()` function
-//! triggers a recursive call to `ty_of_item()`  (note that
-//! `ast_ty_to_ty()` will detect recursive types and report an error).
-//! In the check phase, when the FnCtxt is used as the `AstConv`,
-//! `get_item_type_scheme()` just looks up the item type in `tcx.tcache`.
+//! `AstConv` instance; in this phase, the `get_item_type_scheme()`
+//! function triggers a recursive call to `type_scheme_of_item()`
+//! (note that `ast_ty_to_ty()` will detect recursive types and report
+//! an error).  In the check phase, when the FnCtxt is used as the
+//! `AstConv`, `get_item_type_scheme()` just looks up the item type in
+//! `tcx.tcache` (using `ty::lookup_item_type`).
 //!
 //! The `RegionScope` trait controls what happens when the user does
 //! not specify a region in some location where a region is required
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 1249e0d8ce1..3ea2743c63e 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -467,8 +467,14 @@ pub fn check_pat_struct<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, pat: &'tcx ast::Pat,
         }
     };
 
-    instantiate_path(pcx.fcx, path, ty::lookup_item_type(tcx, enum_def_id),
-                     None, def, pat.span, pat.id);
+    instantiate_path(pcx.fcx,
+                     path,
+                     ty::lookup_item_type(tcx, enum_def_id),
+                     &ty::lookup_predicates(tcx, enum_def_id),
+                     None,
+                     def,
+                     pat.span,
+                     pat.id);
 
     let pat_ty = fcx.node_ty(pat.id);
     demand::eqtype(fcx, pat.span, expected, pat_ty);
@@ -499,6 +505,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
         .map_or_else(|| def.def_id(), |(enum_def, _)| enum_def);
 
     let ctor_scheme = ty::lookup_item_type(tcx, enum_def);
+    let ctor_predicates = ty::lookup_predicates(tcx, enum_def);
     let path_scheme = if ty::is_fn_ty(ctor_scheme.ty) {
         let fn_ret = ty::assert_no_late_bound_regions(tcx, &ty::ty_fn_ret(ctor_scheme.ty));
         ty::TypeScheme {
@@ -508,7 +515,7 @@ pub fn check_pat_enum<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>,
     } else {
         ctor_scheme
     };
-    instantiate_path(pcx.fcx, path, path_scheme, None, def, pat.span, pat.id);
+    instantiate_path(pcx.fcx, path, path_scheme, &ctor_predicates, None, def, pat.span, pat.id);
 
     let pat_ty = fcx.node_ty(pat.id);
     demand::eqtype(fcx, pat.span, expected, pat_ty);
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index b2a676e878e..0b7c5b04aaa 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -13,7 +13,7 @@
 use super::{check_fn, Expectation, FnCtxt};
 
 use astconv;
-use middle::region::CodeExtent;
+use middle::region;
 use middle::subst;
 use middle::ty::{self, ToPolyTraitRef, Ty};
 use rscope::RegionScope;
@@ -78,7 +78,9 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
     fcx.write_ty(expr.id, closure_type);
 
     let fn_sig =
-        ty::liberate_late_bound_regions(fcx.tcx(), CodeExtent::from_node_id(body.id), &fn_ty.sig);
+        ty::liberate_late_bound_regions(fcx.tcx(),
+                                        region::DestructionScopeData::new(body.id),
+                                        &fn_ty.sig);
 
     check_fn(fcx.ccx,
              ast::Unsafety::Normal,
diff --git a/src/librustc_typeck/check/compare_method.rs b/src/librustc_typeck/check/compare_method.rs
index a5b938c7600..1e1d7e09260 100644
--- a/src/librustc_typeck/check/compare_method.rs
+++ b/src/librustc_typeck/check/compare_method.rs
@@ -205,7 +205,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
     // however, because we want to replace all late-bound regions with
     // region variables.
     let impl_bounds =
-        impl_m.generics.to_bounds(tcx, impl_to_skol_substs);
+        impl_m.predicates.instantiate(tcx, impl_to_skol_substs);
 
     let (impl_bounds, _) =
         infcx.replace_late_bound_regions_with_fresh_var(
@@ -216,7 +216,7 @@ pub fn compare_impl_method<'tcx>(tcx: &ty::ctxt<'tcx>,
            impl_bounds.repr(tcx));
 
     // Normalize the associated types in the trait_bounds.
-    let trait_bounds = trait_m.generics.to_bounds(tcx, &trait_to_skol_substs);
+    let trait_bounds = trait_m.predicates.instantiate(tcx, &trait_to_skol_substs);
 
     // Obtain the predicate split predicate sets for each.
     let trait_pred = trait_bounds.predicates.split();
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
new file mode 100644
index 00000000000..ce67369ca9d
--- /dev/null
+++ b/src/librustc_typeck/check/dropck.rs
@@ -0,0 +1,293 @@
+// Copyright 2014-2015 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 check::regionck::{self, Rcx};
+
+use middle::infer;
+use middle::region;
+use middle::subst;
+use middle::ty::{self, Ty};
+use util::ppaux::{Repr};
+
+use syntax::codemap::Span;
+
+pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
+                                                     typ: ty::Ty<'tcx>,
+                                                     span: Span,
+                                                     scope: region::CodeExtent) {
+    debug!("check_safety_of_destructor_if_necessary typ: {} scope: {:?}",
+           typ.repr(rcx.tcx()), scope);
+
+    // types that have been traversed so far by `traverse_type_if_unseen`
+    let mut breadcrumbs: Vec<Ty<'tcx>> = Vec::new();
+
+    iterate_over_potentially_unsafe_regions_in_type(
+        rcx,
+        &mut breadcrumbs,
+        typ,
+        span,
+        scope,
+        0);
+}
+
+fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
+    rcx: &mut Rcx<'a, 'tcx>,
+    breadcrumbs: &mut Vec<Ty<'tcx>>,
+    ty_root: ty::Ty<'tcx>,
+    span: Span,
+    scope: region::CodeExtent,
+    depth: uint)
+{
+    let origin = |&:| infer::SubregionOrigin::SafeDestructor(span);
+    let mut walker = ty_root.walk();
+    let opt_phantom_data_def_id = rcx.tcx().lang_items.phantom_data();
+
+    let destructor_for_type = rcx.tcx().destructor_for_type.borrow();
+
+    while let Some(typ) = walker.next() {
+        // Avoid recursing forever.
+        if breadcrumbs.contains(&typ) {
+            continue;
+        }
+        breadcrumbs.push(typ);
+
+        // If we encounter `PhantomData<T>`, then we should replace it
+        // with `T`, the type it represents as owned by the
+        // surrounding context, before doing further analysis.
+        let typ = if let ty::ty_struct(struct_did, substs) = typ.sty {
+            if opt_phantom_data_def_id == Some(struct_did) {
+                let item_type = ty::lookup_item_type(rcx.tcx(), struct_did);
+                let tp_def = item_type.generics.types
+                    .opt_get(subst::TypeSpace, 0).unwrap();
+                let new_typ = substs.type_for_def(tp_def);
+                debug!("replacing phantom {} with {}",
+                       typ.repr(rcx.tcx()), new_typ.repr(rcx.tcx()));
+                new_typ
+            } else {
+                typ
+            }
+        } else {
+            typ
+        };
+
+        let opt_type_did = match typ.sty {
+            ty::ty_struct(struct_did, _) => Some(struct_did),
+            ty::ty_enum(enum_did, _) => Some(enum_did),
+            _ => None,
+        };
+
+        let opt_dtor =
+            opt_type_did.and_then(|did| destructor_for_type.get(&did));
+
+        debug!("iterate_over_potentially_unsafe_regions_in_type \
+                {}typ: {} scope: {:?} opt_dtor: {:?}",
+               (0..depth).map(|_| ' ').collect::<String>(),
+               typ.repr(rcx.tcx()), scope, opt_dtor);
+
+        // If `typ` has a destructor, then we must ensure that all
+        // borrowed data reachable via `typ` must outlive the parent
+        // of `scope`. This is handled below.
+        //
+        // However, there is an important special case: by
+        // parametricity, any generic type parameters have *no* trait
+        // bounds in the Drop impl can not be used in any way (apart
+        // from being dropped), and thus we can treat data borrowed
+        // via such type parameters remains unreachable.
+        //
+        // For example, consider `impl<T> Drop for Vec<T> { ... }`,
+        // which does have to be able to drop instances of `T`, but
+        // otherwise cannot read data from `T`.
+        //
+        // Of course, for the type expression passed in for any such
+        // unbounded type parameter `T`, we must resume the recursive
+        // analysis on `T` (since it would be ignored by
+        // type_must_outlive).
+        //
+        // FIXME (pnkfelix): Long term, we could be smart and actually
+        // feed which generic parameters can be ignored *into* `fn
+        // type_must_outlive` (or some generalization thereof). But
+        // for the short term, it probably covers most cases of
+        // interest to just special case Drop impls where: (1.) there
+        // are no generic lifetime parameters and (2.)  *all* generic
+        // type parameters are unbounded.  If both conditions hold, we
+        // simply skip the `type_must_outlive` call entirely (but
+        // resume the recursive checking of the type-substructure).
+
+        let has_dtor_of_interest;
+
+        if let Some(&dtor_method_did) = opt_dtor {
+            let impl_did = ty::impl_of_method(rcx.tcx(), dtor_method_did)
+                .unwrap_or_else(|| {
+                    rcx.tcx().sess.span_bug(
+                        span, "no Drop impl found for drop method")
+                });
+
+            let dtor_typescheme = ty::lookup_item_type(rcx.tcx(), impl_did);
+            let dtor_generics = dtor_typescheme.generics;
+            let dtor_predicates = ty::lookup_predicates(rcx.tcx(), impl_did);
+
+            let has_pred_of_interest = dtor_predicates.predicates.iter().any(|pred| {
+                // In `impl<T> Drop where ...`, we automatically
+                // assume some predicate will be meaningful and thus
+                // represents a type through which we could reach
+                // borrowed data. However, there can be implicit
+                // predicates (namely for Sized), and so we still need
+                // to walk through and filter out those cases.
+
+                let result = match *pred {
+                    ty::Predicate::Trait(ty::Binder(ref t_pred)) => {
+                        let def_id = t_pred.trait_ref.def_id;
+                        match rcx.tcx().lang_items.to_builtin_kind(def_id) {
+                            Some(ty::BoundSend) |
+                            Some(ty::BoundSized) |
+                            Some(ty::BoundCopy) |
+                            Some(ty::BoundSync) => false,
+                            _ => true,
+                        }
+                    }
+                    ty::Predicate::Equate(..) |
+                    ty::Predicate::RegionOutlives(..) |
+                    ty::Predicate::TypeOutlives(..) |
+                    ty::Predicate::Projection(..) => {
+                        // we assume all of these where-clauses may
+                        // give the drop implementation the capabilty
+                        // to access borrowed data.
+                        true
+                    }
+                };
+
+                if result {
+                    debug!("typ: {} has interesting dtor due to generic preds, e.g. {}",
+                           typ.repr(rcx.tcx()), pred.repr(rcx.tcx()));
+                }
+
+                result
+            });
+
+            // In `impl<'a> Drop ...`, we automatically assume
+            // `'a` is meaningful and thus represents a bound
+            // through which we could reach borrowed data.
+            //
+            // FIXME (pnkfelix): In the future it would be good to
+            // extend the language to allow the user to express,
+            // in the impl signature, that a lifetime is not
+            // actually used (something like `where 'a: ?Live`).
+            let has_region_param_of_interest =
+                dtor_generics.has_region_params(subst::TypeSpace);
+
+            has_dtor_of_interest =
+                has_region_param_of_interest ||
+                has_pred_of_interest;
+
+            if has_dtor_of_interest {
+                debug!("typ: {} has interesting dtor, due to \
+                        region params: {} or pred: {}",
+                       typ.repr(rcx.tcx()),
+                       has_region_param_of_interest,
+                       has_pred_of_interest);
+            } else {
+                debug!("typ: {} has dtor, but it is uninteresting",
+                       typ.repr(rcx.tcx()));
+            }
+
+        } else {
+            debug!("typ: {} has no dtor, and thus is uninteresting",
+                   typ.repr(rcx.tcx()));
+            has_dtor_of_interest = false;
+        }
+
+        if has_dtor_of_interest {
+            // If `typ` has a destructor, then we must ensure that all
+            // borrowed data reachable via `typ` must outlive the
+            // parent of `scope`. (It does not suffice for it to
+            // outlive `scope` because that could imply that the
+            // borrowed data is torn down in between the end of
+            // `scope` and when the destructor itself actually runs.)
+
+            let parent_region =
+                match rcx.tcx().region_maps.opt_encl_scope(scope) {
+                    Some(parent_scope) => ty::ReScope(parent_scope),
+                    None => rcx.tcx().sess.span_bug(
+                        span, format!("no enclosing scope found for scope: {:?}",
+                                      scope).as_slice()),
+                };
+
+            regionck::type_must_outlive(rcx, origin(), typ, parent_region);
+
+        } else {
+            // Okay, `typ` itself is itself not reachable by a
+            // destructor; but it may contain substructure that has a
+            // destructor.
+
+            match typ.sty {
+                ty::ty_struct(struct_did, substs) => {
+                    // Don't recurse; we extract type's substructure,
+                    // so do not process subparts of type expression.
+                    walker.skip_current_subtree();
+
+                    let fields =
+                        ty::lookup_struct_fields(rcx.tcx(), struct_did);
+                    for field in fields.iter() {
+                        let field_type =
+                            ty::lookup_field_type(rcx.tcx(),
+                                                  struct_did,
+                                                  field.id,
+                                                  substs);
+                        iterate_over_potentially_unsafe_regions_in_type(
+                            rcx,
+                            breadcrumbs,
+                            field_type,
+                            span,
+                            scope,
+                            depth+1)
+                    }
+                }
+
+                ty::ty_enum(enum_did, substs) => {
+                    // Don't recurse; we extract type's substructure,
+                    // so do not process subparts of type expression.
+                    walker.skip_current_subtree();
+
+                    let all_variant_info =
+                        ty::substd_enum_variants(rcx.tcx(),
+                                                 enum_did,
+                                                 substs);
+                    for variant_info in all_variant_info.iter() {
+                        for argument_type in variant_info.args.iter() {
+                            iterate_over_potentially_unsafe_regions_in_type(
+                                rcx,
+                                breadcrumbs,
+                                *argument_type,
+                                span,
+                                scope,
+                                depth+1)
+                        }
+                    }
+                }
+
+                ty::ty_rptr(..) | ty::ty_ptr(_) | ty::ty_bare_fn(..) => {
+                    // Don't recurse, since references, pointers,
+                    // boxes, and bare functions don't own instances
+                    // of the types appearing within them.
+                    walker.skip_current_subtree();
+                }
+                _ => {}
+            };
+
+            // You might be tempted to pop breadcrumbs here after
+            // processing type's internals above, but then you hit
+            // exponential time blowup e.g. on
+            // compile-fail/huge-struct.rs. Instead, we do not remove
+            // anything from the breadcrumbs vector during any particular
+            // traversal, and instead clear it after the whole traversal
+            // is done.
+        }
+    }
+}
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index 77701af25d3..dfbfc86c659 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -46,7 +46,7 @@ struct InstantiatedMethodSig<'tcx> {
 
     /// Generic bounds on the method's parameters which must be added
     /// as pending obligations.
-    method_bounds: ty::GenericBounds<'tcx>,
+    method_predicates: ty::InstantiatedPredicates<'tcx>,
 }
 
 pub fn confirm<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
@@ -99,7 +99,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
 
         // Create the final signature for the method, replacing late-bound regions.
         let InstantiatedMethodSig {
-            method_sig, all_substs, method_bounds
+            method_sig, all_substs, method_predicates
         } = self.instantiate_method_sig(&pick, all_substs);
         let method_self_ty = method_sig.inputs[0];
 
@@ -107,7 +107,7 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         self.unify_receivers(self_ty, method_self_ty);
 
         // Add any trait/regions obligations specified on the method's type parameters.
-        self.add_obligations(&pick, &all_substs, &method_bounds);
+        self.add_obligations(&pick, &all_substs, &method_predicates);
 
         // Create the final `MethodCallee`.
         let fty = ty::mk_bare_fn(self.tcx(), None, self.tcx().mk_bare_fn(ty::BareFnTy {
@@ -416,18 +416,19 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         // that obligation is not necessarily satisfied. (In the
         // future, it would be.) But we know that the true `Self` DOES implement
         // the trait. So we just delete this requirement. Hack hack hack.
-        let mut method_bounds = pick.method_ty.generics.to_bounds(self.tcx(), &all_substs);
+        let mut method_predicates = pick.method_ty.predicates.instantiate(self.tcx(), &all_substs);
         match pick.kind {
             probe::ObjectPick(..) => {
-                assert_eq!(method_bounds.predicates.get_slice(subst::SelfSpace).len(), 1);
-                method_bounds.predicates.pop(subst::SelfSpace);
+                assert_eq!(method_predicates.predicates.get_slice(subst::SelfSpace).len(), 1);
+                method_predicates.predicates.pop(subst::SelfSpace);
             }
             _ => { }
         }
-        let method_bounds = self.fcx.normalize_associated_types_in(self.span, &method_bounds);
+        let method_predicates = self.fcx.normalize_associated_types_in(self.span,
+                                                                       &method_predicates);
 
-        debug!("method_bounds after subst = {}",
-               method_bounds.repr(self.tcx()));
+        debug!("method_predicates after subst = {}",
+               method_predicates.repr(self.tcx()));
 
         // Instantiate late-bound regions and substitute the trait
         // parameters into the method type to get the actual method type.
@@ -446,22 +447,22 @@ impl<'a,'tcx> ConfirmContext<'a,'tcx> {
         InstantiatedMethodSig {
             method_sig: method_sig,
             all_substs: all_substs,
-            method_bounds: method_bounds,
+            method_predicates: method_predicates,
         }
     }
 
     fn add_obligations(&mut self,
                        pick: &probe::Pick<'tcx>,
                        all_substs: &subst::Substs<'tcx>,
-                       method_bounds: &ty::GenericBounds<'tcx>) {
-        debug!("add_obligations: pick={} all_substs={} method_bounds={}",
+                       method_predicates: &ty::InstantiatedPredicates<'tcx>) {
+        debug!("add_obligations: pick={} all_substs={} method_predicates={}",
                pick.repr(self.tcx()),
                all_substs.repr(self.tcx()),
-               method_bounds.repr(self.tcx()));
+               method_predicates.repr(self.tcx()));
 
         self.fcx.add_obligations_for_parameters(
             traits::ObligationCause::misc(self.span, self.fcx.body_id),
-            method_bounds);
+            method_predicates);
 
         self.fcx.add_default_region_param_bounds(
             all_substs,
diff --git a/src/librustc_typeck/check/method/mod.rs b/src/librustc_typeck/check/method/mod.rs
index 88455b3385a..55b4dae5b9e 100644
--- a/src/librustc_typeck/check/method/mod.rs
+++ b/src/librustc_typeck/check/method/mod.rs
@@ -221,7 +221,7 @@ pub fn lookup_in_trait_adjusted<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     //
     // Note that as the method comes from a trait, it should not have
     // any late-bound regions appearing in its bounds.
-    let method_bounds = fcx.instantiate_bounds(span, trait_ref.substs, &method_ty.generics);
+    let method_bounds = fcx.instantiate_bounds(span, trait_ref.substs, &method_ty.predicates);
     assert!(!method_bounds.has_escaping_regions());
     fcx.add_obligations_for_parameters(
         traits::ObligationCause::misc(span, fcx.body_id),
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index ba49ae637b3..82bd4ae87ff 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -525,7 +525,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                                                             trait_def_id);
 
         let trait_impls = self.tcx().trait_impls.borrow();
-        let impl_def_ids = match trait_impls.get(&trait_def_id) {
+        let impl_def_ids = trait_impls.get(&trait_def_id);
+        let impl_def_ids = match impl_def_ids {
             None => { return; }
             Some(impls) => impls,
         };
@@ -665,8 +666,9 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
             debug!("assemble_projection_candidates: projection_trait_ref={}",
                    projection_trait_ref.repr(self.tcx()));
 
-            let trait_def = ty::lookup_trait_def(self.tcx(), projection_trait_ref.def_id);
-            let bounds = trait_def.generics.to_bounds(self.tcx(), projection_trait_ref.substs);
+            let trait_predicates = ty::lookup_predicates(self.tcx(),
+                                                         projection_trait_ref.def_id);
+            let bounds = trait_predicates.instantiate(self.tcx(), projection_trait_ref.substs);
             let predicates = bounds.predicates.into_vec();
             debug!("assemble_projection_candidates: predicates={}",
                    predicates.repr(self.tcx()));
@@ -942,8 +944,8 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                     let cause = traits::ObligationCause::misc(self.span, self.fcx.body_id);
 
                     // Check whether the impl imposes obligations we have to worry about.
-                    let impl_generics = ty::lookup_item_type(self.tcx(), impl_def_id).generics;
-                    let impl_bounds = impl_generics.to_bounds(self.tcx(), substs);
+                    let impl_bounds = ty::lookup_predicates(self.tcx(), impl_def_id);
+                    let impl_bounds = impl_bounds.instantiate(self.tcx(), substs);
                     let traits::Normalized { value: impl_bounds,
                                              obligations: norm_obligations } =
                         traits::normalize(selcx, cause.clone(), &impl_bounds);
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 9c0d6f7dae3..d12b23187b8 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -90,10 +90,10 @@ use middle::infer;
 use middle::mem_categorization as mc;
 use middle::mem_categorization::McResult;
 use middle::pat_util::{self, pat_id_map};
-use middle::region::CodeExtent;
+use middle::region::{self, CodeExtent};
 use middle::subst::{self, Subst, Substs, VecPerParamSpace, ParamSpace, TypeSpace};
 use middle::traits;
-use middle::ty::{FnSig, VariantInfo, TypeScheme};
+use middle::ty::{FnSig, GenericPredicates, VariantInfo, TypeScheme};
 use middle::ty::{Disr, ParamTy, ParameterEnvironment};
 use middle::ty::{self, HasProjectionTypes, RegionEscape, Ty};
 use middle::ty::liberate_late_bound_regions;
@@ -101,7 +101,7 @@ use middle::ty::{MethodCall, MethodCallee, MethodMap, ObjectCastMap};
 use middle::ty_fold::{TypeFolder, TypeFoldable};
 use rscope::RegionScope;
 use session::Session;
-use {CrateCtxt, lookup_def_ccx, no_params, require_same_types};
+use {CrateCtxt, lookup_def_ccx, require_same_types};
 use TypeAndSubsts;
 use lint;
 use util::common::{block_query, indenter, loop_query};
@@ -127,6 +127,7 @@ use syntax::ptr::P;
 use syntax::visit::{self, Visitor};
 
 mod assoc;
+pub mod dropck;
 pub mod _match;
 pub mod vtable;
 pub mod writeback;
@@ -495,7 +496,9 @@ fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
             let fn_sig =
                 fn_ty.sig.subst(ccx.tcx, &inh.param_env.free_substs);
             let fn_sig =
-                liberate_late_bound_regions(ccx.tcx, CodeExtent::from_node_id(body.id), &fn_sig);
+                liberate_late_bound_regions(ccx.tcx,
+                                            region::DestructionScopeData::new(body.id),
+                                            &fn_sig);
             let fn_sig =
                 inh.normalize_associated_types_in(&inh.param_env, body.span, body.id, &fn_sig);
 
@@ -1443,11 +1446,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn instantiate_bounds(&self,
                           span: Span,
                           substs: &Substs<'tcx>,
-                          generics: &ty::Generics<'tcx>)
-                          -> ty::GenericBounds<'tcx>
+                          bounds: &ty::GenericPredicates<'tcx>)
+                          -> ty::InstantiatedPredicates<'tcx>
     {
-        ty::GenericBounds {
-            predicates: self.instantiate_type_scheme(span, substs, &generics.predicates)
+        ty::InstantiatedPredicates {
+            predicates: self.instantiate_type_scheme(span, substs, &bounds.predicates)
         }
     }
 
@@ -1558,12 +1561,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     {
         let type_scheme =
             ty::lookup_item_type(self.tcx(), def_id);
+        let type_predicates =
+            ty::lookup_predicates(self.tcx(), def_id);
         let substs =
             self.infcx().fresh_substs_for_generics(
                 span,
                 &type_scheme.generics);
         let bounds =
-            self.instantiate_bounds(span, &substs, &type_scheme.generics);
+            self.instantiate_bounds(span, &substs, &type_predicates);
         self.add_obligations_for_parameters(
             traits::ObligationCause::new(
                 span,
@@ -1591,7 +1596,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     {
         let tcx = self.tcx();
 
-        let ty::TypeScheme { generics, ty: decl_ty } = ty::lookup_item_type(tcx, did);
+        let ty::TypeScheme { generics, ty: decl_ty } =
+            ty::lookup_item_type(tcx, did);
 
         let wants_params =
             generics.has_type_params(TypeSpace) || generics.has_region_params(TypeSpace);
@@ -1686,7 +1692,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let mut bounds_checker = wf::BoundsChecker::new(self,
                                                         ast_t.span,
-                                                        CodeExtent::from_node_id(self.body_id),
+                                                        self.body_id,
                                                         None);
         bounds_checker.check_ty(t);
 
@@ -1840,16 +1846,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// and `T`. This routine will add a region obligation `$1:'$0` and register it locally.
     pub fn add_obligations_for_parameters(&self,
                                           cause: traits::ObligationCause<'tcx>,
-                                          generic_bounds: &ty::GenericBounds<'tcx>)
+                                          predicates: &ty::InstantiatedPredicates<'tcx>)
     {
-        assert!(!generic_bounds.has_escaping_regions());
+        assert!(!predicates.has_escaping_regions());
 
-        debug!("add_obligations_for_parameters(generic_bounds={})",
-               generic_bounds.repr(self.tcx()));
+        debug!("add_obligations_for_parameters(predicates={})",
+               predicates.repr(self.tcx()));
 
         let obligations = traits::predicates_for_generics(self.tcx(),
                                                           cause,
-                                                          generic_bounds);
+                                                          predicates);
 
         obligations.map_move(|o| self.register_predicate(o));
     }
@@ -3613,8 +3619,8 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
       }
       ast::ExprPath(ref path) => {
           let defn = lookup_def(fcx, path.span, id);
-          let pty = type_scheme_for_def(fcx, expr.span, defn);
-          instantiate_path(fcx, path, pty, None, defn, expr.span, expr.id);
+          let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, defn);
+          instantiate_path(fcx, path, scheme, &predicates, None, defn, expr.span, expr.id);
 
           // We always require that the type provided as the value for
           // a type parameter outlives the moment of instantiation.
@@ -3626,10 +3632,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
           astconv::instantiate_trait_ref(fcx, fcx, &*qpath.trait_ref, Some(self_ty), None);
 
           let defn = lookup_def(fcx, expr.span, id);
-          let pty = type_scheme_for_def(fcx, expr.span, defn);
+          let (scheme, predicates) = type_scheme_and_predicates_for_def(fcx, expr.span, defn);
           let mut path = qpath.trait_ref.path.clone();
           path.segments.push(qpath.item_path.clone());
-          instantiate_path(fcx, &path, pty, Some(self_ty), defn, expr.span, expr.id);
+          instantiate_path(fcx, &path, scheme, &predicates, Some(self_ty),
+                           defn, expr.span, expr.id);
 
           // We always require that the type provided as the value for
           // a type parameter outlives the moment of instantiation.
@@ -4045,9 +4052,9 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>,
                 };
 
                 if let Some(did) = did {
-                    let polytype = ty::lookup_item_type(tcx, did);
+                    let predicates = ty::lookup_predicates(tcx, did);
                     let substs = Substs::new_type(vec![idx_type], vec![]);
-                    let bounds = fcx.instantiate_bounds(expr.span, &substs, &polytype.generics);
+                    let bounds = fcx.instantiate_bounds(expr.span, &substs, &predicates);
                     fcx.add_obligations_for_parameters(
                         traits::ObligationCause::new(expr.span,
                                                      fcx.body_id,
@@ -4628,46 +4635,36 @@ pub fn lookup_def(fcx: &FnCtxt, sp: Span, id: ast::NodeId) -> def::Def {
 }
 
 // Returns the type parameter count and the type for the given definition.
-pub fn type_scheme_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
-                                     sp: Span,
-                                     defn: def::Def)
-                                     -> TypeScheme<'tcx> {
+fn type_scheme_and_predicates_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                                                sp: Span,
+                                                defn: def::Def)
+                                                -> (TypeScheme<'tcx>, GenericPredicates<'tcx>) {
     match defn {
-      def::DefLocal(nid) | def::DefUpvar(nid, _) => {
-          let typ = fcx.local_ty(sp, nid);
-          return no_params(typ);
-      }
-      def::DefFn(id, _) | def::DefStaticMethod(id, _) | def::DefMethod(id, _, _) |
-      def::DefStatic(id, _) | def::DefVariant(_, id, _) |
-      def::DefStruct(id) | def::DefConst(id) => {
-        return ty::lookup_item_type(fcx.ccx.tcx, id);
-      }
-      def::DefTrait(_) |
-      def::DefTy(..) |
-      def::DefAssociatedTy(..) |
-      def::DefAssociatedPath(..) |
-      def::DefPrimTy(_) |
-      def::DefTyParam(..) => {
-        fcx.ccx.tcx.sess.span_bug(sp, "expected value, found type");
-      }
-      def::DefMod(..) | def::DefForeignMod(..) => {
-        fcx.ccx.tcx.sess.span_bug(sp, "expected value, found module");
-      }
-      def::DefUse(..) => {
-        fcx.ccx.tcx.sess.span_bug(sp, "expected value, found use");
-      }
-      def::DefRegion(..) => {
-        fcx.ccx.tcx.sess.span_bug(sp, "expected value, found region");
-      }
-      def::DefTyParamBinder(..) => {
-        fcx.ccx.tcx.sess.span_bug(sp, "expected value, found type parameter");
-      }
-      def::DefLabel(..) => {
-        fcx.ccx.tcx.sess.span_bug(sp, "expected value, found label");
-      }
-      def::DefSelfTy(..) => {
-        fcx.ccx.tcx.sess.span_bug(sp, "expected value, found self ty");
-      }
+        def::DefLocal(nid) | def::DefUpvar(nid, _) => {
+            let typ = fcx.local_ty(sp, nid);
+            (ty::TypeScheme { generics: ty::Generics::empty(), ty: typ },
+             ty::GenericPredicates::empty())
+        }
+        def::DefFn(id, _) | def::DefStaticMethod(id, _) | def::DefMethod(id, _, _) |
+        def::DefStatic(id, _) | def::DefVariant(_, id, _) |
+        def::DefStruct(id) | def::DefConst(id) => {
+            (ty::lookup_item_type(fcx.tcx(), id), ty::lookup_predicates(fcx.tcx(), id))
+        }
+        def::DefTrait(_) |
+        def::DefTy(..) |
+        def::DefAssociatedTy(..) |
+        def::DefAssociatedPath(..) |
+        def::DefPrimTy(_) |
+        def::DefTyParam(..) |
+        def::DefMod(..) |
+        def::DefForeignMod(..) |
+        def::DefUse(..) |
+        def::DefRegion(..) |
+        def::DefTyParamBinder(..) |
+        def::DefLabel(..) |
+        def::DefSelfTy(..) => {
+            fcx.ccx.tcx.sess.span_bug(sp, &format!("expected value, found {:?}", defn));
+        }
     }
 }
 
@@ -4676,6 +4673,7 @@ pub fn type_scheme_for_def<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                   path: &ast::Path,
                                   type_scheme: TypeScheme<'tcx>,
+                                  type_predicates: &ty::GenericPredicates<'tcx>,
                                   opt_self_ty: Option<Ty<'tcx>>,
                                   def: def::Def,
                                   span: Span,
@@ -4861,7 +4859,7 @@ pub fn instantiate_path<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 
     // Add all the obligations that are required, substituting and
     // normalized appropriately.
-    let bounds = fcx.instantiate_bounds(span, &substs, &type_scheme.generics);
+    let bounds = fcx.instantiate_bounds(span, &substs, &type_predicates);
     fcx.add_obligations_for_parameters(
         traits::ObligationCause::new(span, fcx.body_id, traits::ItemObligation(def.def_id())),
         &bounds);
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 9df0403794d..bcb2ba6231d 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -83,6 +83,7 @@
 //! contents.
 
 use astconv::AstConv;
+use check::dropck;
 use check::FnCtxt;
 use check::regionmanip;
 use check::vtable;
@@ -171,6 +172,7 @@ pub struct Rcx<'a, 'tcx: 'a> {
 
     // id of AST node being analyzed (the subject of the analysis).
     subject: SubjectNode,
+
 }
 
 /// Returns the validity region of `def` -- that is, how long is `def` valid?
@@ -198,7 +200,8 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> {
         Rcx { fcx: fcx,
               repeating_scope: initial_repeating_scope,
               subject: subject,
-              region_bound_pairs: Vec::new() }
+              region_bound_pairs: Vec::new()
+        }
     }
 
     pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
@@ -469,6 +472,10 @@ fn constrain_bindings_in_pat(pat: &ast::Pat, rcx: &mut Rcx) {
         type_of_node_must_outlive(
             rcx, infer::BindingTypeIsNotValidAtDecl(span),
             id, var_region);
+
+        let var_scope = tcx.region_maps.var_scope(id);
+        let typ = rcx.resolve_node_type(id);
+        dropck::check_safety_of_destructor_if_necessary(rcx, typ, span, var_scope);
     })
 }
 
@@ -517,6 +524,40 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             */
             _ => {}
         }
+
+        // If necessary, constrain destructors in the unadjusted form of this
+        // expression.
+        let cmt_result = {
+            let mc = mc::MemCategorizationContext::new(rcx.fcx);
+            mc.cat_expr_unadjusted(expr)
+        };
+        match cmt_result {
+            Ok(head_cmt) => {
+                check_safety_of_rvalue_destructor_if_necessary(rcx,
+                                                               head_cmt,
+                                                               expr.span);
+            }
+            Err(..) => {
+                rcx.fcx.tcx().sess.span_note(expr.span,
+                                             "cat_expr_unadjusted Errd during dtor check");
+            }
+        }
+    }
+
+    // If necessary, constrain destructors in this expression. This will be
+    // the adjusted form if there is an adjustment.
+    let cmt_result = {
+        let mc = mc::MemCategorizationContext::new(rcx.fcx);
+        mc.cat_expr(expr)
+    };
+    match cmt_result {
+        Ok(head_cmt) => {
+            check_safety_of_rvalue_destructor_if_necessary(rcx, head_cmt, expr.span);
+        }
+        Err(..) => {
+            rcx.fcx.tcx().sess.span_note(expr.span,
+                                         "cat_expr Errd during dtor check");
+        }
     }
 
     match expr.node {
@@ -995,6 +1036,33 @@ pub fn mk_subregion_due_to_dereference(rcx: &mut Rcx,
                     minimum_lifetime, maximum_lifetime)
 }
 
+fn check_safety_of_rvalue_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
+                                                            cmt: mc::cmt<'tcx>,
+                                                            span: Span) {
+    match cmt.cat {
+        mc::cat_rvalue(region) => {
+            match region {
+                ty::ReScope(rvalue_scope) => {
+                    let typ = rcx.resolve_type(cmt.ty);
+                    dropck::check_safety_of_destructor_if_necessary(rcx,
+                                                                    typ,
+                                                                    span,
+                                                                    rvalue_scope);
+                }
+                ty::ReStatic => {}
+                region => {
+                    rcx.tcx()
+                       .sess
+                       .span_bug(span,
+                                 format!("unexpected rvalue region in rvalue \
+                                          destructor safety checking: `{}`",
+                                         region.repr(rcx.tcx())).as_slice());
+                }
+            }
+        }
+        _ => {}
+    }
+}
 
 /// Invoked on any index expression that occurs. Checks that if this is a slice being indexed, the
 /// lifetime of the pointer includes the deref expr.
@@ -1404,7 +1472,7 @@ fn link_reborrowed_region<'a, 'tcx>(rcx: &Rcx<'a, 'tcx>,
 }
 
 /// Ensures that all borrowed data reachable via `ty` outlives `region`.
-fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
+pub fn type_must_outlive<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
                                origin: infer::SubregionOrigin<'tcx>,
                                ty: Ty<'tcx>,
                                region: ty::Region)
@@ -1520,8 +1588,8 @@ fn projection_bounds<'a,'tcx>(rcx: &Rcx<'a, 'tcx>,
     // ```
     //
     // we can thus deduce that `<T as SomeTrait<'a>>::SomeType : 'a`.
-    let trait_def = ty::lookup_trait_def(tcx, projection_ty.trait_ref.def_id);
-    let predicates = trait_def.generics.predicates.as_slice().to_vec();
+    let trait_predicates = ty::lookup_predicates(tcx, projection_ty.trait_ref.def_id);
+    let predicates = trait_predicates.predicates.as_slice().to_vec();
     traits::elaborate_predicates(tcx, predicates)
         .filter_map(|predicate| {
             // we're only interesting in `T : 'a` style predicates:
diff --git a/src/librustc_typeck/check/vtable.rs b/src/librustc_typeck/check/vtable.rs
index 00f6c6109fa..2e7eff68bd5 100644
--- a/src/librustc_typeck/check/vtable.rs
+++ b/src/librustc_typeck/check/vtable.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use check::{FnCtxt, structurally_resolved_type};
+use check::{FnCtxt};
 use check::demand;
 use middle::traits::{self, ObjectSafetyViolation, MethodViolationCode};
 use middle::traits::{Obligation, ObligationCause};
@@ -66,20 +66,11 @@ pub fn check_object_cast<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     demand::suptype(fcx, source_expr.span, source_expected_ty, source_ty);
 
     debug!("check_object_cast postunify source_ty={}", source_ty.repr(tcx));
-    let source_ty = structurally_resolved_type(fcx, source_expr.span, source_ty);
-    debug!("check_object_cast resolveto source_ty={}", source_ty.repr(tcx));
 
     let object_trait = object_trait(&object_trait_ty);
 
-    let referent_ty = match source_ty.sty {
-        ty::ty_uniq(ty) => ty,
-        ty::ty_rptr(_, ty::mt { ty, mutbl: _ }) => ty,
-        _ => fcx.tcx().sess.span_bug(source_expr.span,
-                                     "expected appropriate reference type"),
-    };
-
     // Ensure that if Ptr<T> is cast to Ptr<Trait>, then T : Trait.
-    push_cast_obligation(fcx, cast_expr, object_trait, referent_ty);
+    push_cast_obligation(fcx, cast_expr, object_trait, fresh_ty);
     check_object_safety(tcx, object_trait, source_expr.span);
 
     fn object_trait<'a, 'tcx>(t: &'a Ty<'tcx>) -> &'a ty::TyTrait<'tcx> {
diff --git a/src/librustc_typeck/check/wf.rs b/src/librustc_typeck/check/wf.rs
index 1079e87a48b..94670305be7 100644
--- a/src/librustc_typeck/check/wf.rs
+++ b/src/librustc_typeck/check/wf.rs
@@ -107,12 +107,12 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                 });
             }
             ast::ItemTrait(..) => {
-                let trait_def =
-                    ty::lookup_trait_def(ccx.tcx, local_def(item.id));
+                let trait_predicates =
+                    ty::lookup_predicates(ccx.tcx, local_def(item.id));
                 reject_non_type_param_bounds(
                     ccx.tcx,
                     item.span,
-                    &trait_def.generics);
+                    &trait_predicates);
             }
             _ => {}
         }
@@ -124,11 +124,13 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         let ccx = self.ccx;
         let item_def_id = local_def(item.id);
         let type_scheme = ty::lookup_item_type(ccx.tcx, item_def_id);
-        reject_non_type_param_bounds(ccx.tcx, item.span, &type_scheme.generics);
+        let type_predicates = ty::lookup_predicates(ccx.tcx, item_def_id);
+        reject_non_type_param_bounds(ccx.tcx, item.span, &type_predicates);
         let param_env =
             ty::construct_parameter_environment(ccx.tcx,
                                                 item.span,
                                                 &type_scheme.generics,
+                                                &type_predicates,
                                                 item.id);
         let inh = Inherited::new(ccx.tcx, param_env);
         let fcx = blank_fn_ctxt(ccx, &inh, ty::FnConverging(type_scheme.ty), item.id);
@@ -145,9 +147,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
             let variants = lookup_fields(fcx);
             let mut bounds_checker = BoundsChecker::new(fcx,
                                                         item.span,
-                                                        region::CodeExtent::from_node_id(item.id),
+                                                        item.id,
                                                         Some(&mut this.cache));
-            for variant in &variants {
+            debug!("check_type_defn at bounds_checker.scope: {:?}", bounds_checker.scope);
+
+             for variant in &variants {
                 for field in &variant.fields {
                     // Regions are checked below.
                     bounds_checker.check_traits_in_ty(field.ty);
@@ -180,8 +184,9 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
         self.with_fcx(item, |this, fcx| {
             let mut bounds_checker = BoundsChecker::new(fcx,
                                                         item.span,
-                                                        region::CodeExtent::from_node_id(item.id),
+                                                        item.id,
                                                         Some(&mut this.cache));
+            debug!("check_item_type at bounds_checker.scope: {:?}", bounds_checker.scope);
 
             let type_scheme = ty::lookup_item_type(fcx.tcx(), local_def(item.id));
             let item_ty = fcx.instantiate_type_scheme(item.span,
@@ -196,12 +201,11 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                   item: &ast::Item)
     {
         self.with_fcx(item, |this, fcx| {
-            let item_scope = region::CodeExtent::from_node_id(item.id);
-
             let mut bounds_checker = BoundsChecker::new(fcx,
                                                         item.span,
-                                                        item_scope,
+                                                        item.id,
                                                         Some(&mut this.cache));
+            debug!("check_impl at bounds_checker.scope: {:?}", bounds_checker.scope);
 
             // Find the impl self type as seen from the "inside" --
             // that is, with all type parameters converted from bound
@@ -281,9 +285,8 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> {
 // Reject any predicates that do not involve a type parameter.
 fn reject_non_type_param_bounds<'tcx>(tcx: &ty::ctxt<'tcx>,
                                       span: Span,
-                                      generics: &ty::Generics<'tcx>) {
-
-    for predicate in generics.predicates.iter() {
+                                      predicates: &ty::GenericPredicates<'tcx>) {
+    for predicate in predicates.predicates.iter() {
         match predicate {
             &ty::Predicate::Trait(ty::Binder(ref tr)) => {
                 let found_param = tr.input_types().iter()
@@ -365,7 +368,7 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
                         reject_non_type_param_bounds(
                             self.ccx.tcx,
                             method.span,
-                            &ty_method.generics);
+                            &ty_method.predicates);
                         reject_shadowing_type_parameters(
                             self.ccx.tcx,
                             method.span,
@@ -383,7 +386,12 @@ impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
 pub struct BoundsChecker<'cx,'tcx:'cx> {
     fcx: &'cx FnCtxt<'cx,'tcx>,
     span: Span,
-    scope: region::CodeExtent,
+
+    // This field is often attached to item impls; it is not clear
+    // that `CodeExtent` is well-defined for such nodes, so pnkfelix
+    // has left it as a NodeId rather than porting to CodeExtent.
+    scope: ast::NodeId,
+
     binding_count: uint,
     cache: Option<&'cx mut HashSet<Ty<'tcx>>>,
 }
@@ -391,7 +399,7 @@ pub struct BoundsChecker<'cx,'tcx:'cx> {
 impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
     pub fn new(fcx: &'cx FnCtxt<'cx,'tcx>,
                span: Span,
-               scope: region::CodeExtent,
+               scope: ast::NodeId,
                cache: Option<&'cx mut HashSet<Ty<'tcx>>>)
                -> BoundsChecker<'cx,'tcx> {
         BoundsChecker { fcx: fcx, span: span, scope: scope,
@@ -408,9 +416,11 @@ impl<'cx,'tcx> BoundsChecker<'cx,'tcx> {
     /// Note that it does not (currently, at least) check that `A : Copy` (that check is delegated
     /// to the point where impl `A : Trait<B>` is implemented).
     pub fn check_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
-        let trait_def = ty::lookup_trait_def(self.fcx.tcx(), trait_ref.def_id);
+        let trait_predicates = ty::lookup_predicates(self.fcx.tcx(), trait_ref.def_id);
 
-        let bounds = self.fcx.instantiate_bounds(self.span, trait_ref.substs, &trait_def.generics);
+        let bounds = self.fcx.instantiate_bounds(self.span,
+                                                 trait_ref.substs,
+                                                 &trait_predicates);
 
         self.fcx.add_obligations_for_parameters(
             traits::ObligationCause::new(
@@ -446,9 +456,12 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
         where T : TypeFoldable<'tcx> + Repr<'tcx>
     {
         self.binding_count += 1;
-        let value = liberate_late_bound_regions(self.fcx.tcx(), self.scope, binder);
-        debug!("BoundsChecker::fold_binder: late-bound regions replaced: {}",
-               value.repr(self.tcx()));
+        let value = liberate_late_bound_regions(
+            self.fcx.tcx(),
+            region::DestructionScopeData::new(self.scope),
+            binder);
+        debug!("BoundsChecker::fold_binder: late-bound regions replaced: {} at scope: {:?}",
+               value.repr(self.tcx()), self.scope);
         let value = value.fold_with(self);
         self.binding_count -= 1;
         ty::Binder(value)
@@ -472,8 +485,9 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> {
         match t.sty{
             ty::ty_struct(type_id, substs) |
             ty::ty_enum(type_id, substs) => {
-                let type_scheme = ty::lookup_item_type(self.fcx.tcx(), type_id);
-                let bounds = self.fcx.instantiate_bounds(self.span, substs, &type_scheme.generics);
+                let type_predicates = ty::lookup_predicates(self.fcx.tcx(), type_id);
+                let bounds = self.fcx.instantiate_bounds(self.span, substs,
+                                                         &type_predicates);
 
                 if self.binding_count == 0 {
                     self.fcx.add_obligations_for_parameters(
@@ -593,10 +607,10 @@ fn enum_variants<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         .collect()
 }
 
-fn filter_to_trait_obligations<'tcx>(bounds: ty::GenericBounds<'tcx>)
-                                     -> ty::GenericBounds<'tcx>
+fn filter_to_trait_obligations<'tcx>(bounds: ty::InstantiatedPredicates<'tcx>)
+                                     -> ty::InstantiatedPredicates<'tcx>
 {
-    let mut result = ty::GenericBounds::empty();
+    let mut result = ty::InstantiatedPredicates::empty();
     for (space, _, predicate) in bounds.predicates.iter_enumerated() {
         match *predicate {
             ty::Predicate::Trait(..) |
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index ed340b0882c..1542e74ff81 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -247,6 +247,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             debug!("new_polytype={}", new_polytype.repr(tcx));
 
             tcx.tcache.borrow_mut().insert(new_did, new_polytype);
+            tcx.predicates.borrow_mut().insert(new_did, new_method_ty.predicates.clone());
             tcx.impl_or_trait_items
                .borrow_mut()
                .insert(new_did, ty::MethodTraitItem(new_method_ty));
@@ -555,6 +556,7 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
     debug!("subst_receiver_types_in_method_ty: combined_substs={}",
            combined_substs.repr(tcx));
 
+    let method_predicates = method.predicates.subst(tcx, &combined_substs);
     let mut method_generics = method.generics.subst(tcx, &combined_substs);
 
     // replace the type parameters declared on the trait with those
@@ -579,6 +581,7 @@ fn subst_receiver_types_in_method_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
     ty::Method::new(
         method.name,
         method_generics,
+        method_predicates,
         method_fty,
         method.explicit_self,
         method.vis,
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index ce26658cf4b..8a1945c16a6 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -20,28 +20,83 @@ current crate: we assume that after the collect phase, the types of
 all local items will be present in the table.
 
 Unlike most of the types that are present in Rust, the types computed
-for each item are in fact polytypes.  In "layman's terms", this means
-that they are generic types that may have type parameters (more
-mathematically phrased, they are universally quantified over a set of
-type parameters).  TypeSchemes are represented by an instance of
-`ty::TypeScheme`.  This combines the core type along with a list of the
-bounds for each parameter.  Type parameters themselves are represented
-as `ty_param()` instances.
+for each item are in fact type schemes. This means that they are
+generic types that may have type parameters. TypeSchemes are
+represented by an instance of `ty::TypeScheme`.  This combines the
+core type along with a list of the bounds for each parameter. Type
+parameters themselves are represented as `ty_param()` instances.
+
+The phasing of type conversion is somewhat complicated. There are a
+number of possible cycles that can arise.
+
+Converting types can require:
+
+1. `Foo<X>` where `Foo` is a type alias, or trait requires knowing:
+   - number of region / type parameters
+   - for type parameters, `T:'a` annotations to control defaults for object lifetimes
+   - defaults for type parameters (which are themselves types!)
+2. `Foo<X>` where `Foo` is a type alias requires knowing what `Foo` expands to
+3. Translating `SomeTrait` with no explicit lifetime bound requires knowing
+   - supertraits of `SomeTrait`
+4. Translating `T::X` (vs `<T as Trait>::X`) requires knowing
+   - bounds on `T`
+   - supertraits of those bounds
+
+So as you can see, in general translating types requires knowing the
+trait hierarchy. But this gets a bit tricky because translating the
+trait hierarchy requires converting the types that appear in trait
+references. One potential saving grace is that in general knowing the
+trait hierarchy is only necessary for shorthands like `T::X` or
+handling omitted lifetime bounds on object types. Therefore, if we are
+lazy about expanding out the trait hierachy, users can sever cycles if
+necessary. Lazy expansion is also needed for type aliases.
+
+This system is not perfect yet. Currently, we "convert" types and
+traits in three phases (note that conversion only affects the types of
+items / enum variants / methods; it does not e.g. compute the types of
+individual expressions):
+
+0. Intrinsics
+1. Trait definitions
+2. Type definitions
+
+Conversion itself is done by simply walking each of the items in turn
+and invoking an appropriate function (e.g., `trait_def_of_item` or
+`convert_item`). However, it is possible that while converting an
+item, we may need to compute the *type scheme* or *trait definition*
+for other items. This is a kind of shallow conversion that is
+triggered on demand by calls to `AstConv::get_item_type_scheme` or
+`AstConv::lookup_trait_def`. It is possible for cycles to result from
+this (e.g., `type A = B; type B = A;`), in which case astconv
+(currently) reports the error.
+
+There are some shortcomings in this design:
+
+- Cycles through trait definitions (e.g. supertraits) are not currently
+  detected by astconv. (#12511)
+- Because the type scheme includes defaults, cycles through type
+  parameter defaults are illegal even if those defaults are never
+  employed. This is not necessarily a bug.
+- The phasing of trait definitions before type definitions does not
+  seem to be necessary, sufficient, or particularly helpful, given that
+  processing a trait definition can trigger processing a type def and
+  vice versa. However, if I remove it, I get ICEs, so some more work is
+  needed in that area. -nmatsakis
 
 */
+
 use astconv::{self, AstConv, ty_of_arg, ast_ty_to_ty, ast_region_to_region};
-use metadata::csearch;
 use middle::lang_items::SizedTraitLangItem;
 use middle::region;
 use middle::resolve_lifetime;
 use middle::subst;
-use middle::subst::{Substs, TypeSpace};
+use middle::subst::{Substs, SelfSpace, TypeSpace, VecPerParamSpace};
 use middle::ty::{AsPredicate, ImplContainer, ImplOrTraitItemContainer, TraitContainer};
 use middle::ty::{self, RegionEscape, Ty, TypeScheme};
 use middle::ty_fold::{self, TypeFolder, TypeFoldable};
 use middle::infer;
-use no_params;
 use rscope::*;
+use util::common::memoized;
 use util::nodemap::{FnvHashMap, FnvHashSet};
 use util::ppaux;
 use util::ppaux::{Repr,UserString};
@@ -130,11 +185,11 @@ struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx, 'v> visit::Visitor<'v> for CollectItemTypesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, i: &ast::Item) {
-        convert(self.ccx, i);
+        convert_item(self.ccx, i);
         visit::walk_item(self, i);
     }
     fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
-        convert_foreign(self.ccx, i);
+        convert_foreign_item(self.ccx, i);
         visit::walk_foreign_item(self, i);
     }
 }
@@ -157,16 +212,16 @@ impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> {
 
     fn get_item_type_scheme(&self, id: ast::DefId) -> ty::TypeScheme<'tcx> {
         if id.krate != ast::LOCAL_CRATE {
-            return csearch::get_type(self.tcx, id)
+            return ty::lookup_item_type(self.tcx, id);
         }
 
         match self.tcx.map.find(id.node) {
             Some(ast_map::NodeItem(item)) => {
-                ty_of_item(self, &*item)
+                type_scheme_of_item(self, &*item)
             }
             Some(ast_map::NodeForeignItem(foreign_item)) => {
                 let abi = self.tcx.map.get_foreign_abi(id.node);
-                ty_of_foreign_item(self, &*foreign_item, abi)
+                type_scheme_of_foreign_item(self, &*foreign_item, abi)
             }
             x => {
                 self.tcx.sess.bug(&format!("unexpected sort of node \
@@ -181,7 +236,7 @@ impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> {
     }
 
     fn ty_infer(&self, span: Span) -> Ty<'tcx> {
-        span_err!(self.tcx.sess, span, E0121,
+        span_err!(self.tcx().sess, span, E0121,
                   "the type placeholder `_` is not allowed within types on item signatures");
         self.tcx().types.err
     }
@@ -192,14 +247,14 @@ impl<'a, 'tcx> AstConv<'tcx> for CollectCtxt<'a, 'tcx> {
                     item_name: ast::Name)
                     -> Ty<'tcx>
     {
-        ty::mk_projection(self.tcx, trait_ref, item_name)
+        ty::mk_projection(self.tcx(), trait_ref, item_name)
     }
 }
 
 fn get_enum_variant_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
-                                        enum_ty: Ty<'tcx>,
-                                        variants: &[P<ast::Variant>],
-                                        generics: &ast::Generics) {
+                                    enum_scheme: ty::TypeScheme<'tcx>,
+                                    enum_predicates: ty::GenericPredicates<'tcx>,
+                                    variants: &[P<ast::Variant>]) {
     let tcx = ccx.tcx;
 
     // Create a set of parameter types shared among all the variants.
@@ -212,38 +267,35 @@ fn get_enum_variant_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
             ast::TupleVariantKind(ref args) if args.len() > 0 => {
                 let rs = ExplicitRscope;
                 let input_tys: Vec<_> = args.iter().map(|va| ccx.to_ty(&rs, &*va.ty)).collect();
-                ty::mk_ctor_fn(tcx, variant_def_id, &input_tys[], enum_ty)
+                ty::mk_ctor_fn(tcx, variant_def_id, &input_tys[], enum_scheme.ty)
             }
 
             ast::TupleVariantKind(_) => {
-                enum_ty
+                enum_scheme.ty
             }
 
             ast::StructVariantKind(ref struct_def) => {
-                let scheme = TypeScheme {
-                    generics: ty_generics_for_type_or_impl(ccx, generics),
-                    ty: enum_ty
-                };
-
-                convert_struct(ccx, &**struct_def, scheme, variant.node.id);
-                enum_ty
+                convert_struct(ccx, &**struct_def, enum_scheme.clone(),
+                               enum_predicates.clone(), variant.node.id);
+                enum_scheme.ty
             }
         };
 
-        let scheme = TypeScheme {
-            generics: ty_generics_for_type_or_impl(ccx, generics),
+        let variant_scheme = TypeScheme {
+            generics: enum_scheme.generics.clone(),
             ty: result_ty
         };
 
-        tcx.tcache.borrow_mut().insert(variant_def_id, scheme);
-
+        tcx.tcache.borrow_mut().insert(variant_def_id, variant_scheme.clone());
+        tcx.predicates.borrow_mut().insert(variant_def_id, enum_predicates.clone());
         write_ty_to_tcx(tcx, variant.node.id, result_ty);
     }
 }
 
 fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                    trait_id: ast::NodeId,
-                                   trait_def: &ty::TraitDef<'tcx>) {
+                                   trait_def: &ty::TraitDef<'tcx>,
+                                   trait_predicates: &ty::GenericPredicates<'tcx>) {
     let tcx = ccx.tcx;
     if let ast_map::NodeItem(item) = tcx.map.get(trait_id) {
         if let ast::ItemTrait(_, _, _, ref trait_items) = item.node {
@@ -259,6 +311,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                     ccx,
                                     trait_id,
                                     &trait_def.generics,
+                                    &trait_predicates,
                                     &trait_items[],
                                     &m.id,
                                     &m.ident.name,
@@ -273,6 +326,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                     ccx,
                                     trait_id,
                                     &trait_def.generics,
+                                    &trait_predicates,
                                     &trait_items[],
                                     &m.id,
                                     &m.pe_ident().name,
@@ -342,12 +396,17 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
             m.def_id,
             TypeScheme {
                 generics: m.generics.clone(),
-                ty: ty::mk_bare_fn(ccx.tcx, Some(m.def_id), ccx.tcx.mk_bare_fn(m.fty.clone())) });
+                ty: ty::mk_bare_fn(ccx.tcx, Some(m.def_id), ccx.tcx.mk_bare_fn(m.fty.clone()))
+            });
+        ccx.tcx.predicates.borrow_mut().insert(
+            m.def_id,
+            m.predicates.clone());
     }
 
     fn ty_method_of_trait_method<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                            trait_id: ast::NodeId,
                                            trait_generics: &ty::Generics<'tcx>,
+                                           trait_bounds: &ty::GenericPredicates<'tcx>,
                                            _trait_items: &[ast::TraitItem],
                                            m_id: &ast::NodeId,
                                            m_name: &ast::Name,
@@ -358,10 +417,15 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                            m_decl: &ast::FnDecl)
                                            -> ty::Method<'tcx> {
         let ty_generics =
-            ty_generics_for_fn_or_method(
-                ccx,
-                m_generics,
-                (*trait_generics).clone());
+            ty_generics_for_fn_or_method(ccx,
+                                         m_generics,
+                                         trait_generics.clone());
+
+        let ty_bounds =
+            ty_generic_bounds_for_fn_or_method(ccx,
+                                               m_generics,
+                                               &ty_generics,
+                                               trait_bounds.clone());
 
         let (fty, explicit_self_category) = {
             let trait_self_ty = ty::mk_self_type(ccx.tcx);
@@ -376,6 +440,7 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
         ty::Method::new(
             *m_name,
             ty_generics,
+            ty_bounds,
             fty,
             explicit_self_category,
             // assume public, because this is only invoked on trait methods
@@ -389,16 +454,20 @@ fn collect_trait_methods<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
 
 fn convert_field<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                 struct_generics: &ty::Generics<'tcx>,
+                                struct_predicates: &ty::GenericPredicates<'tcx>,
                                 v: &ast::StructField,
                                 origin: ast::DefId) -> ty::field_ty {
     let tt = ccx.to_ty(&ExplicitRscope, &*v.node.ty);
     write_ty_to_tcx(ccx.tcx, v.node.id, tt);
+
     /* add the field to the tcache */
     ccx.tcx.tcache.borrow_mut().insert(local_def(v.node.id),
                                        ty::TypeScheme {
                                            generics: struct_generics.clone(),
                                            ty: tt
                                        });
+    ccx.tcx.predicates.borrow_mut().insert(local_def(v.node.id),
+                                           struct_predicates.clone());
 
     match v.node.kind {
         ast::NamedField(ident, visibility) => {
@@ -442,6 +511,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>,
                                  ms: I,
                                  untransformed_rcvr_ty: Ty<'tcx>,
                                  rcvr_ty_generics: &ty::Generics<'tcx>,
+                                 rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,
                                  rcvr_visibility: ast::Visibility)
                                  where I: Iterator<Item=&'i ast::Method> {
     debug!("convert_methods(untransformed_rcvr_ty={}, rcvr_ty_generics={})",
@@ -456,11 +526,13 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>,
         }
 
         let m_def_id = local_def(m.id);
+
         let mty = Rc::new(ty_of_method(ccx,
                                        container,
                                        m,
                                        untransformed_rcvr_ty,
                                        rcvr_ty_generics,
+                                       rcvr_ty_predicates,
                                        rcvr_visibility));
         let fty = ty::mk_bare_fn(tcx, Some(m_def_id), tcx.mk_bare_fn(mty.fty.clone()));
         debug!("method {} (id {}) has type {}",
@@ -473,6 +545,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>,
                 generics: mty.generics.clone(),
                 ty: fty
             });
+        tcx.predicates.borrow_mut().insert(m_def_id, mty.predicates.clone());
 
         write_ty_to_tcx(tcx, m.id, fty);
 
@@ -489,13 +562,19 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>,
                               m: &ast::Method,
                               untransformed_rcvr_ty: Ty<'tcx>,
                               rcvr_ty_generics: &ty::Generics<'tcx>,
+                              rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,
                               rcvr_visibility: ast::Visibility)
                               -> ty::Method<'tcx> {
         let m_ty_generics =
-            ty_generics_for_fn_or_method(
-                ccx,
-                m.pe_generics(),
-                (*rcvr_ty_generics).clone());
+            ty_generics_for_fn_or_method(ccx,
+                                         m.pe_generics(),
+                                         rcvr_ty_generics.clone());
+
+        let m_ty_bounds =
+            ty_generic_bounds_for_fn_or_method(ccx,
+                                               m.pe_generics(),
+                                               &m_ty_generics,
+                                               rcvr_ty_predicates.clone());
 
         let (fty, explicit_self_category) = astconv::ty_of_method(ccx,
                                                                   m.pe_unsafety(),
@@ -512,6 +591,7 @@ fn convert_methods<'a,'tcx,'i,I>(ccx: &CollectCtxt<'a, 'tcx>,
 
         ty::Method::new(m.pe_ident().name,
                         m_ty_generics,
+                        m_ty_bounds,
                         fty,
                         explicit_self_category,
                         method_vis,
@@ -550,20 +630,21 @@ fn ensure_no_ty_param_bounds(ccx: &CollectCtxt,
     }
 }
 
-fn convert(ccx: &CollectCtxt, it: &ast::Item) {
+fn convert_item(ccx: &CollectCtxt, it: &ast::Item) {
     let tcx = ccx.tcx;
     debug!("convert: item {} with id {}", token::get_ident(it.ident), it.id);
     match it.node {
         // These don't define types.
         ast::ItemExternCrate(_) | ast::ItemUse(_) |
-        ast::ItemForeignMod(_) | ast::ItemMod(_) | ast::ItemMac(_) => {}
-        ast::ItemEnum(ref enum_definition, ref generics) => {
-            let scheme = ty_of_item(ccx, it);
+        ast::ItemForeignMod(_) | ast::ItemMod(_) | ast::ItemMac(_) => {
+        }
+        ast::ItemEnum(ref enum_definition, _) => {
+            let (scheme, predicates) = convert_typed_item(ccx, it);
             write_ty_to_tcx(tcx, it.id, scheme.ty);
             get_enum_variant_types(ccx,
-                                   scheme.ty,
-                                   &enum_definition.variants,
-                                   generics);
+                                   scheme,
+                                   predicates,
+                                   &enum_definition.variants);
         },
         ast::ItemImpl(_, _,
                       ref generics,
@@ -571,18 +652,21 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) {
                       ref selfty,
                       ref impl_items) => {
             // Create generics from the generics specified in the impl head.
+
+            debug!("convert: ast_generics={:?}", generics);
             let ty_generics = ty_generics_for_type_or_impl(ccx, generics);
+            let ty_predicates = ty_generic_bounds_for_type_or_impl(ccx, &ty_generics, generics);
+
+            debug!("convert: impl_bounds={:?}", ty_predicates);
 
             let selfty = ccx.to_ty(&ExplicitRscope, &**selfty);
             write_ty_to_tcx(tcx, it.id, selfty);
 
-            tcx.tcache
-               .borrow_mut()
-               .insert(local_def(it.id),
-                       TypeScheme {
-                        generics: ty_generics.clone(),
-                        ty: selfty,
-                       });
+            tcx.tcache.borrow_mut().insert(local_def(it.id),
+                                           TypeScheme { generics: ty_generics.clone(),
+                                                        ty: selfty });
+            tcx.predicates.borrow_mut().insert(local_def(it.id),
+                                               ty_predicates.clone());
 
             // If there is a trait reference, treat the methods as always public.
             // This is to work around some incorrect behavior in privacy checking:
@@ -614,14 +698,14 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) {
                         }
 
                         let typ = ccx.to_ty(&ExplicitRscope, &*typedef.typ);
-                        tcx.tcache
-                           .borrow_mut()
-                           .insert(local_def(typedef.id),
-                                   TypeScheme {
-                                    generics: ty::Generics::empty(),
-                                    ty: typ,
-                                   });
-                        write_ty_to_tcx(ccx.tcx, typedef.id, typ);
+                        tcx.tcache.borrow_mut().insert(local_def(typedef.id),
+                                                       TypeScheme {
+                                                           generics: ty::Generics::empty(),
+                                                           ty: typ,
+                                                       });
+                        tcx.predicates.borrow_mut().insert(local_def(typedef.id),
+                                                           ty::GenericPredicates::empty());
+                        write_ty_to_tcx(tcx, typedef.id, typ);
 
                         let associated_type = Rc::new(ty::AssociatedType {
                             name: typedef.ident.name,
@@ -642,6 +726,7 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) {
                             methods.into_iter(),
                             selfty,
                             &ty_generics,
+                            &ty_predicates,
                             parent_visibility);
 
             if let Some(ref trait_ref) = *opt_trait_ref {
@@ -652,16 +737,16 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) {
                                                None);
             }
 
-            enforce_impl_ty_params_are_constrained(ccx.tcx,
+            enforce_impl_ty_params_are_constrained(tcx,
                                                    generics,
                                                    local_def(it.id));
         },
         ast::ItemTrait(_, _, _, ref trait_methods) => {
             let trait_def = trait_def_of_item(ccx, it);
+            convert_trait_predicates(ccx, it);
+            let trait_predicates = ty::lookup_predicates(ccx.tcx, local_def(it.id));
 
-            debug!("trait_def: ident={} trait_def={}",
-                   it.ident.repr(ccx.tcx),
-                   trait_def.repr(ccx.tcx));
+            debug!("convert: trait_bounds={:?}", trait_predicates);
 
             for trait_method in trait_methods {
                 let self_type = ty::mk_self_type(tcx);
@@ -700,47 +785,46 @@ fn convert(ccx: &CollectCtxt, it: &ast::Item) {
                             }),
                             untransformed_rcvr_ty,
                             &trait_def.generics,
+                            &trait_predicates,
                             it.vis);
 
             // We need to do this *after* converting methods, since
             // convert_methods produces a tcache entry that is wrong for
             // static trait methods. This is somewhat unfortunate.
-            collect_trait_methods(ccx, it.id, &*trait_def);
+            collect_trait_methods(ccx, it.id, &*trait_def, &trait_predicates);
         },
         ast::ItemStruct(ref struct_def, _) => {
             // Write the class type.
-            let scheme = ty_of_item(ccx, it);
+            let (scheme, predicates) = convert_typed_item(ccx, it);
             write_ty_to_tcx(tcx, it.id, scheme.ty);
-
-            tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone());
-
-            convert_struct(ccx, &**struct_def, scheme, it.id);
+            convert_struct(ccx, &**struct_def, scheme, predicates, it.id);
         },
         ast::ItemTy(_, ref generics) => {
             ensure_no_ty_param_bounds(ccx, it.span, generics, "type");
-            let tpt = ty_of_item(ccx, it);
-            write_ty_to_tcx(tcx, it.id, tpt.ty);
+            let (scheme, _) = convert_typed_item(ccx, it);
+            write_ty_to_tcx(tcx, it.id, scheme.ty);
         },
         _ => {
             // This call populates the type cache with the converted type
             // of the item in passing. All we have to do here is to write
             // it into the node type table.
-            let scheme = ty_of_item(ccx, it);
+            let (scheme, _) = convert_typed_item(ccx, it);
             write_ty_to_tcx(tcx, it.id, scheme.ty);
         },
     }
 }
 
 fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
-                                struct_def: &ast::StructDef,
-                                scheme: ty::TypeScheme<'tcx>,
-                                id: ast::NodeId) {
+                            struct_def: &ast::StructDef,
+                            scheme: ty::TypeScheme<'tcx>,
+                            predicates: ty::GenericPredicates<'tcx>,
+                            id: ast::NodeId) {
     let tcx = ccx.tcx;
 
     // Write the type of each of the members and check for duplicate fields.
     let mut seen_fields: FnvHashMap<ast::Name, Span> = FnvHashMap();
     let field_tys = struct_def.fields.iter().map(|f| {
-        let result = convert_field(ccx, &scheme.generics, f, local_def(id));
+        let result = convert_field(ccx, &scheme.generics, &predicates, f, local_def(id));
 
         if result.name != special_idents::unnamed_field.name {
             let dup = match seen_fields.get(&result.name) {
@@ -778,6 +862,7 @@ fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                 write_ty_to_tcx(tcx, ctor_id, selfty);
 
                 tcx.tcache.borrow_mut().insert(local_def(ctor_id), scheme);
+                tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates);
             } else if struct_def.fields[0].node.kind.is_unnamed() {
                 // Tuple-like.
                 let inputs: Vec<_> = struct_def.fields.iter().map(
@@ -789,44 +874,30 @@ fn convert_struct<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                                 selfty);
                 write_ty_to_tcx(tcx, ctor_id, ctor_fn_ty);
                 tcx.tcache.borrow_mut().insert(local_def(ctor_id),
-                                  TypeScheme {
-                    generics: scheme.generics,
-                    ty: ctor_fn_ty
-                });
+                                               TypeScheme {
+                                                   generics: scheme.generics,
+                                                   ty: ctor_fn_ty
+                                               });
+                tcx.predicates.borrow_mut().insert(local_def(ctor_id), predicates);
             }
         }
     }
 }
 
-fn convert_foreign(ccx: &CollectCtxt, i: &ast::ForeignItem) {
-    // As above, this call populates the type table with the converted
-    // type of the foreign item. We simply write it into the node type
-    // table.
-
-    // For reasons I cannot fully articulate, I do so hate the AST
-    // map, and I regard each time that I use it as a personal and
-    // moral failing, but at the moment it seems like the only
-    // convenient way to extract the ABI. - ndm
-    let abi = ccx.tcx.map.get_foreign_abi(i.id);
-
-    let scheme = ty_of_foreign_item(ccx, i, abi);
-    write_ty_to_tcx(ccx.tcx, i.id, scheme.ty);
-
-    ccx.tcx.tcache.borrow_mut().insert(local_def(i.id), scheme);
-}
-
 fn get_trait_def<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                            trait_id: ast::DefId)
                            -> Rc<ty::TraitDef<'tcx>> {
+    let tcx = ccx.tcx;
+
     if trait_id.krate != ast::LOCAL_CRATE {
-        return ty::lookup_trait_def(ccx.tcx, trait_id)
+        return ty::lookup_trait_def(tcx, trait_id)
     }
 
-    match ccx.tcx.map.get(trait_id.node) {
+    match tcx.map.get(trait_id.node) {
         ast_map::NodeItem(item) => trait_def_of_item(ccx, &*item),
         _ => {
-            ccx.tcx.sess.bug(&format!("get_trait_def({}): not an item",
-                                     trait_id.node)[])
+            tcx.sess.bug(&format!("get_trait_def({}): not an item",
+                                  trait_id.node)[])
         }
     }
 }
@@ -837,6 +908,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
 {
     let def_id = local_def(it.id);
     let tcx = ccx.tcx;
+
     if let Some(def) = tcx.trait_defs.borrow().get(&def_id) {
         return def.clone();
     }
@@ -868,16 +940,13 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
 
     let substs = ccx.tcx.mk_substs(mk_trait_substs(ccx, generics));
 
-    let ty_generics = ty_generics_for_trait(ccx,
-                                            it.id,
-                                            substs,
-                                            generics,
-                                            items);
+    let ty_generics = ty_generics_for_trait(ccx, it.id, substs, generics);
 
-    let self_param_ty = ty::ParamTy::for_self();
+    let self_param_ty = ty::ParamTy::for_self().to_ty(ccx.tcx);
 
+    // supertraits:
     let bounds = compute_bounds(ccx,
-                                self_param_ty.to_ty(ccx.tcx),
+                                self_param_ty,
                                 bounds,
                                 SizedByDefault::No,
                                 it.span);
@@ -890,11 +959,11 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                      ast::TypeTraitItem(ref data) => Some(data.ty_param.ident.name),
                  }
              })
-            .collect();
+             .collect();
 
     let trait_ref = Rc::new(ty::TraitRef {
         def_id: def_id,
-        substs: substs
+        substs: substs,
     });
 
     let trait_def = Rc::new(ty::TraitDef {
@@ -905,6 +974,7 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
         trait_ref: trait_ref,
         associated_type_names: associated_type_names,
     });
+
     tcx.trait_defs.borrow_mut().insert(def_id, trait_def.clone());
 
     return trait_def;
@@ -913,6 +983,8 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                  generics: &ast::Generics)
                                  -> subst::Substs<'tcx>
     {
+        let tcx = ccx.tcx;
+
         // Creates a no-op substitution for the trait's type parameters.
         let regions =
             generics.lifetimes
@@ -929,121 +1001,267 @@ fn trait_def_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
             generics.ty_params
                     .iter()
                     .enumerate()
-                    .map(|(i, def)| ty::mk_param(ccx.tcx, subst::TypeSpace,
+                    .map(|(i, def)| ty::mk_param(tcx, subst::TypeSpace,
                                                  i as u32, def.ident.name))
                     .collect();
 
         // ...and also create the `Self` parameter.
-        let self_ty = ty::mk_self_type(ccx.tcx);
+        let self_ty = ty::mk_self_type(tcx);
 
         subst::Substs::new_trait(types, regions, self_ty)
     }
 }
 
-fn ty_of_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Item)
-                            -> ty::TypeScheme<'tcx> {
-    let def_id = local_def(it.id);
+fn convert_trait_predicates<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>, it: &ast::Item) {
     let tcx = ccx.tcx;
-    if let Some(scheme) = tcx.tcache.borrow().get(&def_id) {
-        return scheme.clone();
+    let trait_def = trait_def_of_item(ccx, it);
+
+    let def_id = local_def(it.id);
+
+    let (generics, items) = match it.node {
+        ast::ItemTrait(_, ref generics, _, ref items) => (generics, items),
+        ref s => {
+            tcx.sess.span_bug(
+                it.span,
+                &format!("trait_def_of_item invoked on {:?}", s)[]);
+        }
+    };
+
+    let self_param_ty = ty::ParamTy::for_self().to_ty(ccx.tcx);
+
+    let super_predicates = ty::predicates(ccx.tcx, self_param_ty, &trait_def.bounds);
+
+    let assoc_predicates = predicates_for_associated_types(ccx, &trait_def.trait_ref, items);
+
+    // `ty_generic_bounds` below will consider the bounds on the type
+    // parameters (including `Self`) and the explicit where-clauses,
+    // but to get the full set of predicates on a trait we need to add
+    // in the supertrait bounds and anything declared on the
+    // associated types.
+    let mut base_predicates =
+        ty::GenericPredicates {
+            predicates: VecPerParamSpace::new(super_predicates, vec![], vec![])
+        };
+    base_predicates.predicates.extend(subst::TypeSpace, assoc_predicates.into_iter());
+
+    let self_bounds = &trait_def.generics.types.get_self().unwrap().bounds;
+    base_predicates.predicates.extend(
+        subst::SelfSpace,
+        ty::predicates(ccx.tcx, self_param_ty, self_bounds).into_iter());
+
+    // add in the explicit where-clauses
+    let trait_predicates =
+        ty_generic_bounds(ccx,
+                          subst::TypeSpace,
+                          &trait_def.generics,
+                          base_predicates,
+                          &generics.where_clause);
+
+    let prev_predicates = tcx.predicates.borrow_mut().insert(def_id, trait_predicates);
+    assert!(prev_predicates.is_none());
+
+    return;
+
+    fn predicates_for_associated_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+                                                 self_trait_ref: &Rc<ty::TraitRef<'tcx>>,
+                                                 trait_items: &[ast::TraitItem])
+                                                 -> Vec<ty::Predicate<'tcx>>
+    {
+        trait_items
+            .iter()
+            .flat_map(|trait_item| {
+                let assoc_type_def = match *trait_item {
+                    ast::TypeTraitItem(ref assoc_type) => &assoc_type.ty_param,
+                    ast::RequiredMethod(..) | ast::ProvidedMethod(..) => {
+                        return vec!().into_iter();
+                    }
+                };
+
+                let assoc_ty = ty::mk_projection(ccx.tcx,
+                                                 self_trait_ref.clone(),
+                                                 assoc_type_def.ident.name);
+
+                let bounds = compute_bounds(ccx,
+                                            assoc_ty,
+                                            &*assoc_type_def.bounds,
+                                            SizedByDefault::Yes,
+                                            assoc_type_def.span);
+
+                ty::predicates(ccx.tcx, assoc_ty, &bounds).into_iter()
+            })
+            .collect()
     }
+}
+
+fn type_scheme_of_item<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+                                it: &ast::Item)
+                                -> ty::TypeScheme<'tcx>
+{
+    memoized(&ccx.tcx.tcache,
+             local_def(it.id),
+             |_| compute_type_scheme_of_item(ccx, it))
+}
+
+
+fn compute_type_scheme_of_item<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+                                              it: &ast::Item)
+                                              -> ty::TypeScheme<'tcx>
+{
+    let tcx = ccx.tcx;
     match it.node {
         ast::ItemStatic(ref t, _, _) | ast::ItemConst(ref t, _) => {
-            let typ = ccx.to_ty(&ExplicitRscope, &**t);
-            let scheme = no_params(typ);
-
-            tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone());
-            return scheme;
+            let ty = ccx.to_ty(&ExplicitRscope, &**t);
+            ty::TypeScheme { ty: ty, generics: ty::Generics::empty() }
         }
         ast::ItemFn(ref decl, unsafety, abi, ref generics, _) => {
             let ty_generics = ty_generics_for_fn_or_method(ccx,
                                                            generics,
                                                            ty::Generics::empty());
             let tofd = astconv::ty_of_bare_fn(ccx, unsafety, abi, &**decl);
-            let scheme = TypeScheme {
-                generics: ty_generics,
-                ty: ty::mk_bare_fn(ccx.tcx, Some(local_def(it.id)), ccx.tcx.mk_bare_fn(tofd))
-            };
-            debug!("type of {} (id {}) is {}",
-                    token::get_ident(it.ident),
-                    it.id,
-                    scheme.repr(tcx));
-
-            ccx.tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone());
-            return scheme;
+            let ty = ty::mk_bare_fn(tcx, Some(local_def(it.id)), tcx.mk_bare_fn(tofd));
+            ty::TypeScheme { ty: ty, generics: ty_generics }
         }
         ast::ItemTy(ref t, ref generics) => {
-            match tcx.tcache.borrow_mut().get(&local_def(it.id)) {
-                Some(scheme) => return scheme.clone(),
-                None => { }
-            }
-
-            let scheme = {
-                let ty = ccx.to_ty(&ExplicitRscope, &**t);
-                TypeScheme {
-                    generics: ty_generics_for_type_or_impl(ccx, generics),
-                    ty: ty
-                }
-            };
-
-            tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone());
-            return scheme;
+            let ty = ccx.to_ty(&ExplicitRscope, &**t);
+            let ty_generics = ty_generics_for_type_or_impl(ccx, generics);
+            ty::TypeScheme { ty: ty, generics: ty_generics }
         }
         ast::ItemEnum(_, ref generics) => {
             // Create a new generic polytype.
             let ty_generics = ty_generics_for_type_or_impl(ccx, generics);
             let substs = mk_item_substs(ccx, &ty_generics);
             let t = ty::mk_enum(tcx, local_def(it.id), tcx.mk_substs(substs));
-            let scheme = TypeScheme {
-                generics: ty_generics,
-                ty: t
-            };
-
-            tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone());
-            return scheme;
-        }
-        ast::ItemTrait(..) => {
-            tcx.sess.span_bug(it.span, "invoked ty_of_item on trait");
+            ty::TypeScheme { ty: t, generics: ty_generics }
         }
         ast::ItemStruct(_, ref generics) => {
             let ty_generics = ty_generics_for_type_or_impl(ccx, generics);
             let substs = mk_item_substs(ccx, &ty_generics);
             let t = ty::mk_struct(tcx, local_def(it.id), tcx.mk_substs(substs));
-            let scheme = TypeScheme {
-                generics: ty_generics,
-                ty: t
-            };
-
-            tcx.tcache.borrow_mut().insert(local_def(it.id), scheme.clone());
-            return scheme;
+            ty::TypeScheme { ty: t, generics: ty_generics }
+        }
+        ast::ItemTrait(..) |
+        ast::ItemImpl(..) |
+        ast::ItemMod(..) |
+        ast::ItemForeignMod(..) |
+        ast::ItemExternCrate(..) |
+        ast::ItemUse(..) |
+        ast::ItemMac(..) => {
+            tcx.sess.span_bug(
+                it.span,
+                format!("compute_type_scheme_of_item: unexpected item type: {:?}",
+                        it.node).as_slice());
         }
-        ast::ItemExternCrate(_) | ast::ItemUse(_) |
-        ast::ItemImpl(..) | ast::ItemMod(_) |
-        ast::ItemForeignMod(_) | ast::ItemMac(_) => panic!(),
     }
 }
 
-fn ty_of_foreign_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
-                                    it: &ast::ForeignItem,
-                                    abi: abi::Abi) -> ty::TypeScheme<'tcx>
+fn convert_typed_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+                                it: &ast::Item)
+                                -> (ty::TypeScheme<'tcx>, ty::GenericPredicates<'tcx>)
+{
+    let tcx = ccx.tcx;
+
+    let tag = type_scheme_of_item(ccx, it);
+    let scheme = TypeScheme { generics: tag.generics, ty: tag.ty };
+    let predicates = match it.node {
+        ast::ItemStatic(..) | ast::ItemConst(..) => {
+            ty::GenericPredicates::empty()
+        }
+        ast::ItemFn(_, _, _, ref ast_generics, _) => {
+            ty_generic_bounds_for_fn_or_method(ccx,
+                                               ast_generics,
+                                               &scheme.generics,
+                                               ty::GenericPredicates::empty())
+        }
+        ast::ItemTy(_, ref generics) => {
+            ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics)
+        }
+        ast::ItemEnum(_, ref generics) => {
+            ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics)
+        }
+        ast::ItemStruct(_, ref generics) => {
+            ty_generic_bounds_for_type_or_impl(ccx, &scheme.generics, generics)
+        }
+        ast::ItemTrait(..) |
+        ast::ItemExternCrate(..) |
+        ast::ItemUse(..) |
+        ast::ItemImpl(..) |
+        ast::ItemMod(..) |
+        ast::ItemForeignMod(..) |
+        ast::ItemMac(..) => {
+            tcx.sess.span_bug(
+                it.span,
+                format!("compute_type_scheme_of_item: unexpected item type: {:?}",
+                        it.node).as_slice());
+        }
+    };
+
+    let prev_predicates = tcx.predicates.borrow_mut().insert(local_def(it.id),
+                                                             predicates.clone());
+    assert!(prev_predicates.is_none());
+
+    return (scheme, predicates);
+
+}
+
+fn type_scheme_of_foreign_item<'a, 'tcx>(
+    ccx: &CollectCtxt<'a, 'tcx>,
+    it: &ast::ForeignItem,
+    abi: abi::Abi)
+    -> ty::TypeScheme<'tcx>
+{
+    memoized(&ccx.tcx().tcache,
+             local_def(it.id),
+             |_| compute_type_scheme_of_foreign_item(ccx, it, abi))
+}
+
+fn compute_type_scheme_of_foreign_item<'a, 'tcx>(
+    ccx: &CollectCtxt<'a, 'tcx>,
+    it: &ast::ForeignItem,
+    abi: abi::Abi)
+    -> ty::TypeScheme<'tcx>
 {
     match it.node {
         ast::ForeignItemFn(ref fn_decl, ref generics) => {
-            ty_of_foreign_fn_decl(ccx,
-                                  &**fn_decl,
-                                  local_def(it.id),
-                                  generics,
-                                  abi)
+            compute_type_scheme_of_foreign_fn_decl(ccx, fn_decl, generics, abi)
         }
         ast::ForeignItemStatic(ref t, _) => {
             ty::TypeScheme {
                 generics: ty::Generics::empty(),
-                ty: ast_ty_to_ty(ccx, &ExplicitRscope, &**t)
+                ty: ast_ty_to_ty(ccx, &ExplicitRscope, t)
             }
         }
     }
 }
 
+fn convert_foreign_item<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
+                                  it: &ast::ForeignItem)
+{
+    // For reasons I cannot fully articulate, I do so hate the AST
+    // map, and I regard each time that I use it as a personal and
+    // moral failing, but at the moment it seems like the only
+    // convenient way to extract the ABI. - ndm
+    let tcx = ccx.tcx;
+    let abi = tcx.map.get_foreign_abi(it.id);
+
+    let scheme = type_scheme_of_foreign_item(ccx, it, abi);
+    write_ty_to_tcx(ccx.tcx, it.id, scheme.ty);
+
+    let predicates = match it.node {
+        ast::ForeignItemFn(_, ref generics) => {
+            ty_generic_bounds_for_fn_or_method(ccx,
+                                               generics,
+                                               &scheme.generics,
+                                               ty::GenericPredicates::empty())
+        }
+        ast::ForeignItemStatic(..) => {
+            ty::GenericPredicates::empty()
+        }
+    };
+
+    let prev_predicates = tcx.predicates.borrow_mut().insert(local_def(it.id), predicates);
+    assert!(prev_predicates.is_none());
+}
+
 fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                           generics: &ast::Generics)
                                           -> ty::Generics<'tcx> {
@@ -1051,15 +1269,25 @@ fn ty_generics_for_type_or_impl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                 subst::TypeSpace,
                 &generics.lifetimes[],
                 &generics.ty_params[],
-                ty::Generics::empty(),
-                &generics.where_clause)
+                ty::Generics::empty())
+}
+
+fn ty_generic_bounds_for_type_or_impl<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+                                               ty_generics: &ty::Generics<'tcx>,
+                                               generics: &ast::Generics)
+                                               -> ty::GenericPredicates<'tcx>
+{
+    ty_generic_bounds(ccx,
+                      subst::TypeSpace,
+                      ty_generics,
+                      ty::GenericPredicates::empty(),
+                      &generics.where_clause)
 }
 
 fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                    trait_id: ast::NodeId,
                                    substs: &'tcx subst::Substs<'tcx>,
-                                   ast_generics: &ast::Generics,
-                                   trait_items: &[ast::TraitItem])
+                                   ast_generics: &ast::Generics)
                                    -> ty::Generics<'tcx>
 {
     debug!("ty_generics_for_trait(trait_id={}, substs={})",
@@ -1070,8 +1298,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                     subst::TypeSpace,
                     &ast_generics.lifetimes[],
                     &ast_generics.ty_params[],
-                    ty::Generics::empty(),
-                    &ast_generics.where_clause);
+                    ty::Generics::empty());
 
     // Add in the self type parameter.
     //
@@ -1101,49 +1328,7 @@ fn ty_generics_for_trait<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
 
     generics.types.push(subst::SelfSpace, def);
 
-    generics.predicates.push(subst::SelfSpace, self_trait_ref.as_predicate());
-
-    let assoc_predicates = predicates_for_associated_types(ccx,
-                                                           &self_trait_ref,
-                                                           trait_items);
-
-    debug!("ty_generics_for_trait: assoc_predicates={}", assoc_predicates.repr(ccx.tcx));
-
-    for assoc_predicate in assoc_predicates {
-        generics.predicates.push(subst::TypeSpace, assoc_predicate);
-    }
-
     return generics;
-
-    fn predicates_for_associated_types<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
-                                                 self_trait_ref: &Rc<ty::TraitRef<'tcx>>,
-                                                 trait_items: &[ast::TraitItem])
-                                                 -> Vec<ty::Predicate<'tcx>>
-    {
-        trait_items
-            .iter()
-            .flat_map(|trait_item| {
-                let assoc_type_def = match *trait_item {
-                    ast::TypeTraitItem(ref assoc_type) => &assoc_type.ty_param,
-                    ast::RequiredMethod(..) | ast::ProvidedMethod(..) => {
-                        return vec!().into_iter();
-                    }
-                };
-
-                let assoc_ty = ty::mk_projection(ccx.tcx,
-                                                 self_trait_ref.clone(),
-                                                 assoc_type_def.ident.name);
-
-                let bounds = compute_bounds(ccx,
-                                            assoc_ty,
-                                            &*assoc_type_def.bounds,
-                                            SizedByDefault::Yes,
-                                            assoc_type_def.span);
-
-                ty::predicates(ccx.tcx, assoc_ty, &bounds).into_iter()
-            })
-            .collect()
-    }
 }
 
 fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
@@ -1156,8 +1341,20 @@ fn ty_generics_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                 subst::FnSpace,
                 &early_lifetimes[],
                 &generics.ty_params[],
-                base_generics,
-                &generics.where_clause)
+                base_generics)
+}
+
+fn ty_generic_bounds_for_fn_or_method<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+                                               generics: &ast::Generics,
+                                               ty_generics: &ty::Generics<'tcx>,
+                                               base: ty::GenericPredicates<'tcx>)
+                                               -> ty::GenericPredicates<'tcx>
+{
+    ty_generic_bounds(ccx,
+                      subst::FnSpace,
+                      ty_generics,
+                      base,
+                      &generics.where_clause)
 }
 
 // Add the Sized bound, unless the type parameter is marked as `?Sized`.
@@ -1207,47 +1404,29 @@ fn add_unsized_bound<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
     }
 }
 
-fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
-                        space: subst::ParamSpace,
-                        lifetime_defs: &[ast::LifetimeDef],
-                        types: &[ast::TyParam],
-                        base_generics: ty::Generics<'tcx>,
-                        where_clause: &ast::WhereClause)
-                        -> ty::Generics<'tcx>
+fn ty_generic_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+                              space: subst::ParamSpace,
+                              generics: &ty::Generics<'tcx>,
+                              base: ty::GenericPredicates<'tcx>,
+                              where_clause: &ast::WhereClause)
+                              -> ty::GenericPredicates<'tcx>
 {
-    let mut result = base_generics;
-
-    for (i, l) in lifetime_defs.iter().enumerate() {
-        let bounds = l.bounds.iter()
-                             .map(|l| ast_region_to_region(ccx.tcx, l))
-                             .collect();
-        let def = ty::RegionParameterDef { name: l.lifetime.name,
-                                           space: space,
-                                           index: i as u32,
-                                           def_id: local_def(l.lifetime.id),
-                                           bounds: bounds };
-        debug!("ty_generics: def for region param: {:?}", def);
-        result.regions.push(space, def);
+    let tcx = ccx.tcx;
+    let mut result = base;
+
+    // For now, scrape the bounds out of parameters from Generics. This is not great.
+    for def in generics.regions.get_slice(space) {
+        let r_a = def.to_early_bound_region();
+        for &r_b in &def.bounds {
+            let outlives = ty::Binder(ty::OutlivesPredicate(r_a, r_b));
+            result.predicates.push(def.space, ty::Predicate::RegionOutlives(outlives));
+        }
     }
-
-    assert!(result.types.is_empty_in(space));
-
-    // Now create the real type parameters.
-    for (i, param) in types.iter().enumerate() {
-        let def = get_or_create_type_parameter_def(ccx,
-                                                   space,
-                                                   param,
-                                                   i as u32);
-        debug!("ty_generics: def for type param: {}, {:?}",
-               def.repr(ccx.tcx),
-               space);
-        result.types.push(space, def);
+    for def in generics.types.get_slice(space) {
+        let t = ty::mk_param_from_def(ccx.tcx, def);
+        result.predicates.extend(def.space, ty::predicates(ccx.tcx, t, &def.bounds).into_iter());
     }
 
-    // Just for fun, also push the bounds from the type parameters
-    // into the predicates list. This is currently kind of non-DRY.
-    create_predicates(ccx.tcx, &mut result, space);
-
     // Add the bounds not associated with a type parameter
     for predicate in &where_clause.predicates {
         match predicate {
@@ -1275,7 +1454,7 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                         }
 
                         &ast::TyParamBound::RegionTyParamBound(ref lifetime) => {
-                            let region = ast_region_to_region(ccx.tcx, lifetime);
+                            let region = ast_region_to_region(tcx, lifetime);
                             let pred = ty::Binder(ty::OutlivesPredicate(ty, region));
                             result.predicates.push(space, ty::Predicate::TypeOutlives(pred))
                         }
@@ -1284,9 +1463,9 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
             }
 
             &ast::WherePredicate::RegionPredicate(ref region_pred) => {
-                let r1 = ast_region_to_region(ccx.tcx, &region_pred.lifetime);
+                let r1 = ast_region_to_region(tcx, &region_pred.lifetime);
                 for bound in &region_pred.bounds {
-                    let r2 = ast_region_to_region(ccx.tcx, bound);
+                    let r2 = ast_region_to_region(tcx, bound);
                     let pred = ty::Binder(ty::OutlivesPredicate(r1, r2));
                     result.predicates.push(space, ty::Predicate::RegionOutlives(pred))
                 }
@@ -1294,39 +1473,50 @@ fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
 
             &ast::WherePredicate::EqPredicate(ref eq_pred) => {
                 // FIXME(#20041)
-                ccx.tcx.sess.span_bug(eq_pred.span,
-                                         "Equality constraints are not yet \
-                                            implemented (#20041)")
+                tcx.sess.span_bug(eq_pred.span,
+                                    "Equality constraints are not yet \
+                                        implemented (#20041)")
             }
         }
     }
 
     return result;
+}
 
-    fn create_predicates<'tcx>(
-        tcx: &ty::ctxt<'tcx>,
-        result: &mut ty::Generics<'tcx>,
-        space: subst::ParamSpace)
-    {
-        for type_param_def in result.types.get_slice(space) {
-            let param_ty = ty::mk_param_from_def(tcx, type_param_def);
-            for predicate in ty::predicates(tcx, param_ty, &type_param_def.bounds) {
-                result.predicates.push(space, predicate);
-            }
-        }
+fn ty_generics<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+                        space: subst::ParamSpace,
+                        lifetime_defs: &[ast::LifetimeDef],
+                        types: &[ast::TyParam],
+                        base_generics: ty::Generics<'tcx>)
+                        -> ty::Generics<'tcx>
+{
+    let tcx = ccx.tcx;
+    let mut result = base_generics;
 
-        for region_param_def in result.regions.get_slice(space) {
-            let region = region_param_def.to_early_bound_region();
-            for &bound_region in &region_param_def.bounds {
-                // account for new binder introduced in the predicate below; no need
-                // to shift `region` because it is never a late-bound region
-                let bound_region = ty_fold::shift_region(bound_region, 1);
-                result.predicates.push(
-                    space,
-                    ty::Binder(ty::OutlivesPredicate(region, bound_region)).as_predicate());
-            }
-        }
+    for (i, l) in lifetime_defs.iter().enumerate() {
+        let bounds = l.bounds.iter()
+                             .map(|l| ast_region_to_region(tcx, l))
+                             .collect();
+        let def = ty::RegionParameterDef { name: l.lifetime.name,
+                                           space: space,
+                                           index: i as u32,
+                                           def_id: local_def(l.lifetime.id),
+                                           bounds: bounds };
+        // debug!("ty_generics: def for region param: {:?}",
+        //        def.repr(tcx));
+        result.regions.push(space, def);
+    }
+
+    assert!(result.types.is_empty_in(space));
+
+    // Now create the real type parameters.
+    for (i, param) in types.iter().enumerate() {
+        let def = get_or_create_type_parameter_def(ccx, space, param, i as u32);
+        debug!("ty_generics: def for type param: {:?}, {:?}", def, space);
+        result.types.push(space, def);
     }
+
+    result
 }
 
 fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
@@ -1335,8 +1525,9 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                                              index: u32)
                                              -> ty::TypeParameterDef<'tcx>
 {
-    match ccx.tcx.ty_param_defs.borrow().get(&param.id) {
-        Some(d) => { return (*d).clone(); }
+    let tcx = ccx.tcx;
+    match tcx.ty_param_defs.borrow().get(&param.id) {
+        Some(d) => { return d.clone(); }
         None => { }
     }
 
@@ -1355,9 +1546,9 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
             ty::walk_ty(ty, |t| {
                 match t.sty {
                     ty::ty_param(p) => if p.idx > cur_idx {
-                        span_err!(ccx.tcx.sess, path.span, E0128,
+                        span_err!(tcx.sess, path.span, E0128,
                                   "type parameters with a default cannot use \
-                                   forward declared identifiers");
+                                  forward declared identifiers");
                         },
                         _ => {}
                     }
@@ -1376,7 +1567,7 @@ fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
         default: default
     };
 
-    ccx.tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
+    tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
 
     def
 }
@@ -1404,7 +1595,7 @@ fn compute_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                           ast_bounds,
                           span);
 
-        check_bounds_compatible(ccx.tcx,
+        check_bounds_compatible(ccx,
                                 param_ty,
                                 &param_bounds,
                                 span);
@@ -1415,24 +1606,22 @@ fn compute_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
     param_bounds
 }
 
-fn check_bounds_compatible<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                 param_ty: Ty<'tcx>,
-                                 param_bounds: &ty::ParamBounds<'tcx>,
-                                 span: Span) {
-    // Currently the only bound which is incompatible with other bounds is
-    // Sized/Unsized.
+fn check_bounds_compatible<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
+                                    param_ty: Ty<'tcx>,
+                                    param_bounds: &ty::ParamBounds<'tcx>,
+                                    span: Span) {
     if !param_bounds.builtin_bounds.contains(&ty::BoundSized) {
         ty::each_bound_trait_and_supertraits(
-            tcx,
+            ccx.tcx,
             &param_bounds.trait_bounds[],
             |trait_ref| {
-                let trait_def = ty::lookup_trait_def(tcx, trait_ref.def_id());
+                let trait_def = ccx.get_trait_def(trait_ref.def_id());
                 if trait_def.bounds.builtin_bounds.contains(&ty::BoundSized) {
-                    span_err!(tcx.sess, span, E0129,
+                    span_err!(ccx.tcx.sess, span, E0129,
                               "incompatible bounds on `{}`, \
                                bound `{}` does not allow unsized type",
-                              param_ty.user_string(tcx),
-                              trait_ref.user_string(tcx));
+                              param_ty.user_string(ccx.tcx),
+                              trait_ref.user_string(ccx.tcx));
                 }
                 true
             });
@@ -1445,10 +1634,12 @@ fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                               ast_bounds: &[ast::TyParamBound])
                               -> ty::ParamBounds<'tcx>
 {
-    let astconv::PartitionedBounds { builtin_bounds,
-                                     trait_bounds,
-                                     region_bounds } =
-        astconv::partition_bounds(ccx.tcx, span, ast_bounds);
+    let tcx = ccx.tcx;
+    let astconv::PartitionedBounds {
+        builtin_bounds,
+        trait_bounds,
+        region_bounds
+    } = astconv::partition_bounds(tcx, span, ast_bounds.as_slice());
 
     let mut projection_bounds = Vec::new();
 
@@ -1461,11 +1652,13 @@ fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
                                                 Some(param_ty),
                                                 &mut projection_bounds)
         })
-        .collect();
+    .collect();
+
     let region_bounds: Vec<ty::Region> =
         region_bounds.into_iter()
-        .map(|r| ast_region_to_region(ccx.tcx, r))
-        .collect();
+                     .map(|r| ast_region_to_region(ccx.tcx, r))
+                     .collect();
+
     ty::ParamBounds {
         region_bounds: region_bounds,
         builtin_bounds: builtin_bounds,
@@ -1474,13 +1667,14 @@ fn conv_param_bounds<'a,'tcx>(ccx: &CollectCtxt<'a,'tcx>,
     }
 }
 
-fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
-                                       decl: &ast::FnDecl,
-                                       def_id: ast::DefId,
-                                       ast_generics: &ast::Generics,
-                                       abi: abi::Abi)
-                                       -> ty::TypeScheme<'tcx> {
-    for i in &decl.inputs {
+fn compute_type_scheme_of_foreign_fn_decl<'a, 'tcx>(
+    ccx: &CollectCtxt<'a, 'tcx>,
+    decl: &ast::FnDecl,
+    ast_generics: &ast::Generics,
+    abi: abi::Abi)
+    -> ty::TypeScheme<'tcx>
+{
+    for i in decl.inputs.iter() {
         match (*i).pat.node {
             ast::PatIdent(_, _, _) => (),
             ast::PatWild(ast::PatWildSingle) => (),
@@ -1491,9 +1685,8 @@ fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
         }
     }
 
-    let ty_generics_for_fn_or_method = ty_generics_for_fn_or_method(ccx,
-                                                                    ast_generics,
-                                                                    ty::Generics::empty());
+    let ty_generics = ty_generics_for_fn_or_method(ccx, ast_generics, ty::Generics::empty());
+
     let rb = BindingRscope::new();
     let input_tys = decl.inputs
                         .iter()
@@ -1519,13 +1712,11 @@ fn ty_of_foreign_fn_decl<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
                                        output: output,
                                        variadic: decl.variadic}),
         }));
-    let scheme = TypeScheme {
-        generics: ty_generics_for_fn_or_method,
-        ty: t_fn
-    };
 
-    ccx.tcx.tcache.borrow_mut().insert(def_id, scheme.clone());
-    return scheme;
+    ty::TypeScheme {
+        generics: ty_generics,
+        ty: t_fn
+    }
 }
 
 fn mk_item_substs<'a, 'tcx>(ccx: &CollectCtxt<'a, 'tcx>,
@@ -1556,6 +1747,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
     explicit_self: &ast::ExplicitSelf,
     body_id: ast::NodeId)
 {
+    let tcx = ccx.tcx;
     if let ast::SelfExplicit(ref ast_type, _) = explicit_self.node {
         let typ = ccx.to_ty(rs, &**ast_type);
         let base_type = match typ.sty {
@@ -1564,7 +1756,7 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
             _ => typ,
         };
 
-        let body_scope = region::CodeExtent::from_node_id(body_id);
+        let body_scope = region::DestructionScopeData::new(body_id);
 
         // "Required type" comes from the trait definition. It may
         // contain late-bound regions from the method, but not the
@@ -1573,27 +1765,28 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
         assert!(!base_type.has_regions_escaping_depth(1));
         let required_type_free =
             liberate_early_bound_regions(
-                ccx.tcx, body_scope,
+                tcx, body_scope,
                 &ty::liberate_late_bound_regions(
-                    ccx.tcx, body_scope, &ty::Binder(required_type)));
+                    tcx, body_scope, &ty::Binder(required_type)));
 
         // The "base type" comes from the impl. It too may have late-bound
         // regions from the method.
         assert!(!base_type.has_regions_escaping_depth(1));
         let base_type_free =
             liberate_early_bound_regions(
-                ccx.tcx, body_scope,
+                tcx, body_scope,
                 &ty::liberate_late_bound_regions(
-                    ccx.tcx, body_scope, &ty::Binder(base_type)));
+                    tcx, body_scope, &ty::Binder(base_type)));
 
         debug!("required_type={} required_type_free={} \
                 base_type={} base_type_free={}",
-               required_type.repr(ccx.tcx),
-               required_type_free.repr(ccx.tcx),
-               base_type.repr(ccx.tcx),
-               base_type_free.repr(ccx.tcx));
-        let infcx = infer::new_infer_ctxt(ccx.tcx);
-        drop(::require_same_types(ccx.tcx,
+               required_type.repr(tcx),
+               required_type_free.repr(tcx),
+               base_type.repr(tcx),
+               base_type_free.repr(tcx));
+
+        let infcx = infer::new_infer_ctxt(tcx);
+        drop(::require_same_types(tcx,
                                   Some(&infcx),
                                   false,
                                   explicit_self.span,
@@ -1601,14 +1794,14 @@ fn check_method_self_type<'a, 'tcx, RS:RegionScope>(
                                   required_type_free,
                                   || {
                 format!("mismatched self type: expected `{}`",
-                        ppaux::ty_to_string(ccx.tcx, required_type))
+                        ppaux::ty_to_string(tcx, required_type))
         }));
         infcx.resolve_regions_and_report_errors(body_id);
     }
 
     fn liberate_early_bound_regions<'tcx,T>(
         tcx: &ty::ctxt<'tcx>,
-        scope: region::CodeExtent,
+        scope: region::DestructionScopeData,
         value: &T)
         -> T
         where T : TypeFoldable<'tcx> + Repr<'tcx>
@@ -1639,6 +1832,7 @@ fn enforce_impl_ty_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
                                                 impl_def_id: ast::DefId)
 {
     let impl_scheme = ty::lookup_item_type(tcx, impl_def_id);
+    let impl_predicates = ty::lookup_predicates(tcx, impl_def_id);
     let impl_trait_ref = ty::impl_trait_ref(tcx, impl_def_id);
 
     // The trait reference is an input, so find all type parameters
@@ -1656,18 +1850,18 @@ fn enforce_impl_ty_params_are_constrained<'tcx>(tcx: &ty::ctxt<'tcx>,
         let num_inputs = input_parameters.len();
 
         let projection_predicates =
-            impl_scheme.generics.predicates
-            .iter()
-            .filter_map(|predicate| {
-                match *predicate {
-                    // Ignore higher-ranked binders. For the purposes
-                    // of this check, they don't matter because they
-                    // only affect named regions, and we're just
-                    // concerned about type parameters here.
-                    ty::Predicate::Projection(ref data) => Some(data.0.clone()),
-                    _ => None,
-                }
-            });
+            impl_predicates.predicates
+                           .iter()
+                           .filter_map(|predicate| {
+                               match *predicate {
+                                   // Ignore higher-ranked binders. For the purposes
+                                   // of this check, they don't matter because they
+                                   // only affect named regions, and we're just
+                                   // concerned about type parameters here.
+                                   ty::Predicate::Projection(ref data) => Some(data.0.clone()),
+                                   _ => None,
+                               }
+                           });
 
         for projection in projection_predicates {
             // Special case: watch out for some kind of sneaky attempt
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index d490ea5408d..ccfadaba244 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -79,6 +79,7 @@ This API is completely unstable and subject to change.
 #![feature(collections)]
 #![feature(core)]
 #![feature(int_uint)]
+#![feature(std_misc)]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
@@ -101,7 +102,6 @@ pub use rustc::util;
 use middle::def;
 use middle::infer;
 use middle::subst;
-use middle::subst::VecPerParamSpace;
 use middle::ty::{self, Ty};
 use session::config;
 use util::common::time;
@@ -176,17 +176,6 @@ fn lookup_def_ccx(ccx: &CrateCtxt, sp: Span, id: ast::NodeId)
     lookup_def_tcx(ccx.tcx, sp, id)
 }
 
-fn no_params<'tcx>(t: Ty<'tcx>) -> ty::TypeScheme<'tcx> {
-    ty::TypeScheme {
-        generics: ty::Generics {
-            types: VecPerParamSpace::empty(),
-            regions: VecPerParamSpace::empty(),
-            predicates: VecPerParamSpace::empty(),
-        },
-        ty: t
-    }
-}
-
 fn require_same_types<'a, 'tcx, M>(tcx: &ty::ctxt<'tcx>,
                                    maybe_infcx: Option<&infer::InferCtxt<'a, 'tcx>>,
                                    t1_is_expected: bool,
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index dfa5b01270e..d1283d6f46b 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -166,10 +166,11 @@ pub fn build_external_trait(cx: &DocContext, tcx: &ty::ctxt,
         }
     });
     let trait_def = ty::lookup_trait_def(tcx, did);
+    let predicates = ty::lookup_predicates(tcx, did);
     let bounds = trait_def.bounds.clean(cx);
     clean::Trait {
         unsafety: def.unsafety,
-        generics: (&def.generics, subst::TypeSpace).clean(cx),
+        generics: (&def.generics, &predicates, subst::TypeSpace).clean(cx),
         items: items.collect(),
         bounds: bounds,
     }
@@ -181,9 +182,10 @@ fn build_external_function(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) ->
         ty::ty_bare_fn(_, ref f) => ((did, &f.sig).clean(cx), f.unsafety),
         _ => panic!("bad function"),
     };
+    let predicates = ty::lookup_predicates(tcx, did);
     clean::Function {
         decl: decl,
-        generics: (&t.generics, subst::FnSpace).clean(cx),
+        generics: (&t.generics, &predicates, subst::FnSpace).clean(cx),
         unsafety: style,
     }
 }
@@ -192,6 +194,7 @@ fn build_struct(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Stru
     use syntax::parse::token::special_idents::unnamed_field;
 
     let t = ty::lookup_item_type(tcx, did);
+    let predicates = ty::lookup_predicates(tcx, did);
     let fields = ty::lookup_struct_fields(tcx, did);
 
     clean::Struct {
@@ -201,7 +204,7 @@ fn build_struct(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Stru
             [ref f, ..] if f.name == unnamed_field.name => doctree::Tuple,
             _ => doctree::Plain,
         },
-        generics: (&t.generics, subst::TypeSpace).clean(cx),
+        generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
         fields: fields.clean(cx),
         fields_stripped: false,
     }
@@ -209,10 +212,11 @@ fn build_struct(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::Stru
 
 fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEnum {
     let t = ty::lookup_item_type(tcx, did);
+    let predicates = ty::lookup_predicates(tcx, did);
     match t.ty.sty {
         ty::ty_enum(edid, _) if !csearch::is_typedef(&tcx.sess.cstore, did) => {
             return clean::EnumItem(clean::Enum {
-                generics: (&t.generics, subst::TypeSpace).clean(cx),
+                generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
                 variants_stripped: false,
                 variants: ty::enum_variants(tcx, edid).clean(cx),
             })
@@ -222,7 +226,7 @@ fn build_type(cx: &DocContext, tcx: &ty::ctxt, did: ast::DefId) -> clean::ItemEn
 
     clean::TypedefItem(clean::Typedef {
         type_: t.ty.clean(cx),
-        generics: (&t.generics, subst::TypeSpace).clean(cx),
+        generics: (&t.generics, &predicates, subst::TypeSpace).clean(cx),
     })
 }
 
@@ -293,6 +297,7 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt,
 
     let attrs = load_attrs(cx, tcx, did);
     let ty = ty::lookup_item_type(tcx, did);
+    let predicates = ty::lookup_predicates(tcx, did);
     let trait_items = csearch::get_impl_items(&tcx.sess.cstore, did)
             .iter()
             .filter_map(|did| {
@@ -323,9 +328,10 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt,
             ty::TypeTraitItem(ref assoc_ty) => {
                 let did = assoc_ty.def_id;
                 let type_scheme = ty::lookup_item_type(tcx, did);
+                let predicates = ty::lookup_predicates(tcx, did);
                 // Not sure the choice of ParamSpace actually matters here, because an
                 // associated type won't have generics on the LHS
-                let typedef = (type_scheme, subst::ParamSpace::TypeSpace).clean(cx);
+                let typedef = (type_scheme, predicates, subst::ParamSpace::TypeSpace).clean(cx);
                 Some(clean::Item {
                     name: Some(assoc_ty.name.clean(cx)),
                     inner: clean::TypedefItem(typedef),
@@ -349,7 +355,7 @@ fn build_impl(cx: &DocContext, tcx: &ty::ctxt,
                 }
             }),
             for_: ty.ty.clean(cx),
-            generics: (&ty.generics, subst::TypeSpace).clean(cx),
+            generics: (&ty.generics, &predicates, subst::TypeSpace).clean(cx),
             items: trait_items,
             polarity: polarity.map(|p| { p.clean(cx) }),
         }),
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 7ab9d8c6672..6c3d2d8fa19 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -860,7 +860,9 @@ impl Clean<Generics> for ast::Generics {
     }
 }
 
-impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>, subst::ParamSpace) {
+impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
+                                    &'a ty::GenericPredicates<'tcx>,
+                                    subst::ParamSpace) {
     fn clean(&self, cx: &DocContext) -> Generics {
         use std::collections::HashSet;
         use syntax::ast::TraitBoundModifier as TBM;
@@ -885,7 +887,8 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>, subst::ParamSpace) {
             false
         }
 
-        let (gens, space) = *self;
+        let (gens, preds, space) = *self;
+
         // Bounds in the type_params and lifetimes fields are repeated in the predicates
         // field (see rustc_typeck::collect::ty_generics), so remove them.
         let stripped_typarams = gens.types.get_slice(space).iter().map(|tp| {
@@ -899,7 +902,8 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>, subst::ParamSpace) {
             srp.clean(cx)
         }).collect::<Vec<_>>();
 
-        let where_predicates = gens.predicates.get_slice(space).to_vec().clean(cx);
+        let where_predicates = preds.predicates.get_slice(space).to_vec().clean(cx);
+
         // Type parameters have a Sized bound by default unless removed with ?Sized.
         // Scan through the predicates and mark any type parameter with a Sized
         // bound, removing the bounds as we find them.
@@ -913,6 +917,7 @@ impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>, subst::ParamSpace) {
             }
             Some(pred)
         }).collect::<Vec<_>>();
+
         // Finally, run through the type parameters again and insert a ?Sized unbound for
         // any we didn't find to be Sized.
         for tp in &stripped_typarams {
@@ -1303,7 +1308,7 @@ impl<'tcx> Clean<Item> for ty::Method<'tcx> {
             source: Span::empty(),
             inner: TyMethodItem(TyMethod {
                 unsafety: self.fty.unsafety,
-                generics: (&self.generics, subst::FnSpace).clean(cx),
+                generics: (&self.generics, &self.predicates, subst::FnSpace).clean(cx),
                 self_: self_,
                 decl: (self.def_id, &sig).clean(cx),
                 abi: self.fty.abi
@@ -2560,12 +2565,12 @@ impl Clean<Item> for ast::Typedef {
     }
 }
 
-impl<'a> Clean<Typedef> for (ty::TypeScheme<'a>, ParamSpace) {
+impl<'a> Clean<Typedef> for (ty::TypeScheme<'a>, ty::GenericPredicates<'a>, ParamSpace) {
     fn clean(&self, cx: &DocContext) -> Typedef {
-        let (ref ty_scheme, ps) = *self;
+        let (ref ty_scheme, ref predicates, ps) = *self;
         Typedef {
             type_: ty_scheme.ty.clean(cx),
-            generics: (&ty_scheme.generics, ps).clean(cx)
+            generics: (&ty_scheme.generics, predicates, ps).clean(cx)
         }
     }
 }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 0253aaa31ca..9d45caf7669 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -122,10 +122,10 @@ struct Output {
 }
 
 pub fn main() {
-    static STACK_SIZE: uint = 32000000; // 32MB
+    const STACK_SIZE: usize = 32000000; // 32MB
     let res = std::thread::Builder::new().stack_size(STACK_SIZE).scoped(move || {
-        let s = env::args().map(|s| s.into_string().unwrap());
-        main_args(&s.collect::<Vec<_>>())
+        let s = env::args().collect::<Vec<_>>();
+        main_args(&s)
     }).join();
     env::set_exit_status(res.ok().unwrap() as i32);
 }
diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs
index 4e023039de7..abd73fcfb70 100644
--- a/src/librustdoc/passes.rs
+++ b/src/librustdoc/passes.rs
@@ -12,7 +12,7 @@ use std::collections::HashSet;
 use rustc::util::nodemap::NodeSet;
 use std::cmp;
 use std::string::String;
-use std::uint;
+use std::usize;
 use syntax::ast;
 use syntax::ast_util;
 
@@ -310,7 +310,7 @@ pub fn unindent(s: &str) -> String {
     let lines = s.lines_any().collect::<Vec<&str> >();
     let mut saw_first_line = false;
     let mut saw_second_line = false;
-    let min_indent = lines.iter().fold(uint::MAX, |min_indent, line| {
+    let min_indent = lines.iter().fold(usize::MAX, |min_indent, line| {
 
         // After we see the first non-whitespace line, look at
         // the line we have. If it is not whitespace, and therefore
@@ -322,7 +322,7 @@ pub fn unindent(s: &str) -> String {
             !line.chars().all(|c| c.is_whitespace());
 
         let min_indent = if ignore_previous_indents {
-            uint::MAX
+            usize::MAX
         } else {
             min_indent
         };
diff --git a/src/libserialize/collection_impls.rs b/src/libserialize/collection_impls.rs
index 53d3b069467..f81edca8371 100644
--- a/src/libserialize/collection_impls.rs
+++ b/src/libserialize/collection_impls.rs
@@ -10,7 +10,7 @@
 
 //! Implementations of serialization for structures found in libcollections
 
-use std::uint;
+use std::usize;
 use std::default::Default;
 use std::hash::{Hash, Hasher};
 use std::collections::hash_state::HashState;
@@ -148,7 +148,7 @@ impl<
     fn decode<D: Decoder>(d: &mut D) -> Result<EnumSet<T>, D::Error> {
         let bits = try!(d.read_uint());
         let mut set = EnumSet::new();
-        for bit in 0..uint::BITS {
+        for bit in 0..usize::BITS {
             if bits & (1 << bit) != 0 {
                 set.insert(CLike::from_usize(1 << bit));
             }
diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs
index e86ee4a73ce..4579d1f19d3 100644
--- a/src/libserialize/lib.rs
+++ b/src/libserialize/lib.rs
@@ -31,6 +31,7 @@ Core encoding and decoding interfaces.
 #![feature(int_uint)]
 #![feature(io)]
 #![feature(path)]
+#![feature(hash)]
 #![feature(rustc_private)]
 #![feature(slicing_syntax)]
 #![feature(staged_api)]
diff --git a/src/libstd/dynamic_lib.rs b/src/libstd/dynamic_lib.rs
index bee9a0d0033..c5dd66630b4 100644
--- a/src/libstd/dynamic_lib.rs
+++ b/src/libstd/dynamic_lib.rs
@@ -101,7 +101,7 @@ impl DynamicLibrary {
     /// Returns the current search path for dynamic libraries being used by this
     /// process
     pub fn search_path() -> Vec<Path> {
-        match env::var(DynamicLibrary::envvar()) {
+        match env::var_os(DynamicLibrary::envvar()) {
             Some(var) => env::split_paths(&var).collect(),
             None => Vec::new(),
         }
diff --git a/src/libstd/env.rs b/src/libstd/env.rs
index e73797bc66c..ea18838211f 100644
--- a/src/libstd/env.rs
+++ b/src/libstd/env.rs
@@ -71,17 +71,29 @@ static ENV_LOCK: StaticMutex = MUTEX_INIT;
 
 /// An iterator over a snapshot of the environment variables of this process.
 ///
-/// This iterator is created through `std::env::vars()` and yields `(OsString,
-/// OsString)` pairs.
-pub struct Vars { inner: os_imp::Env }
+/// This iterator is created through `std::env::vars()` and yields `(String,
+/// String)` pairs.
+pub struct Vars { inner: VarsOs }
 
-/// Returns an iterator of (variable, value) pairs, for all the environment
-/// variables of the current process.
+/// An iterator over a snapshot of the environment variables of this process.
+///
+/// This iterator is created through `std::env::vars_os()` and yields
+/// `(OsString, OsString)` pairs.
+pub struct VarsOs { inner: os_imp::Env }
+
+/// Returns an iterator of (variable, value) pairs of strings, for all the
+/// environment variables of the current process.
 ///
 /// The returned iterator contains a snapshot of the process's environment
 /// variables at the time of this invocation, modifications to environment
 /// variables afterwards will not be reflected in the returned iterator.
 ///
+/// # Panics
+///
+/// While iterating, the returned iterator will panic if any key or value in the
+/// environment is not valid unicode. If this is not desired, consider using the
+/// `env::vars_os` function.
+///
 /// # Example
 ///
 /// ```rust
@@ -90,37 +102,50 @@ pub struct Vars { inner: os_imp::Env }
 /// // We will iterate through the references to the element returned by
 /// // env::vars();
 /// for (key, value) in env::vars() {
-///     println!("{:?}: {:?}", key, value);
+///     println!("{}: {}", key, value);
 /// }
 /// ```
 pub fn vars() -> Vars {
-    let _g = ENV_LOCK.lock();
-    Vars { inner: os_imp::env() }
-}
-
-impl Iterator for Vars {
-    type Item = (OsString, OsString);
-    fn next(&mut self) -> Option<(OsString, OsString)> { self.inner.next() }
-    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+    Vars { inner: vars_os() }
 }
 
-/// Fetches the environment variable `key` from the current process, returning
-/// None if the variable isn't set.
+/// Returns an iterator of (variable, value) pairs of OS strings, for all the
+/// environment variables of the current process.
+///
+/// The returned iterator contains a snapshot of the process's environment
+/// variables at the time of this invocation, modifications to environment
+/// variables afterwards will not be reflected in the returned iterator.
 ///
 /// # Example
 ///
 /// ```rust
 /// use std::env;
 ///
-/// let key = "HOME";
-/// match env::var(key) {
-///     Some(val) => println!("{}: {:?}", key, val),
-///     None => println!("{} is not defined in the environment.", key)
+/// // We will iterate through the references to the element returned by
+/// // env::vars_os();
+/// for (key, value) in env::vars_os() {
+///     println!("{:?}: {:?}", key, value);
 /// }
 /// ```
-pub fn var<K: ?Sized>(key: &K) -> Option<OsString> where K: AsOsStr {
+pub fn vars_os() -> VarsOs {
     let _g = ENV_LOCK.lock();
-    os_imp::getenv(key.as_os_str())
+    VarsOs { inner: os_imp::env() }
+}
+
+impl Iterator for Vars {
+    type Item = (String, String);
+    fn next(&mut self) -> Option<(String, String)> {
+        self.inner.next().map(|(a, b)| {
+            (a.into_string().unwrap(), b.into_string().unwrap())
+        })
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+impl Iterator for VarsOs {
+    type Item = (OsString, OsString);
+    fn next(&mut self) -> Option<(OsString, OsString)> { self.inner.next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
 }
 
 /// Fetches the environment variable `key` from the current process.
@@ -135,18 +160,37 @@ pub fn var<K: ?Sized>(key: &K) -> Option<OsString> where K: AsOsStr {
 /// use std::env;
 ///
 /// let key = "HOME";
-/// match env::var_string(key) {
+/// match env::var(key) {
 ///     Ok(val) => println!("{}: {:?}", key, val),
 ///     Err(e) => println!("couldn't interpret {}: {}", key, e),
 /// }
 /// ```
-pub fn var_string<K: ?Sized>(key: &K) -> Result<String, VarError> where K: AsOsStr {
-    match var(key) {
+pub fn var<K: ?Sized>(key: &K) -> Result<String, VarError> where K: AsOsStr {
+    match var_os(key) {
         Some(s) => s.into_string().map_err(VarError::NotUnicode),
         None => Err(VarError::NotPresent)
     }
 }
 
+/// Fetches the environment variable `key` from the current process, returning
+/// None if the variable isn't set.
+///
+/// # Example
+///
+/// ```rust
+/// use std::env;
+///
+/// let key = "HOME";
+/// match env::var_os(key) {
+///     Some(val) => println!("{}: {:?}", key, val),
+///     None => println!("{} is not defined in the environment.", key)
+/// }
+/// ```
+pub fn var_os<K: ?Sized>(key: &K) -> Option<OsString> where K: AsOsStr {
+    let _g = ENV_LOCK.lock();
+    os_imp::getenv(key.as_os_str())
+}
+
 /// Possible errors from the `env::var` method.
 #[derive(Debug, PartialEq, Eq, Clone)]
 pub enum VarError {
@@ -190,7 +234,7 @@ impl Error for VarError {
 ///
 /// let key = "KEY";
 /// env::set_var(key, "VALUE");
-/// assert_eq!(env::var_string(key), Ok("VALUE".to_string()));
+/// assert_eq!(env::var(key), Ok("VALUE".to_string()));
 /// ```
 pub fn set_var<K: ?Sized, V: ?Sized>(k: &K, v: &V)
     where K: AsOsStr, V: AsOsStr
@@ -222,7 +266,7 @@ pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a> }
 /// use std::env;
 ///
 /// let key = "PATH";
-/// match env::var(key) {
+/// match env::var_os(key) {
 ///     Some(paths) => {
 ///         for path in env::split_paths(&paths) {
 ///             println!("'{}'", path.display());
@@ -262,7 +306,7 @@ pub struct JoinPathsError {
 /// ```rust
 /// use std::env;
 ///
-/// if let Some(path) = env::var("PATH") {
+/// if let Some(path) = env::var_os("PATH") {
 ///     let mut paths = env::split_paths(&path).collect::<Vec<_>>();
 ///     paths.push(Path::new("/home/xyz/bin"));
 ///     let new_path = env::join_paths(paths.iter()).unwrap();
@@ -376,11 +420,17 @@ pub fn get_exit_status() -> i32 {
     EXIT_STATUS.load(Ordering::SeqCst) as i32
 }
 
-/// An iterator over the arguments of a process, yielding an `OsString` value
+/// An iterator over the arguments of a process, yielding an `String` value
 /// for each argument.
 ///
 /// This structure is created through the `std::env::args` method.
-pub struct Args { inner: os_imp::Args }
+pub struct Args { inner: ArgsOs }
+
+/// An iterator over the arguments of a process, yielding an `OsString` value
+/// for each argument.
+///
+/// This structure is created through the `std::env::args_os` method.
+pub struct ArgsOs { inner: os_imp::Args }
 
 /// Returns the arguments which this program was started with (normally passed
 /// via the command line).
@@ -389,6 +439,12 @@ pub struct Args { inner: os_imp::Args }
 /// set to arbitrary text, and it may not even exist, so this property should
 /// not be relied upon for security purposes.
 ///
+/// # Panics
+///
+/// The returned iterator will panic during iteration if any argument to the
+/// process is not valid unicode. If this is not desired it is recommended to
+/// use the `args_os` function instead.
+///
 /// # Example
 ///
 /// ```rust
@@ -396,14 +452,43 @@ pub struct Args { inner: os_imp::Args }
 ///
 /// // Prints each argument on a separate line
 /// for argument in env::args() {
-///     println!("{:?}", argument);
+///     println!("{}", argument);
 /// }
 /// ```
 pub fn args() -> Args {
-    Args { inner: os_imp::args() }
+    Args { inner: args_os() }
+}
+
+/// Returns the arguments which this program was started with (normally passed
+/// via the command line).
+///
+/// The first element is traditionally the path to the executable, but it can be
+/// set to arbitrary text, and it may not even exist, so this property should
+/// not be relied upon for security purposes.
+///
+/// # Example
+///
+/// ```rust
+/// use std::env;
+///
+/// // Prints each argument on a separate line
+/// for argument in env::args_os() {
+///     println!("{:?}", argument);
+/// }
+/// ```
+pub fn args_os() -> ArgsOs {
+    ArgsOs { inner: os_imp::args() }
 }
 
 impl Iterator for Args {
+    type Item = String;
+    fn next(&mut self) -> Option<String> {
+        self.inner.next().map(|s| s.into_string().unwrap())
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
+}
+
+impl Iterator for ArgsOs {
     type Item = OsString;
     fn next(&mut self) -> Option<OsString> { self.inner.next() }
     fn size_hint(&self) -> (usize, Option<usize>) { self.inner.size_hint() }
@@ -706,7 +791,7 @@ mod tests {
         let n = format!("TEST{}", rng.gen_ascii_chars().take(10)
                                      .collect::<String>());
         let n = OsString::from_string(n);
-        assert!(var(&n).is_none());
+        assert!(var_os(&n).is_none());
         n
     }
 
@@ -718,7 +803,7 @@ mod tests {
     fn test_set_var() {
         let n = make_rand_name();
         set_var(&n, "VALUE");
-        eq(var(&n), Some("VALUE"));
+        eq(var_os(&n), Some("VALUE"));
     }
 
     #[test]
@@ -726,7 +811,7 @@ mod tests {
         let n = make_rand_name();
         set_var(&n, "VALUE");
         remove_var(&n);
-        eq(var(&n), None);
+        eq(var_os(&n), None);
     }
 
     #[test]
@@ -734,9 +819,9 @@ mod tests {
         let n = make_rand_name();
         set_var(&n, "1");
         set_var(&n, "2");
-        eq(var(&n), Some("2"));
+        eq(var_os(&n), Some("2"));
         set_var(&n, "");
-        eq(var(&n), Some(""));
+        eq(var_os(&n), Some(""));
     }
 
     #[test]
@@ -749,7 +834,7 @@ mod tests {
         }
         let n = make_rand_name();
         set_var(&n, s.as_slice());
-        eq(var(&n), Some(s.as_slice()));
+        eq(var_os(&n), Some(s.as_slice()));
     }
 
     #[test]
@@ -767,22 +852,22 @@ mod tests {
         let n = make_rand_name();
         let s = repeat("x").take(10000).collect::<String>();
         set_var(&n, &s);
-        eq(var(&n), Some(s.as_slice()));
+        eq(var_os(&n), Some(s.as_slice()));
         remove_var(&n);
-        eq(var(&n), None);
+        eq(var_os(&n), None);
     }
 
     #[test]
     fn test_env_set_var() {
         let n = make_rand_name();
 
-        let mut e = vars();
+        let mut e = vars_os();
         set_var(&n, "VALUE");
         assert!(!e.any(|(k, v)| {
             &*k == &*n && &*v == "VALUE"
         }));
 
-        assert!(vars().any(|(k, v)| {
+        assert!(vars_os().any(|(k, v)| {
             &*k == &*n && &*v == "VALUE"
         }));
     }
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 967789dd411..83f0b7bc0e9 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -111,7 +111,7 @@
 #![feature(core)]
 #![feature(hash)]
 #![feature(int_uint)]
-#![feature(lang_items, unsafe_destructor)]
+#![feature(lang_items)]
 #![feature(libc)]
 #![feature(linkage, thread_local, asm)]
 #![feature(old_impl_check)]
@@ -120,6 +120,8 @@
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
 #![feature(unicode)]
+#![feature(unsafe_destructor)]
+#![feature(unsafe_no_drop_flag)]
 #![feature(macro_reexport)]
 #![cfg_attr(test, feature(test))]
 
@@ -164,6 +166,7 @@ pub use core::cell;
 pub use core::clone;
 #[cfg(not(test))] pub use core::cmp;
 pub use core::default;
+#[allow(deprecated)]
 pub use core::finally;
 pub use core::hash;
 pub use core::intrinsics;
@@ -250,6 +253,7 @@ pub mod ffi;
 pub mod old_io;
 pub mod io;
 pub mod fs;
+pub mod net;
 pub mod os;
 pub mod env;
 pub mod path;
@@ -306,8 +310,8 @@ mod std {
     pub use marker;  // used for tls!
     pub use ops; // used for bitflags!
 
-    // The test runner calls ::std::os::args() but really wants realstd
-    #[cfg(test)] pub use realstd::os as os;
+    // The test runner calls ::std::env::args() but really wants realstd
+    #[cfg(test)] pub use realstd::env as env;
     // The test runner requires std::slice::Vector, so re-export std::slice just for it.
     //
     // It is also used in vec![]
diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs
new file mode 100644
index 00000000000..66d4d34f8eb
--- /dev/null
+++ b/src/libstd/net/addr.rs
@@ -0,0 +1,592 @@
+// Copyright 2015 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 prelude::v1::*;
+
+use fmt;
+use hash;
+use io;
+use libc::{self, socklen_t, sa_family_t};
+use mem;
+use net::{IpAddr, lookup_host, ntoh, hton};
+use option;
+use sys_common::{FromInner, AsInner, IntoInner};
+use vec;
+
+/// Representation of a socket address for networking applications
+///
+/// A socket address consists of at least an (ip, port) pair and may also
+/// contain other information depending on the protocol.
+#[derive(Copy, Clone, PartialEq, Eq, Hash)]
+pub struct SocketAddr {
+    repr: Repr,
+}
+
+#[derive(Copy)]
+enum Repr {
+    V4(libc::sockaddr_in),
+    V6(libc::sockaddr_in6),
+}
+
+impl SocketAddr {
+    /// Creates a new socket address from the (ip, port) pair.
+    pub fn new(ip: IpAddr, port: u16) -> SocketAddr {
+        let repr = match ip {
+            IpAddr::V4(ref ip) => {
+                Repr::V4(libc::sockaddr_in {
+                    sin_family: libc::AF_INET as sa_family_t,
+                    sin_port: hton(port),
+                    sin_addr: *ip.as_inner(),
+                    .. unsafe { mem::zeroed() }
+                })
+            }
+            IpAddr::V6(ref ip) => {
+                Repr::V6(libc::sockaddr_in6 {
+                    sin6_family: libc::AF_INET6 as sa_family_t,
+                    sin6_port: hton(port),
+                    sin6_addr: *ip.as_inner(),
+                    .. unsafe { mem::zeroed() }
+                })
+            }
+        };
+        SocketAddr { repr: repr }
+    }
+
+    /// Gets the IP address associated with this socket address.
+    pub fn ip(&self) -> IpAddr {
+        match self.repr {
+            Repr::V4(ref sa) => IpAddr::V4(FromInner::from_inner(sa.sin_addr)),
+            Repr::V6(ref sa) => IpAddr::V6(FromInner::from_inner(sa.sin6_addr)),
+        }
+    }
+
+    /// Gets the port number associated with this socket address
+    pub fn port(&self) -> u16 {
+        match self.repr {
+            Repr::V4(ref sa) => ntoh(sa.sin_port),
+            Repr::V6(ref sa) => ntoh(sa.sin6_port),
+        }
+    }
+
+    fn set_port(&mut self, port: u16) {
+        match self.repr {
+            Repr::V4(ref mut sa) => sa.sin_port = hton(port),
+            Repr::V6(ref mut sa) => sa.sin6_port = hton(port),
+        }
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for SocketAddr {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self.repr {
+            Repr::V4(_) => write!(f, "{}:{}", self.ip(), self.port()),
+            Repr::V6(_) => write!(f, "[{}]:{}", self.ip(), self.port()),
+        }
+    }
+}
+
+impl FromInner<libc::sockaddr_in> for SocketAddr {
+    fn from_inner(addr: libc::sockaddr_in) -> SocketAddr {
+        SocketAddr { repr: Repr::V4(addr) }
+    }
+}
+
+impl FromInner<libc::sockaddr_in6> for SocketAddr {
+    fn from_inner(addr: libc::sockaddr_in6) -> SocketAddr {
+        SocketAddr { repr: Repr::V6(addr) }
+    }
+}
+
+impl<'a> IntoInner<(*const libc::sockaddr, socklen_t)> for &'a SocketAddr {
+    fn into_inner(self) -> (*const libc::sockaddr, socklen_t) {
+        match self.repr {
+            Repr::V4(ref a) => {
+                (a as *const _ as *const _, mem::size_of_val(a) as socklen_t)
+            }
+            Repr::V6(ref a) => {
+                (a as *const _ as *const _, mem::size_of_val(a) as socklen_t)
+            }
+        }
+    }
+}
+
+impl fmt::Debug for SocketAddr {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+impl Clone for Repr {
+    fn clone(&self) -> Repr { *self }
+}
+
+impl PartialEq for Repr {
+    fn eq(&self, other: &Repr) -> bool {
+        match (*self, *other) {
+            (Repr::V4(ref a), Repr::V4(ref b)) => {
+                a.sin_port == b.sin_port &&
+                    a.sin_addr.s_addr == b.sin_addr.s_addr
+            }
+            (Repr::V6(ref a), Repr::V6(ref b)) => {
+                a.sin6_port == b.sin6_port &&
+                    a.sin6_addr.s6_addr == b.sin6_addr.s6_addr &&
+                    a.sin6_flowinfo == b.sin6_flowinfo &&
+                    a.sin6_scope_id == b.sin6_scope_id
+            }
+            _ => false,
+        }
+    }
+}
+impl Eq for Repr {}
+
+impl<S: hash::Hasher + hash::Writer> hash::Hash<S> for Repr {
+    fn hash(&self, s: &mut S) {
+        match *self {
+            Repr::V4(ref a) => {
+                (a.sin_family, a.sin_port, a.sin_addr.s_addr).hash(s)
+            }
+            Repr::V6(ref a) => {
+                (a.sin6_family, a.sin6_port, &a.sin6_addr.s6_addr,
+                 a.sin6_flowinfo, a.sin6_scope_id).hash(s)
+            }
+        }
+    }
+}
+
+/// A trait for objects which can be converted or resolved to one or more
+/// `SocketAddr` values.
+///
+/// This trait is used for generic address resolution when constructing network
+/// objects.  By default it is implemented for the following types:
+///
+///  * `SocketAddr` - `to_socket_addrs` is identity function.
+///
+///  * `(IpAddr, u16)` - `to_socket_addrs` constructs `SocketAddr` trivially.
+///
+///  * `(&str, u16)` - the string should be either a string representation of an
+///    IP address expected by `FromStr` implementation for `IpAddr` or a host
+///    name.
+///
+///  * `&str` - the string should be either a string representation of a
+///    `SocketAddr` as expected by its `FromStr` implementation or a string like
+///    `<host_name>:<port>` pair where `<port>` is a `u16` value.
+///
+/// This trait allows constructing network objects like `TcpStream` or
+/// `UdpSocket` easily with values of various types for the bind/connection
+/// address. It is needed because sometimes one type is more appropriate than
+/// the other: for simple uses a string like `"localhost:12345"` is much nicer
+/// than manual construction of the corresponding `SocketAddr`, but sometimes
+/// `SocketAddr` value is *the* main source of the address, and converting it to
+/// some other type (e.g. a string) just for it to be converted back to
+/// `SocketAddr` in constructor methods is pointless.
+///
+/// Some examples:
+///
+/// ```no_run
+/// use std::net::{IpAddr, SocketAddr, TcpStream, UdpSocket, TcpListener};
+///
+/// fn main() {
+///     let ip = IpAddr::new_v4(127, 0, 0, 1);
+///     let port = 12345;
+///
+///     // The following lines are equivalent modulo possible "localhost" name
+///     // resolution differences
+///     let tcp_s = TcpStream::connect(&SocketAddr::new(ip, port));
+///     let tcp_s = TcpStream::connect(&(ip, port));
+///     let tcp_s = TcpStream::connect(&("127.0.0.1", port));
+///     let tcp_s = TcpStream::connect(&("localhost", port));
+///     let tcp_s = TcpStream::connect("127.0.0.1:12345");
+///     let tcp_s = TcpStream::connect("localhost:12345");
+///
+///     // TcpListener::bind(), UdpSocket::bind() and UdpSocket::send_to()
+///     // behave similarly
+///     let tcp_l = TcpListener::bind("localhost:12345");
+///
+///     let mut udp_s = UdpSocket::bind(&("127.0.0.1", port)).unwrap();
+///     udp_s.send_to(&[7], &(ip, 23451));
+/// }
+/// ```
+pub trait ToSocketAddrs {
+    /// Returned iterator over socket addresses which this type may correspond
+    /// to.
+    type Iter: Iterator<Item=SocketAddr>;
+
+    /// Converts this object to an iterator of resolved `SocketAddr`s.
+    ///
+    /// The returned iterator may not actually yield any values depending on the
+    /// outcome of any resolution performed.
+    ///
+    /// Note that this function may block the current thread while resolution is
+    /// performed.
+    ///
+    /// # Errors
+    ///
+    /// Any errors encountered during resolution will be returned as an `Err`.
+    fn to_socket_addrs(&self) -> io::Result<Self::Iter>;
+}
+
+impl ToSocketAddrs for SocketAddr {
+    type Iter = option::IntoIter<SocketAddr>;
+    fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+        Ok(Some(*self).into_iter())
+    }
+}
+
+impl ToSocketAddrs for (IpAddr, u16) {
+    type Iter = option::IntoIter<SocketAddr>;
+    fn to_socket_addrs(&self) -> io::Result<option::IntoIter<SocketAddr>> {
+        let (ip, port) = *self;
+        Ok(Some(SocketAddr::new(ip, port)).into_iter())
+    }
+}
+
+fn resolve_socket_addr(s: &str, p: u16) -> io::Result<vec::IntoIter<SocketAddr>> {
+    let ips = try!(lookup_host(s));
+    let v: Vec<_> = try!(ips.map(|a| {
+        a.map(|mut a| { a.set_port(p); a })
+    }).collect());
+    Ok(v.into_iter())
+}
+
+impl<'a> ToSocketAddrs for (&'a str, u16) {
+    type Iter = vec::IntoIter<SocketAddr>;
+    fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
+        let (host, port) = *self;
+
+        // try to parse the host as a regular IpAddr first
+        match host.parse().ok() {
+            Some(addr) => return Ok(vec![SocketAddr::new(addr, port)].into_iter()),
+            None => {}
+        }
+
+        resolve_socket_addr(host, port)
+    }
+}
+
+// accepts strings like 'localhost:12345'
+impl ToSocketAddrs for str {
+    type Iter = vec::IntoIter<SocketAddr>;
+    fn to_socket_addrs(&self) -> io::Result<vec::IntoIter<SocketAddr>> {
+        // try to parse as a regular SocketAddr first
+        match self.parse().ok() {
+            Some(addr) => return Ok(vec![addr].into_iter()),
+            None => {}
+        }
+
+        macro_rules! try_opt {
+            ($e:expr, $msg:expr) => (
+                match $e {
+                    Some(r) => r,
+                    None => return Err(io::Error::new(io::ErrorKind::InvalidInput,
+                                                      $msg, None)),
+                }
+            )
+        }
+
+        // split the string by ':' and convert the second part to u16
+        let mut parts_iter = self.rsplitn(2, ':');
+        let port_str = try_opt!(parts_iter.next(), "invalid socket address");
+        let host = try_opt!(parts_iter.next(), "invalid socket address");
+        let port: u16 = try_opt!(port_str.parse().ok(), "invalid port value");
+        resolve_socket_addr(host, port)
+    }
+}
+
+impl<'a, T: ToSocketAddrs + ?Sized> ToSocketAddrs for &'a T {
+    type Iter = T::Iter;
+    fn to_socket_addrs(&self) -> io::Result<T::Iter> {
+        (**self).to_socket_addrs()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::v1::*;
+    use io;
+    use net::*;
+    use net::Ipv6MulticastScope::*;
+
+    #[test]
+    fn test_from_str_ipv4() {
+        assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse());
+        assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse());
+        assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse());
+
+        // out of range
+        let none: Option<IpAddr> = "256.0.0.1".parse().ok();
+        assert_eq!(None, none);
+        // too short
+        let none: Option<IpAddr> = "255.0.0".parse().ok();
+        assert_eq!(None, none);
+        // too long
+        let none: Option<IpAddr> = "255.0.0.1.2".parse().ok();
+        assert_eq!(None, none);
+        // no number between dots
+        let none: Option<IpAddr> = "255.0..1".parse().ok();
+        assert_eq!(None, none);
+    }
+
+    #[test]
+    fn test_from_str_ipv6() {
+        assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse());
+        assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse());
+
+        assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse());
+        assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse());
+
+        assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)),
+                "2a02:6b8::11:11".parse());
+
+        // too long group
+        let none: Option<IpAddr> = "::00000".parse().ok();
+        assert_eq!(None, none);
+        // too short
+        let none: Option<IpAddr> = "1:2:3:4:5:6:7".parse().ok();
+        assert_eq!(None, none);
+        // too long
+        let none: Option<IpAddr> = "1:2:3:4:5:6:7:8:9".parse().ok();
+        assert_eq!(None, none);
+        // triple colon
+        let none: Option<IpAddr> = "1:2:::6:7:8".parse().ok();
+        assert_eq!(None, none);
+        // two double colons
+        let none: Option<IpAddr> = "1:2::6::8".parse().ok();
+        assert_eq!(None, none);
+    }
+
+    #[test]
+    fn test_from_str_ipv4_in_ipv6() {
+        assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)),
+                "::192.0.2.33".parse());
+        assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)),
+                "::FFFF:192.0.2.33".parse());
+        assert_eq!(Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)),
+                "64:ff9b::192.0.2.33".parse());
+        assert_eq!(Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)),
+                "2001:db8:122:c000:2:2100:192.0.2.33".parse());
+
+        // colon after v4
+        let none: Option<IpAddr> = "::127.0.0.1:".parse().ok();
+        assert_eq!(None, none);
+        // not enough groups
+        let none: Option<IpAddr> = "1.2.3.4.5:127.0.0.1".parse().ok();
+        assert_eq!(None, none);
+        // too many groups
+        let none: Option<IpAddr> = "1.2.3.4.5:6:7:127.0.0.1".parse().ok();
+        assert_eq!(None, none);
+    }
+
+    #[test]
+    fn test_from_str_socket_addr() {
+        assert_eq!(Ok(SocketAddr::new(IpAddr::new_v4(77, 88, 21, 11), 80)),
+                "77.88.21.11:80".parse());
+        assert_eq!(Ok(SocketAddr::new(IpAddr::new_v6(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)),
+                "[2a02:6b8:0:1::1]:53".parse());
+        assert_eq!(Ok(SocketAddr::new(IpAddr::new_v6(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)),
+                "[::127.0.0.1]:22".parse());
+
+        // without port
+        let none: Option<SocketAddr> = "127.0.0.1".parse().ok();
+        assert_eq!(None, none);
+        // without port
+        let none: Option<SocketAddr> = "127.0.0.1:".parse().ok();
+        assert_eq!(None, none);
+        // wrong brackets around v4
+        let none: Option<SocketAddr> = "[127.0.0.1]:22".parse().ok();
+        assert_eq!(None, none);
+        // port out of range
+        let none: Option<SocketAddr> = "127.0.0.1:123456".parse().ok();
+        assert_eq!(None, none);
+    }
+
+    #[test]
+    fn ipv6_addr_to_string() {
+        // ipv4-mapped address
+        let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280);
+        assert_eq!(a1.to_string(), "::ffff:192.0.2.128");
+
+        // ipv4-compatible address
+        let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280);
+        assert_eq!(a1.to_string(), "::192.0.2.128");
+
+        // v6 address with no zero segments
+        assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(),
+                   "8:9:a:b:c:d:e:f");
+
+        // reduce a single run of zeros
+        assert_eq!("ae::ffff:102:304",
+                   Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string());
+
+        // don't reduce just a single zero segment
+        assert_eq!("1:2:3:4:5:6:0:8",
+                   Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string());
+
+        // 'any' address
+        assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string());
+
+        // loopback address
+        assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string());
+
+        // ends in zeros
+        assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string());
+
+        // two runs of zeros, second one is longer
+        assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string());
+
+        // two runs of zeros, equal length
+        assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string());
+    }
+
+    #[test]
+    fn ipv4_to_ipv6() {
+        assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678),
+                   Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped());
+        assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678),
+                   Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible());
+    }
+
+    #[test]
+    fn ipv6_to_ipv4() {
+        assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(),
+                   Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)));
+        assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
+                   Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)));
+        assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(),
+                   None);
+    }
+
+    #[test]
+    fn ipv4_properties() {
+        fn check(octets: &[u8; 4], unspec: bool, loopback: bool,
+                 private: bool, link_local: bool, global: bool,
+                 multicast: bool) {
+            let ip = Ipv4Addr::new(octets[0], octets[1], octets[2], octets[3]);
+            assert_eq!(octets, &ip.octets());
+
+            assert_eq!(ip.is_unspecified(), unspec);
+            assert_eq!(ip.is_loopback(), loopback);
+            assert_eq!(ip.is_private(), private);
+            assert_eq!(ip.is_link_local(), link_local);
+            assert_eq!(ip.is_global(), global);
+            assert_eq!(ip.is_multicast(), multicast);
+        }
+
+        //    address                unspec loopbk privt  linloc global multicast
+        check(&[0, 0, 0, 0],         true,  false, false, false, true,  false);
+        check(&[0, 0, 0, 1],         false, false, false, false, true,  false);
+        check(&[1, 0, 0, 0],         false, false, false, false, true,  false);
+        check(&[10, 9, 8, 7],        false, false, true,  false, false, false);
+        check(&[127, 1, 2, 3],       false, true,  false, false, false, false);
+        check(&[172, 31, 254, 253],  false, false, true,  false, false,  false);
+        check(&[169, 254, 253, 242], false, false, false, true,  false, false);
+        check(&[192, 168, 254, 253], false, false, true,  false, false, false);
+        check(&[224, 0, 0, 0],       false, false, false, false, true,  true);
+        check(&[239, 255, 255, 255], false, false, false, false, true,  true);
+        check(&[255, 255, 255, 255], false, false, false, false, true,  false);
+    }
+
+    #[test]
+    fn ipv6_properties() {
+        fn check(str_addr: &str, unspec: bool, loopback: bool,
+                 unique_local: bool, global: bool,
+                 u_link_local: bool, u_site_local: bool, u_global: bool,
+                 m_scope: Option<Ipv6MulticastScope>) {
+            let ip: Ipv6Addr = str_addr.parse().ok().unwrap();
+            assert_eq!(str_addr, ip.to_string());
+
+            assert_eq!(ip.is_unspecified(), unspec);
+            assert_eq!(ip.is_loopback(), loopback);
+            assert_eq!(ip.is_unique_local(), unique_local);
+            assert_eq!(ip.is_global(), global);
+            assert_eq!(ip.is_unicast_link_local(), u_link_local);
+            assert_eq!(ip.is_unicast_site_local(), u_site_local);
+            assert_eq!(ip.is_unicast_global(), u_global);
+            assert_eq!(ip.multicast_scope(), m_scope);
+            assert_eq!(ip.is_multicast(), m_scope.is_some());
+        }
+
+        //    unspec loopbk uniqlo global unill  unisl  uniglo mscope
+        check("::",
+              true,  false, false, true,  false, false, true,  None);
+        check("::1",
+              false, true,  false, false, false, false, false, None);
+        check("::0.0.0.2",
+              false, false, false, true,  false, false, true,  None);
+        check("1::",
+              false, false, false, true,  false, false, true,  None);
+        check("fc00::",
+              false, false, true,  false, false, false, false, None);
+        check("fdff:ffff::",
+              false, false, true,  false, false, false, false, None);
+        check("fe80:ffff::",
+              false, false, false, false, true,  false, false, None);
+        check("febf:ffff::",
+              false, false, false, false, true,  false, false, None);
+        check("fec0::",
+              false, false, false, false, false, true,  false, None);
+        check("ff01::",
+              false, false, false, false, false, false, false, Some(InterfaceLocal));
+        check("ff02::",
+              false, false, false, false, false, false, false, Some(LinkLocal));
+        check("ff03::",
+              false, false, false, false, false, false, false, Some(RealmLocal));
+        check("ff04::",
+              false, false, false, false, false, false, false, Some(AdminLocal));
+        check("ff05::",
+              false, false, false, false, false, false, false, Some(SiteLocal));
+        check("ff08::",
+              false, false, false, false, false, false, false, Some(OrganizationLocal));
+        check("ff0e::",
+              false, false, false, true,  false, false, false, Some(Global));
+    }
+
+    fn tsa<A: ToSocketAddrs>(a: A) -> io::Result<Vec<SocketAddr>> {
+        Ok(try!(a.to_socket_addrs()).collect())
+    }
+
+    #[test]
+    fn to_socket_addr_socketaddr() {
+        let a = SocketAddr::new(IpAddr::new_v4(77, 88, 21, 11), 12345);
+        assert_eq!(Ok(vec![a]), tsa(a));
+    }
+
+    #[test]
+    fn to_socket_addr_ipaddr_u16() {
+        let a = IpAddr::new_v4(77, 88, 21, 11);
+        let p = 12345u16;
+        let e = SocketAddr::new(a, p);
+        assert_eq!(Ok(vec![e]), tsa((a, p)));
+    }
+
+    #[test]
+    fn to_socket_addr_str_u16() {
+        let a = SocketAddr::new(IpAddr::new_v4(77, 88, 21, 11), 24352);
+        assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352u16)));
+
+        let a = SocketAddr::new(IpAddr::new_v6(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
+        assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53)));
+
+        let a = SocketAddr::new(IpAddr::new_v4(127, 0, 0, 1), 23924);
+        assert!(tsa(("localhost", 23924u16)).unwrap().contains(&a));
+    }
+
+    #[test]
+    fn to_socket_addr_str() {
+        let a = SocketAddr::new(IpAddr::new_v4(77, 88, 21, 11), 24352);
+        assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352"));
+
+        let a = SocketAddr::new(IpAddr::new_v6(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53);
+        assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53"));
+
+        let a = SocketAddr::new(IpAddr::new_v4(127, 0, 0, 1), 23924);
+        assert!(tsa("localhost:23924").unwrap().contains(&a));
+    }
+}
diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs
new file mode 100644
index 00000000000..08f7a6e2e96
--- /dev/null
+++ b/src/libstd/net/ip.rs
@@ -0,0 +1,449 @@
+// Copyright 2015 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 prelude::v1::*;
+
+use cmp::Ordering;
+use hash;
+use fmt;
+use libc;
+use sys_common::{AsInner, FromInner};
+use net::{hton, ntoh};
+
+/// Representation of an IPv4 address.
+#[derive(Copy)]
+pub struct Ipv4Addr {
+    inner: libc::in_addr,
+}
+
+/// Representation of an IPv6 address.
+#[derive(Copy)]
+pub struct Ipv6Addr {
+    inner: libc::in6_addr,
+}
+
+#[allow(missing_docs)]
+#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+pub enum Ipv6MulticastScope {
+    InterfaceLocal,
+    LinkLocal,
+    RealmLocal,
+    AdminLocal,
+    SiteLocal,
+    OrganizationLocal,
+    Global
+}
+
+/// Enumeration of possible IP addresses
+#[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)]
+pub enum IpAddr {
+    /// An IPv4 address.
+    V4(Ipv4Addr),
+    /// An IPv6 address.
+    V6(Ipv6Addr)
+}
+
+impl IpAddr {
+    /// Create a new IpAddr that contains an IPv4 address.
+    ///
+    /// The result will represent the IP address a.b.c.d
+    pub fn new_v4(a: u8, b: u8, c: u8, d: u8) -> IpAddr {
+        IpAddr::V4(Ipv4Addr::new(a, b, c, d))
+    }
+
+    /// Create a new IpAddr that contains an IPv6 address.
+    ///
+    /// The result will represent the IP address a:b:c:d:e:f
+    pub fn new_v6(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
+                  h: u16) -> IpAddr {
+        IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h))
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for IpAddr {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            IpAddr::V4(v4) => v4.fmt(f),
+            IpAddr::V6(v6) => v6.fmt(f)
+        }
+    }
+}
+
+impl Ipv4Addr {
+    /// Create a new IPv4 address from four eight-bit octets.
+    ///
+    /// The result will represent the IP address a.b.c.d
+    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
+        Ipv4Addr {
+            inner: libc::in_addr {
+                s_addr: hton(((a as u32) << 24) |
+                             ((b as u32) << 16) |
+                             ((c as u32) <<  8) |
+                              (d as u32)),
+            }
+        }
+    }
+
+    /// Returns the four eight-bit integers that make up this address
+    pub fn octets(&self) -> [u8; 4] {
+        let bits = ntoh(self.inner.s_addr);
+        [(bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8]
+    }
+
+    /// Returns true for the special 'unspecified' address 0.0.0.0
+    pub fn is_unspecified(&self) -> bool {
+        self.inner.s_addr == 0
+    }
+
+    /// Returns true if this is a loopback address (127.0.0.0/8)
+    pub fn is_loopback(&self) -> bool {
+        self.octets()[0] == 127
+    }
+
+    /// Returns true if this is a private address.
+    ///
+    /// The private address ranges are defined in RFC1918 and include:
+    ///
+    ///  - 10.0.0.0/8
+    ///  - 172.16.0.0/12
+    ///  - 192.168.0.0/16
+    pub fn is_private(&self) -> bool {
+        match (self.octets()[0], self.octets()[1]) {
+            (10, _) => true,
+            (172, b) if b >= 16 && b <= 31 => true,
+            (192, 168) => true,
+            _ => false
+        }
+    }
+
+    /// Returns true if the address is link-local (169.254.0.0/16)
+    pub fn is_link_local(&self) -> bool {
+        self.octets()[0] == 169 && self.octets()[1] == 254
+    }
+
+    /// Returns true if the address appears to be globally routable.
+    ///
+    /// Non-globally-routable networks include the private networks (10.0.0.0/8,
+    /// 172.16.0.0/12 and 192.168.0.0/16), the loopback network (127.0.0.0/8),
+    /// and the link-local network (169.254.0.0/16).
+    pub fn is_global(&self) -> bool {
+        !self.is_private() && !self.is_loopback() && !self.is_link_local()
+    }
+
+    /// Returns true if this is a multicast address.
+    ///
+    /// Multicast addresses have a most significant octet between 224 and 239.
+    pub fn is_multicast(&self) -> bool {
+        self.octets()[0] >= 224 && self.octets()[0] <= 239
+    }
+
+    /// Convert this address to an IPv4-compatible IPv6 address
+    ///
+    /// a.b.c.d becomes ::a.b.c.d
+    pub fn to_ipv6_compatible(&self) -> Ipv6Addr {
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0,
+                      ((self.octets()[0] as u16) << 8) | self.octets()[1] as u16,
+                      ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16)
+    }
+
+    /// Convert this address to an IPv4-mapped IPv6 address
+    ///
+    /// a.b.c.d becomes ::ffff:a.b.c.d
+    pub fn to_ipv6_mapped(&self) -> Ipv6Addr {
+        Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff,
+                      ((self.octets()[0] as u16) << 8) | self.octets()[1] as u16,
+                      ((self.octets()[2] as u16) << 8) | self.octets()[3] as u16)
+    }
+
+}
+
+impl fmt::Display for Ipv4Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        let octets = self.octets();
+        write!(fmt, "{}.{}.{}.{}", octets[0], octets[1], octets[2], octets[3])
+    }
+}
+
+impl fmt::Debug for Ipv4Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+impl Clone for Ipv4Addr {
+    fn clone(&self) -> Ipv4Addr { *self }
+}
+
+impl PartialEq for Ipv4Addr {
+    fn eq(&self, other: &Ipv4Addr) -> bool {
+        self.inner.s_addr == other.inner.s_addr
+    }
+}
+impl Eq for Ipv4Addr {}
+
+impl<S: hash::Hasher + hash::Writer> hash::Hash<S> for Ipv4Addr {
+    fn hash(&self, s: &mut S) {
+        self.inner.s_addr.hash(s)
+    }
+}
+
+impl PartialOrd for Ipv4Addr {
+    fn partial_cmp(&self, other: &Ipv4Addr) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for Ipv4Addr {
+    fn cmp(&self, other: &Ipv4Addr) -> Ordering {
+        self.inner.s_addr.cmp(&other.inner.s_addr)
+    }
+}
+
+impl AsInner<libc::in_addr> for Ipv4Addr {
+    fn as_inner(&self) -> &libc::in_addr { &self.inner }
+}
+impl FromInner<libc::in_addr> for Ipv4Addr {
+    fn from_inner(addr: libc::in_addr) -> Ipv4Addr {
+        Ipv4Addr { inner: addr }
+    }
+}
+
+impl Ipv6Addr {
+    /// Create a new IPv6 address from eight 16-bit segments.
+    ///
+    /// The result will represent the IP address a:b:c:d:e:f
+    pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
+               h: u16) -> Ipv6Addr {
+        Ipv6Addr {
+            inner: libc::in6_addr {
+                s6_addr: [hton(a), hton(b), hton(c), hton(d),
+                          hton(e), hton(f), hton(g), hton(h)]
+            }
+        }
+    }
+
+    /// Return the eight 16-bit segments that make up this address
+    pub fn segments(&self) -> [u16; 8] {
+        [ntoh(self.inner.s6_addr[0]),
+         ntoh(self.inner.s6_addr[1]),
+         ntoh(self.inner.s6_addr[2]),
+         ntoh(self.inner.s6_addr[3]),
+         ntoh(self.inner.s6_addr[4]),
+         ntoh(self.inner.s6_addr[5]),
+         ntoh(self.inner.s6_addr[6]),
+         ntoh(self.inner.s6_addr[7])]
+    }
+
+    /// Returns true for the special 'unspecified' address ::
+    pub fn is_unspecified(&self) -> bool {
+        self.segments() == [0, 0, 0, 0, 0, 0, 0, 0]
+    }
+
+    /// Returns true if this is a loopback address (::1)
+    pub fn is_loopback(&self) -> bool {
+        self.segments() == [0, 0, 0, 0, 0, 0, 0, 1]
+    }
+
+    /// Returns true if the address appears to be globally routable.
+    ///
+    /// Non-globally-routable networks include the loopback address; the
+    /// link-local, site-local, and unique local unicast addresses; and the
+    /// interface-, link-, realm-, admin- and site-local multicast addresses.
+    pub fn is_global(&self) -> bool {
+        match self.multicast_scope() {
+            Some(Ipv6MulticastScope::Global) => true,
+            None => self.is_unicast_global(),
+            _ => false
+        }
+    }
+
+    /// Returns true if this is a unique local address (IPv6)
+    ///
+    /// Unique local addresses are defined in RFC4193 and have the form fc00::/7
+    pub fn is_unique_local(&self) -> bool {
+        (self.segments()[0] & 0xfe00) == 0xfc00
+    }
+
+    /// Returns true if the address is unicast and link-local (fe80::/10)
+    pub fn is_unicast_link_local(&self) -> bool {
+        (self.segments()[0] & 0xffc0) == 0xfe80
+    }
+
+    /// Returns true if this is a deprecated unicast site-local address (IPv6
+    /// fec0::/10)
+    pub fn is_unicast_site_local(&self) -> bool {
+        (self.segments()[0] & 0xffc0) == 0xfec0
+    }
+
+    /// Returns true if the address is a globally routable unicast address
+    ///
+    /// Non-globally-routable unicast addresses include the loopback address,
+    /// the link-local addresses, the deprecated site-local addresses and the
+    /// unique local addresses.
+    pub fn is_unicast_global(&self) -> bool {
+        !self.is_multicast()
+            && !self.is_loopback() && !self.is_unicast_link_local()
+            && !self.is_unicast_site_local() && !self.is_unique_local()
+    }
+
+    /// Returns the address's multicast scope if the address is multicast.
+    pub fn multicast_scope(&self) -> Option<Ipv6MulticastScope> {
+        if self.is_multicast() {
+            match self.segments()[0] & 0x000f {
+                1 => Some(Ipv6MulticastScope::InterfaceLocal),
+                2 => Some(Ipv6MulticastScope::LinkLocal),
+                3 => Some(Ipv6MulticastScope::RealmLocal),
+                4 => Some(Ipv6MulticastScope::AdminLocal),
+                5 => Some(Ipv6MulticastScope::SiteLocal),
+                8 => Some(Ipv6MulticastScope::OrganizationLocal),
+                14 => Some(Ipv6MulticastScope::Global),
+                _ => None
+            }
+        } else {
+            None
+        }
+    }
+
+    /// Returns true if this is a multicast address.
+    ///
+    /// Multicast addresses have the form ff00::/8.
+    pub fn is_multicast(&self) -> bool {
+        (self.segments()[0] & 0xff00) == 0xff00
+    }
+
+    /// Convert this address to an IPv4 address. Returns None if this address is
+    /// neither IPv4-compatible or IPv4-mapped.
+    ///
+    /// ::a.b.c.d and ::ffff:a.b.c.d become a.b.c.d
+    pub fn to_ipv4(&self) -> Option<Ipv4Addr> {
+        match self.segments() {
+            [0, 0, 0, 0, 0, f, g, h] if f == 0 || f == 0xffff => {
+                Some(Ipv4Addr::new((g >> 8) as u8, g as u8,
+                                   (h >> 8) as u8, h as u8))
+            },
+            _ => None
+        }
+    }
+}
+
+impl fmt::Display for Ipv6Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        match self.segments() {
+            // We need special cases for :: and ::1, otherwise they're formatted
+            // as ::0.0.0.[01]
+            [0, 0, 0, 0, 0, 0, 0, 0] => write!(fmt, "::"),
+            [0, 0, 0, 0, 0, 0, 0, 1] => write!(fmt, "::1"),
+            // Ipv4 Compatible address
+            [0, 0, 0, 0, 0, 0, g, h] => {
+                write!(fmt, "::{}.{}.{}.{}", (g >> 8) as u8, g as u8,
+                       (h >> 8) as u8, h as u8)
+            }
+            // Ipv4-Mapped address
+            [0, 0, 0, 0, 0, 0xffff, g, h] => {
+                write!(fmt, "::ffff:{}.{}.{}.{}", (g >> 8) as u8, g as u8,
+                       (h >> 8) as u8, h as u8)
+            },
+            _ => {
+                fn find_zero_slice(segments: &[u16; 8]) -> (usize, usize) {
+                    let mut longest_span_len = 0;
+                    let mut longest_span_at = 0;
+                    let mut cur_span_len = 0;
+                    let mut cur_span_at = 0;
+
+                    for i in range(0, 8) {
+                        if segments[i] == 0 {
+                            if cur_span_len == 0 {
+                                cur_span_at = i;
+                            }
+
+                            cur_span_len += 1;
+
+                            if cur_span_len > longest_span_len {
+                                longest_span_len = cur_span_len;
+                                longest_span_at = cur_span_at;
+                            }
+                        } else {
+                            cur_span_len = 0;
+                            cur_span_at = 0;
+                        }
+                    }
+
+                    (longest_span_at, longest_span_len)
+                }
+
+                let (zeros_at, zeros_len) = find_zero_slice(&self.segments());
+
+                if zeros_len > 1 {
+                    fn fmt_subslice(segments: &[u16]) -> String {
+                        segments
+                            .iter()
+                            .map(|&seg| format!("{:x}", seg))
+                            .collect::<Vec<String>>()
+                            .as_slice()
+                            .connect(":")
+                    }
+
+                    write!(fmt, "{}::{}",
+                           fmt_subslice(&self.segments()[..zeros_at]),
+                           fmt_subslice(&self.segments()[zeros_at + zeros_len..]))
+                } else {
+                    let &[a, b, c, d, e, f, g, h] = &self.segments();
+                    write!(fmt, "{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}:{:x}",
+                           a, b, c, d, e, f, g, h)
+                }
+            }
+        }
+    }
+}
+
+impl fmt::Debug for Ipv6Addr {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(self, fmt)
+    }
+}
+
+impl Clone for Ipv6Addr {
+    fn clone(&self) -> Ipv6Addr { *self }
+}
+
+impl PartialEq for Ipv6Addr {
+    fn eq(&self, other: &Ipv6Addr) -> bool {
+        self.inner.s6_addr == other.inner.s6_addr
+    }
+}
+impl Eq for Ipv6Addr {}
+
+impl<S: hash::Hasher + hash::Writer> hash::Hash<S> for Ipv6Addr {
+    fn hash(&self, s: &mut S) {
+        self.inner.s6_addr.hash(s)
+    }
+}
+
+impl PartialOrd for Ipv6Addr {
+    fn partial_cmp(&self, other: &Ipv6Addr) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for Ipv6Addr {
+    fn cmp(&self, other: &Ipv6Addr) -> Ordering {
+        self.inner.s6_addr.cmp(&other.inner.s6_addr)
+    }
+}
+
+impl AsInner<libc::in6_addr> for Ipv6Addr {
+    fn as_inner(&self) -> &libc::in6_addr { &self.inner }
+}
+impl FromInner<libc::in6_addr> for Ipv6Addr {
+    fn from_inner(addr: libc::in6_addr) -> Ipv6Addr {
+        Ipv6Addr { inner: addr }
+    }
+}
diff --git a/src/libstd/net/mod.rs b/src/libstd/net/mod.rs
new file mode 100644
index 00000000000..d73c06a2549
--- /dev/null
+++ b/src/libstd/net/mod.rs
@@ -0,0 +1,99 @@
+// Copyright 2015 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.
+
+//! Networking primitives for TCP/UDP communication
+//!
+//! > **NOTE**: This module is very much a work in progress and is under active
+//! > development. At this time it is still recommended to use the `old_io`
+//! > module while the details of this module shake out.
+
+#![unstable(feature = "net")]
+
+use prelude::v1::*;
+
+use io::{self, Error, ErrorKind};
+use num::Int;
+use sys_common::net2 as net_imp;
+
+pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
+pub use self::addr::{SocketAddr, ToSocketAddrs};
+pub use self::tcp::{TcpStream, TcpListener};
+pub use self::udp::UdpSocket;
+
+mod ip;
+mod addr;
+mod tcp;
+mod udp;
+mod parser;
+#[cfg(test)] mod test;
+
+/// Possible values which can be passed to the `shutdown` method of `TcpStream`
+/// and `UdpSocket`.
+#[derive(Copy, Clone, PartialEq)]
+pub enum Shutdown {
+    /// Indicates that the reading portion of this stream/socket should be shut
+    /// down. All currently blocked and future reads will return `Ok(0)`.
+    Read,
+    /// Indicates that the writing portion of this stream/socket should be shut
+    /// down. All currently blocked and future writes will return an error.
+    Write,
+    /// Shut down both the reading and writing portions of this stream.
+    ///
+    /// See `Shutdown::Read` and `Shutdown::Write` for more information.
+    Both
+}
+
+fn hton<I: Int>(i: I) -> I { i.to_be() }
+fn ntoh<I: Int>(i: I) -> I { Int::from_be(i) }
+
+fn each_addr<A: ToSocketAddrs + ?Sized, F, T>(addr: &A, mut f: F) -> io::Result<T>
+    where F: FnMut(&SocketAddr) -> io::Result<T>
+{
+    let mut last_err = None;
+    for addr in try!(addr.to_socket_addrs()) {
+        match f(&addr) {
+            Ok(l) => return Ok(l),
+            Err(e) => last_err = Some(e),
+        }
+    }
+    Err(last_err.unwrap_or_else(|| {
+        Error::new(ErrorKind::InvalidInput,
+                   "could not resolve to any addresses", None)
+    }))
+}
+
+/// An iterator over `SocketAddr` values returned from a host lookup operation.
+pub struct LookupHost(net_imp::LookupHost);
+
+impl Iterator for LookupHost {
+    type Item = io::Result<SocketAddr>;
+    fn next(&mut self) -> Option<io::Result<SocketAddr>> { self.0.next() }
+}
+
+/// Resolve the host specified by `host` as a number of `SocketAddr` instances.
+///
+/// This method may perform a DNS query to resolve `host` and may also inspect
+/// system configuration to resolve the specified hostname.
+///
+/// # Example
+///
+/// ```no_run
+/// use std::net;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// for host in try!(net::lookup_host("rust-lang.org")) {
+///     println!("found address: {}", try!(host));
+/// }
+/// # Ok(())
+/// # }
+/// ```
+pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
+    net_imp::lookup_host(host).map(LookupHost)
+}
diff --git a/src/libstd/net/parser.rs b/src/libstd/net/parser.rs
new file mode 100644
index 00000000000..e82dc88cddd
--- /dev/null
+++ b/src/libstd/net/parser.rs
@@ -0,0 +1,330 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! A private parser implementation of IPv4, IPv6, and socket addresses.
+//!
+//! This module is "publicly exported" through the `FromStr` implementations
+//! below.
+
+use prelude::v1::*;
+
+use str::FromStr;
+use net::{Ipv4Addr, Ipv6Addr, IpAddr, SocketAddr};
+
+struct Parser<'a> {
+    // parsing as ASCII, so can use byte array
+    s: &'a [u8],
+    pos: usize,
+}
+
+impl<'a> Parser<'a> {
+    fn new(s: &'a str) -> Parser<'a> {
+        Parser {
+            s: s.as_bytes(),
+            pos: 0,
+        }
+    }
+
+    fn is_eof(&self) -> bool {
+        self.pos == self.s.len()
+    }
+
+    // Commit only if parser returns Some
+    fn read_atomically<T, F>(&mut self, cb: F) -> Option<T> where
+        F: FnOnce(&mut Parser) -> Option<T>,
+    {
+        let pos = self.pos;
+        let r = cb(self);
+        if r.is_none() {
+            self.pos = pos;
+        }
+        r
+    }
+
+    // Commit only if parser read till EOF
+    fn read_till_eof<T, F>(&mut self, cb: F) -> Option<T> where
+        F: FnOnce(&mut Parser) -> Option<T>,
+    {
+        self.read_atomically(move |p| {
+            match cb(p) {
+                Some(x) => if p.is_eof() {Some(x)} else {None},
+                None => None,
+            }
+        })
+    }
+
+    // Return result of first successful parser
+    fn read_or<T>(&mut self, parsers: &mut [Box<FnMut(&mut Parser) -> Option<T>>])
+               -> Option<T> {
+        for pf in parsers.iter_mut() {
+            match self.read_atomically(|p: &mut Parser| pf(p)) {
+                Some(r) => return Some(r),
+                None => {}
+            }
+        }
+        None
+    }
+
+    // Apply 3 parsers sequentially
+    fn read_seq_3<A, B, C, PA, PB, PC>(&mut self,
+                                       pa: PA,
+                                       pb: PB,
+                                       pc: PC)
+                                       -> Option<(A, B, C)> where
+        PA: FnOnce(&mut Parser) -> Option<A>,
+        PB: FnOnce(&mut Parser) -> Option<B>,
+        PC: FnOnce(&mut Parser) -> Option<C>,
+    {
+        self.read_atomically(move |p| {
+            let a = pa(p);
+            let b = if a.is_some() { pb(p) } else { None };
+            let c = if b.is_some() { pc(p) } else { None };
+            match (a, b, c) {
+                (Some(a), Some(b), Some(c)) => Some((a, b, c)),
+                _ => None
+            }
+        })
+    }
+
+    // Read next char
+    fn read_char(&mut self) -> Option<char> {
+        if self.is_eof() {
+            None
+        } else {
+            let r = self.s[self.pos] as char;
+            self.pos += 1;
+            Some(r)
+        }
+    }
+
+    // Return char and advance iff next char is equal to requested
+    fn read_given_char(&mut self, c: char) -> Option<char> {
+        self.read_atomically(|p| {
+            match p.read_char() {
+                Some(next) if next == c => Some(next),
+                _ => None,
+            }
+        })
+    }
+
+    // Read digit
+    fn read_digit(&mut self, radix: u8) -> Option<u8> {
+        fn parse_digit(c: char, radix: u8) -> Option<u8> {
+            let c = c as u8;
+            // assuming radix is either 10 or 16
+            if c >= b'0' && c <= b'9' {
+                Some(c - b'0')
+            } else if radix > 10 && c >= b'a' && c < b'a' + (radix - 10) {
+                Some(c - b'a' + 10)
+            } else if radix > 10 && c >= b'A' && c < b'A' + (radix - 10) {
+                Some(c - b'A' + 10)
+            } else {
+                None
+            }
+        }
+
+        self.read_atomically(|p| {
+            p.read_char().and_then(|c| parse_digit(c, radix))
+        })
+    }
+
+    fn read_number_impl(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
+        let mut r = 0u32;
+        let mut digit_count = 0;
+        loop {
+            match self.read_digit(radix) {
+                Some(d) => {
+                    r = r * (radix as u32) + (d as u32);
+                    digit_count += 1;
+                    if digit_count > max_digits || r >= upto {
+                        return None
+                    }
+                }
+                None => {
+                    if digit_count == 0 {
+                        return None
+                    } else {
+                        return Some(r)
+                    }
+                }
+            };
+        }
+    }
+
+    // Read number, failing if max_digits of number value exceeded
+    fn read_number(&mut self, radix: u8, max_digits: u32, upto: u32) -> Option<u32> {
+        self.read_atomically(|p| p.read_number_impl(radix, max_digits, upto))
+    }
+
+    fn read_ipv4_addr_impl(&mut self) -> Option<Ipv4Addr> {
+        let mut bs = [0u8; 4];
+        let mut i = 0;
+        while i < 4 {
+            if i != 0 && self.read_given_char('.').is_none() {
+                return None;
+            }
+
+            let octet = self.read_number(10, 3, 0x100).map(|n| n as u8);
+            match octet {
+                Some(d) => bs[i] = d,
+                None => return None,
+            };
+            i += 1;
+        }
+        Some(Ipv4Addr::new(bs[0], bs[1], bs[2], bs[3]))
+    }
+
+    // Read IPv4 address
+    fn read_ipv4_addr(&mut self) -> Option<Ipv4Addr> {
+        self.read_atomically(|p| p.read_ipv4_addr_impl())
+    }
+
+    fn read_ipv6_addr_impl(&mut self) -> Option<Ipv6Addr> {
+        fn ipv6_addr_from_head_tail(head: &[u16], tail: &[u16]) -> Ipv6Addr {
+            assert!(head.len() + tail.len() <= 8);
+            let mut gs = [0u16; 8];
+            gs.clone_from_slice(head);
+            gs[(8 - tail.len()) .. 8].clone_from_slice(tail);
+            Ipv6Addr::new(gs[0], gs[1], gs[2], gs[3], gs[4], gs[5], gs[6], gs[7])
+        }
+
+        fn read_groups(p: &mut Parser, groups: &mut [u16; 8], limit: usize)
+                       -> (usize, bool) {
+            let mut i = 0;
+            while i < limit {
+                if i < limit - 1 {
+                    let ipv4 = p.read_atomically(|p| {
+                        if i == 0 || p.read_given_char(':').is_some() {
+                            p.read_ipv4_addr()
+                        } else {
+                            None
+                        }
+                    });
+                    if let Some(v4_addr) = ipv4 {
+                        let octets = v4_addr.octets();
+                        groups[i + 0] = ((octets[0] as u16) << 8) | (octets[1] as u16);
+                        groups[i + 1] = ((octets[2] as u16) << 8) | (octets[3] as u16);
+                        return (i + 2, true);
+                    }
+                }
+
+                let group = p.read_atomically(|p| {
+                    if i == 0 || p.read_given_char(':').is_some() {
+                        p.read_number(16, 4, 0x10000).map(|n| n as u16)
+                    } else {
+                        None
+                    }
+                });
+                match group {
+                    Some(g) => groups[i] = g,
+                    None => return (i, false)
+                }
+                i += 1;
+            }
+            (i, false)
+        }
+
+        let mut head = [0u16; 8];
+        let (head_size, head_ipv4) = read_groups(self, &mut head, 8);
+
+        if head_size == 8 {
+            return Some(Ipv6Addr::new(
+                head[0], head[1], head[2], head[3],
+                head[4], head[5], head[6], head[7]))
+        }
+
+        // IPv4 part is not allowed before `::`
+        if head_ipv4 {
+            return None
+        }
+
+        // read `::` if previous code parsed less than 8 groups
+        if !self.read_given_char(':').is_some() || !self.read_given_char(':').is_some() {
+            return None;
+        }
+
+        let mut tail = [0u16; 8];
+        let (tail_size, _) = read_groups(self, &mut tail, 8 - head_size);
+        Some(ipv6_addr_from_head_tail(&head[..head_size], &tail[..tail_size]))
+    }
+
+    fn read_ipv6_addr(&mut self) -> Option<Ipv6Addr> {
+        self.read_atomically(|p| p.read_ipv6_addr_impl())
+    }
+
+    fn read_ip_addr(&mut self) -> Option<IpAddr> {
+        let ipv4_addr = |p: &mut Parser| p.read_ipv4_addr().map(|v4| IpAddr::V4(v4));
+        let ipv6_addr = |p: &mut Parser| p.read_ipv6_addr().map(|v6| IpAddr::V6(v6));
+        self.read_or(&mut [Box::new(ipv4_addr), Box::new(ipv6_addr)])
+    }
+
+    fn read_socket_addr(&mut self) -> Option<SocketAddr> {
+        let ip_addr = |p: &mut Parser| {
+            let ipv4_p = |p: &mut Parser| p.read_ip_addr();
+            let ipv6_p = |p: &mut Parser| {
+                let open_br = |p: &mut Parser| p.read_given_char('[');
+                let ip_addr = |p: &mut Parser| p.read_ipv6_addr();
+                let clos_br = |p: &mut Parser| p.read_given_char(']');
+                p.read_seq_3::<char, Ipv6Addr, char, _, _, _>(open_br, ip_addr, clos_br)
+                        .map(|t| match t { (_, ip, _) => IpAddr::V6(ip) })
+            };
+            p.read_or(&mut [Box::new(ipv4_p), Box::new(ipv6_p)])
+        };
+        let colon = |p: &mut Parser| p.read_given_char(':');
+        let port  = |p: &mut Parser| p.read_number(10, 5, 0x10000).map(|n| n as u16);
+
+        // host, colon, port
+        self.read_seq_3::<IpAddr, char, u16, _, _, _>(ip_addr, colon, port)
+                .map(|t| match t { (ip, _, port) => SocketAddr::new(ip, port) })
+    }
+}
+
+impl FromStr for IpAddr {
+    type Err = ParseError;
+    fn from_str(s: &str) -> Result<IpAddr, ParseError> {
+        match Parser::new(s).read_till_eof(|p| p.read_ip_addr()) {
+            Some(s) => Ok(s),
+            None => Err(ParseError),
+        }
+    }
+}
+
+impl FromStr for Ipv4Addr {
+    type Err = ParseError;
+    fn from_str(s: &str) -> Result<Ipv4Addr, ParseError> {
+        match Parser::new(s).read_till_eof(|p| p.read_ipv4_addr()) {
+            Some(s) => Ok(s),
+            None => Err(ParseError)
+        }
+    }
+}
+
+impl FromStr for Ipv6Addr {
+    type Err = ParseError;
+    fn from_str(s: &str) -> Result<Ipv6Addr, ParseError> {
+        match Parser::new(s).read_till_eof(|p| p.read_ipv6_addr()) {
+            Some(s) => Ok(s),
+            None => Err(ParseError)
+        }
+    }
+}
+
+impl FromStr for SocketAddr {
+    type Err = ParseError;
+    fn from_str(s: &str) -> Result<SocketAddr, ParseError> {
+        match Parser::new(s).read_till_eof(|p| p.read_socket_addr()) {
+            Some(s) => Ok(s),
+            None => Err(ParseError),
+        }
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Copy)]
+pub struct ParseError;
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
new file mode 100644
index 00000000000..50eafdfc5c2
--- /dev/null
+++ b/src/libstd/net/tcp.rs
@@ -0,0 +1,792 @@
+// Copyright 2015 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 prelude::v1::*;
+use io::prelude::*;
+
+use io;
+use net::{ToSocketAddrs, SocketAddr, Shutdown};
+use sys_common::net2 as net_imp;
+use sys_common::AsInner;
+
+/// A structure which represents a TCP stream between a local socket and a
+/// remote socket.
+///
+/// The socket will be closed when the value is dropped.
+///
+/// # Example
+///
+/// ```no_run
+/// use std::io::prelude::*;
+/// use std::net::TcpStream;
+///
+/// {
+///     let mut stream = TcpStream::connect("127.0.0.1:34254").unwrap();
+///
+///     // ignore the Result
+///     let _ = stream.write(&[1]);
+///     let _ = stream.read(&mut [0; 128]); // ignore here too
+/// } // the stream is closed here
+/// ```
+pub struct TcpStream(net_imp::TcpStream);
+
+/// A structure representing a socket server.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::net::{TcpListener, TcpStream};
+/// use std::thread::Thread;
+///
+/// let listener = TcpListener::bind("127.0.0.1:80").unwrap();
+///
+/// fn handle_client(stream: TcpStream) {
+///     // ...
+/// }
+///
+/// // accept connections and process them, spawning a new thread for each one
+/// for stream in listener.incoming() {
+///     match stream {
+///         Ok(stream) => {
+///             Thread::spawn(move|| {
+///                 // connection succeeded
+///                 handle_client(stream)
+///             });
+///         }
+///         Err(e) => { /* connection failed */ }
+///     }
+/// }
+///
+/// // close the socket server
+/// drop(listener);
+/// ```
+pub struct TcpListener(net_imp::TcpListener);
+
+/// An infinite iterator over the connections from a `TcpListener`.
+///
+/// This iterator will infinitely yield `Some` of the accepted connections. It
+/// is equivalent to calling `accept` in a loop.
+pub struct Incoming<'a> { listener: &'a TcpListener }
+
+impl TcpStream {
+    /// Open a TCP connection to a remote host.
+    ///
+    /// `addr` is an address of the remote host. Anything which implements
+    /// `ToSocketAddrs` trait can be supplied for the address; see this trait
+    /// documentation for concrete examples.
+    pub fn connect<A: ToSocketAddrs + ?Sized>(addr: &A) -> io::Result<TcpStream> {
+        super::each_addr(addr, net_imp::TcpStream::connect).map(TcpStream)
+    }
+
+    /// Returns the socket address of the remote peer of this TCP connection.
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        self.0.peer_addr()
+    }
+
+    /// Returns the socket address of the local half of this TCP connection.
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        self.0.socket_addr()
+    }
+
+    /// Shut down the read, write, or both halves of this connection.
+    ///
+    /// This function will cause all pending and future I/O on the specified
+    /// portions to return immediately with an appropriate value (see the
+    /// documentation of `Shutdown`).
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        self.0.shutdown(how)
+    }
+
+    /// Create a new independently owned handle to the underlying socket.
+    ///
+    /// The returned `TcpStream` is a reference to the same stream that this
+    /// object references. Both handles will read and write the same stream of
+    /// data, and options set on one stream will be propagated to the other
+    /// stream.
+    pub fn try_clone(&self) -> io::Result<TcpStream> {
+        self.0.duplicate().map(TcpStream)
+    }
+
+    /// Sets the nodelay flag on this connection to the boolean specified
+    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+        self.0.set_nodelay(nodelay)
+    }
+
+    /// Sets the keepalive timeout to the timeout specified.
+    ///
+    /// If the value specified is `None`, then the keepalive flag is cleared on
+    /// this connection. Otherwise, the keepalive timeout will be set to the
+    /// specified time, in seconds.
+    pub fn set_keepalive(&self, seconds: Option<u32>) -> io::Result<()> {
+        self.0.set_keepalive(seconds)
+    }
+}
+
+impl Read for TcpStream {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
+}
+impl Write for TcpStream {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+impl<'a> Read for &'a TcpStream {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
+}
+impl<'a> Write for &'a TcpStream {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) }
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+impl AsInner<net_imp::TcpStream> for TcpStream {
+    fn as_inner(&self) -> &net_imp::TcpStream { &self.0 }
+}
+
+impl TcpListener {
+    /// Creates a new `TcpListener` which will be bound to the specified
+    /// address.
+    ///
+    /// The returned listener is ready for accepting connections.
+    ///
+    /// Binding with a port number of 0 will request that the OS assigns a port
+    /// to this listener. The port allocated can be queried via the
+    /// `socket_addr` function.
+    ///
+    /// The address type can be any implementer of `ToSocketAddrs` trait. See
+    /// its documentation for concrete examples.
+    pub fn bind<A: ToSocketAddrs + ?Sized>(addr: &A) -> io::Result<TcpListener> {
+        super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener)
+    }
+
+    /// Returns the local socket address of this listener.
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        self.0.socket_addr()
+    }
+
+    /// Create a new independently owned handle to the underlying socket.
+    ///
+    /// The returned `TcpListener` is a reference to the same socket that this
+    /// object references. Both handles can be used to accept incoming
+    /// connections and options set on one listener will affect the other.
+    pub fn try_clone(&self) -> io::Result<TcpListener> {
+        self.0.duplicate().map(TcpListener)
+    }
+
+    /// Accept a new incoming connection from this listener.
+    ///
+    /// This function will block the calling thread until a new TCP connection
+    /// is established. When established, the corresponding `TcpStream` and the
+    /// remote peer's address will be returned.
+    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+        self.0.accept().map(|(a, b)| (TcpStream(a), b))
+    }
+
+    /// Returns an iterator over the connections being received on this
+    /// listener.
+    ///
+    /// The returned iterator will never returned `None` and will also not yield
+    /// the peer's `SocketAddr` structure.
+    pub fn incoming(&self) -> Incoming {
+        Incoming { listener: self }
+    }
+}
+
+impl<'a> Iterator for Incoming<'a> {
+    type Item = io::Result<TcpStream>;
+    fn next(&mut self) -> Option<io::Result<TcpStream>> {
+        Some(self.listener.accept().map(|p| p.0))
+    }
+}
+
+impl AsInner<net_imp::TcpListener> for TcpListener {
+    fn as_inner(&self) -> &net_imp::TcpListener { &self.0 }
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::v1::*;
+
+    use io::ErrorKind;
+    use io::prelude::*;
+    use net::*;
+    use net::test::{next_test_ip4, next_test_ip6};
+    use sync::mpsc::channel;
+    use thread::Thread;
+
+    fn each_ip(f: &mut FnMut(SocketAddr)) {
+        f(next_test_ip4());
+        f(next_test_ip6());
+    }
+
+    macro_rules! t {
+        ($e:expr) => {
+            match $e {
+                Ok(t) => t,
+                Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+            }
+        }
+    }
+
+    // FIXME #11530 this fails on android because tests are run as root
+    #[cfg_attr(any(windows, target_os = "android"), ignore)]
+    #[test]
+    fn bind_error() {
+        match TcpListener::bind("0.0.0.0:1") {
+            Ok(..) => panic!(),
+            Err(e) => assert_eq!(e.kind(), ErrorKind::PermissionDenied),
+        }
+    }
+
+    #[test]
+    fn connect_error() {
+        match TcpStream::connect("0.0.0.0:1") {
+            Ok(..) => panic!(),
+            Err(e) => assert_eq!(e.kind(), ErrorKind::ConnectionRefused),
+        }
+    }
+
+    #[test]
+    fn listen_localhost() {
+        let socket_addr = next_test_ip4();
+        let listener = t!(TcpListener::bind(&socket_addr));
+
+        let _t = Thread::scoped(move || {
+            let mut stream = t!(TcpStream::connect(&("localhost",
+                                                     socket_addr.port())));
+            t!(stream.write(&[144]));
+        });
+
+        let mut stream = t!(listener.accept()).0;
+        let mut buf = [0];
+        t!(stream.read(&mut buf));
+        assert!(buf[0] == 144);
+    }
+
+    #[test]
+    fn connect_ip4_loopback() {
+        let addr = next_test_ip4();
+        let acceptor = t!(TcpListener::bind(&addr));
+
+        let _t = Thread::scoped(move|| {
+            let mut stream = t!(TcpStream::connect(&("127.0.0.1", addr.port())));
+            t!(stream.write(&[44]));
+        });
+
+        let mut stream = t!(acceptor.accept()).0;
+        let mut buf = [0];
+        t!(stream.read(&mut buf));
+        assert!(buf[0] == 44);
+    }
+
+    #[test]
+    fn connect_ip6_loopback() {
+        let addr = next_test_ip6();
+        let acceptor = t!(TcpListener::bind(&addr));
+
+        let _t = Thread::scoped(move|| {
+            let mut stream = t!(TcpStream::connect(&("::1", addr.port())));
+            t!(stream.write(&[66]));
+        });
+
+        let mut stream = t!(acceptor.accept()).0;
+        let mut buf = [0];
+        t!(stream.read(&mut buf));
+        assert!(buf[0] == 66);
+    }
+
+    #[test]
+    fn smoke_test_ip6() {
+        each_ip(&mut |addr| {
+            let acceptor = t!(TcpListener::bind(&addr));
+
+            let (tx, rx) = channel();
+            let _t = Thread::scoped(move|| {
+                let mut stream = t!(TcpStream::connect(&addr));
+                t!(stream.write(&[99]));
+                tx.send(t!(stream.socket_addr())).unwrap();
+            });
+
+            let (mut stream, addr) = t!(acceptor.accept());
+            let mut buf = [0];
+            t!(stream.read(&mut buf));
+            assert!(buf[0] == 99);
+            assert_eq!(addr, t!(rx.recv()));
+        })
+    }
+
+    #[test]
+    fn read_eof_ip4() {
+        each_ip(&mut |addr| {
+            let acceptor = t!(TcpListener::bind(&addr));
+
+            let _t = Thread::scoped(move|| {
+                let _stream = t!(TcpStream::connect(&addr));
+                // Close
+            });
+
+            let mut stream = t!(acceptor.accept()).0;
+            let mut buf = [0];
+            let nread = t!(stream.read(&mut buf));
+            assert_eq!(nread, 0);
+            let nread = t!(stream.read(&mut buf));
+            assert_eq!(nread, 0);
+        })
+    }
+
+    #[test]
+    fn write_close() {
+        each_ip(&mut |addr| {
+            let acceptor = t!(TcpListener::bind(&addr));
+
+            let (tx, rx) = channel();
+            let _t = Thread::scoped(move|| {
+                drop(t!(TcpStream::connect(&addr)));
+                tx.send(()).unwrap();
+            });
+
+            let mut stream = t!(acceptor.accept()).0;
+            rx.recv().unwrap();
+            let buf = [0];
+            match stream.write(&buf) {
+                Ok(..) => {}
+                Err(e) => {
+                    assert!(e.kind() == ErrorKind::ConnectionReset ||
+                            e.kind() == ErrorKind::BrokenPipe ||
+                            e.kind() == ErrorKind::ConnectionAborted,
+                            "unknown error: {}", e);
+                }
+            }
+        })
+    }
+
+    #[test]
+    fn multiple_connect_serial_ip4() {
+        each_ip(&mut |addr| {
+            let max = 10;
+            let acceptor = t!(TcpListener::bind(&addr));
+
+            let _t = Thread::scoped(move|| {
+                for _ in 0..max {
+                    let mut stream = t!(TcpStream::connect(&addr));
+                    t!(stream.write(&[99]));
+                }
+            });
+
+            for stream in acceptor.incoming().take(max) {
+                let mut stream = t!(stream);
+                let mut buf = [0];
+                t!(stream.read(&mut buf));
+                assert_eq!(buf[0], 99);
+            }
+        })
+    }
+
+    #[test]
+    fn multiple_connect_interleaved_greedy_schedule() {
+        static MAX: usize = 10;
+        each_ip(&mut |addr| {
+            let acceptor = t!(TcpListener::bind(&addr));
+
+            let _t = Thread::scoped(move|| {
+                let acceptor = acceptor;
+                for (i, stream) in acceptor.incoming().enumerate().take(MAX) {
+                    // Start another task to handle the connection
+                    let _t = Thread::scoped(move|| {
+                        let mut stream = t!(stream);
+                        let mut buf = [0];
+                        t!(stream.read(&mut buf));
+                        assert!(buf[0] == i as u8);
+                    });
+                }
+            });
+
+            connect(0, addr);
+        });
+
+        fn connect(i: usize, addr: SocketAddr) {
+            if i == MAX { return }
+
+            let t = Thread::scoped(move|| {
+                let mut stream = t!(TcpStream::connect(&addr));
+                // Connect again before writing
+                connect(i + 1, addr);
+                t!(stream.write(&[i as u8]));
+            });
+            t.join().ok().unwrap();
+        }
+    }
+
+    #[test]
+    fn multiple_connect_interleaved_lazy_schedule_ip4() {
+        static MAX: usize = 10;
+        each_ip(&mut |addr| {
+            let acceptor = t!(TcpListener::bind(&addr));
+
+            let _t = Thread::scoped(move|| {
+                for stream in acceptor.incoming().take(MAX) {
+                    // Start another task to handle the connection
+                    let _t = Thread::scoped(move|| {
+                        let mut stream = t!(stream);
+                        let mut buf = [0];
+                        t!(stream.read(&mut buf));
+                        assert!(buf[0] == 99);
+                    });
+                }
+            });
+
+            connect(0, addr);
+        });
+
+        fn connect(i: usize, addr: SocketAddr) {
+            if i == MAX { return }
+
+            let t = Thread::scoped(move|| {
+                let mut stream = t!(TcpStream::connect(&addr));
+                connect(i + 1, addr);
+                t!(stream.write(&[99]));
+            });
+            t.join().ok().unwrap();
+        }
+    }
+
+    pub fn socket_name(addr: SocketAddr) {
+    }
+
+    pub fn peer_name(addr: SocketAddr) {
+    }
+
+    #[test]
+    fn socket_and_peer_name_ip4() {
+        each_ip(&mut |addr| {
+            let listener = t!(TcpListener::bind(&addr));
+            let so_name = t!(listener.socket_addr());
+            assert_eq!(addr, so_name);
+            let _t = Thread::scoped(move|| {
+                t!(listener.accept());
+            });
+
+            let stream = t!(TcpStream::connect(&addr));
+            assert_eq!(addr, t!(stream.peer_addr()));
+        })
+    }
+
+    #[test]
+    fn partial_read() {
+        each_ip(&mut |addr| {
+            let (tx, rx) = channel();
+            let srv = t!(TcpListener::bind(&addr));
+            let _t = Thread::scoped(move|| {
+                let mut cl = t!(srv.accept()).0;
+                cl.write(&[10]).unwrap();
+                let mut b = [0];
+                t!(cl.read(&mut b));
+                tx.send(()).unwrap();
+            });
+
+            let mut c = t!(TcpStream::connect(&addr));
+            let mut b = [0; 10];
+            assert_eq!(c.read(&mut b), Ok(1));
+            t!(c.write(&[1]));
+            rx.recv().unwrap();
+        })
+    }
+
+    #[test]
+    fn double_bind() {
+        each_ip(&mut |addr| {
+            let _listener = t!(TcpListener::bind(&addr));
+            match TcpListener::bind(&addr) {
+                Ok(..) => panic!(),
+                Err(e) => {
+                    assert!(e.kind() == ErrorKind::ConnectionRefused ||
+                            e.kind() == ErrorKind::Other,
+                            "unknown error: {} {:?}", e, e.kind());
+                }
+            }
+        })
+    }
+
+    #[test]
+    fn fast_rebind() {
+        each_ip(&mut |addr| {
+            let acceptor = t!(TcpListener::bind(&addr));
+
+            let _t = Thread::scoped(move|| {
+                t!(TcpStream::connect(&addr));
+            });
+
+            t!(acceptor.accept());
+            drop(acceptor);
+            t!(TcpListener::bind(&addr));
+        });
+    }
+
+    #[test]
+    fn tcp_clone_smoke() {
+        each_ip(&mut |addr| {
+            let acceptor = t!(TcpListener::bind(&addr));
+
+            let _t = Thread::scoped(move|| {
+                let mut s = t!(TcpStream::connect(&addr));
+                let mut buf = [0, 0];
+                assert_eq!(s.read(&mut buf), Ok(1));
+                assert_eq!(buf[0], 1);
+                t!(s.write(&[2]));
+            });
+
+            let mut s1 = t!(acceptor.accept()).0;
+            let s2 = t!(s1.try_clone());
+
+            let (tx1, rx1) = channel();
+            let (tx2, rx2) = channel();
+            let _t = Thread::scoped(move|| {
+                let mut s2 = s2;
+                rx1.recv().unwrap();
+                t!(s2.write(&[1]));
+                tx2.send(()).unwrap();
+            });
+            tx1.send(()).unwrap();
+            let mut buf = [0, 0];
+            assert_eq!(s1.read(&mut buf), Ok(1));
+            rx2.recv().unwrap();
+        })
+    }
+
+    #[test]
+    fn tcp_clone_two_read() {
+        each_ip(&mut |addr| {
+            let acceptor = t!(TcpListener::bind(&addr));
+            let (tx1, rx) = channel();
+            let tx2 = tx1.clone();
+
+            let _t = Thread::scoped(move|| {
+                let mut s = t!(TcpStream::connect(&addr));
+                t!(s.write(&[1]));
+                rx.recv().unwrap();
+                t!(s.write(&[2]));
+                rx.recv().unwrap();
+            });
+
+            let mut s1 = t!(acceptor.accept()).0;
+            let s2 = t!(s1.try_clone());
+
+            let (done, rx) = channel();
+            let _t = Thread::scoped(move|| {
+                let mut s2 = s2;
+                let mut buf = [0, 0];
+                t!(s2.read(&mut buf));
+                tx2.send(()).unwrap();
+                done.send(()).unwrap();
+            });
+            let mut buf = [0, 0];
+            t!(s1.read(&mut buf));
+            tx1.send(()).unwrap();
+
+            rx.recv().unwrap();
+        })
+    }
+
+    #[test]
+    fn tcp_clone_two_write() {
+        each_ip(&mut |addr| {
+            let acceptor = t!(TcpListener::bind(&addr));
+
+            let _t = Thread::scoped(move|| {
+                let mut s = t!(TcpStream::connect(&addr));
+                let mut buf = [0, 1];
+                t!(s.read(&mut buf));
+                t!(s.read(&mut buf));
+            });
+
+            let mut s1 = t!(acceptor.accept()).0;
+            let s2 = t!(s1.try_clone());
+
+            let (done, rx) = channel();
+            let _t = Thread::scoped(move|| {
+                let mut s2 = s2;
+                t!(s2.write(&[1]));
+                done.send(()).unwrap();
+            });
+            t!(s1.write(&[2]));
+
+            rx.recv().unwrap();
+        })
+    }
+
+    #[test]
+    fn shutdown_smoke() {
+        each_ip(&mut |addr| {
+            let a = t!(TcpListener::bind(&addr));
+            let _t = Thread::scoped(move|| {
+                let mut c = t!(a.accept()).0;
+                let mut b = [0];
+                assert_eq!(c.read(&mut b), Ok(0));
+                t!(c.write(&[1]));
+            });
+
+            let mut s = t!(TcpStream::connect(&addr));
+            t!(s.shutdown(Shutdown::Write));
+            assert!(s.write(&[1]).is_err());
+            let mut b = [0, 0];
+            assert_eq!(t!(s.read(&mut b)), 1);
+            assert_eq!(b[0], 1);
+        })
+    }
+
+    #[test]
+    fn close_readwrite_smoke() {
+        each_ip(&mut |addr| {
+            let a = t!(TcpListener::bind(&addr));
+            let (tx, rx) = channel::<()>();
+            let _t = Thread::scoped(move|| {
+                let _s = t!(a.accept());
+                let _ = rx.recv();
+            });
+
+            let mut b = [0];
+            let mut s = t!(TcpStream::connect(&addr));
+            let mut s2 = t!(s.try_clone());
+
+            // closing should prevent reads/writes
+            t!(s.shutdown(Shutdown::Write));
+            assert!(s.write(&[0]).is_err());
+            t!(s.shutdown(Shutdown::Read));
+            assert_eq!(s.read(&mut b), Ok(0));
+
+            // closing should affect previous handles
+            assert!(s2.write(&[0]).is_err());
+            assert_eq!(s2.read(&mut b), Ok(0));
+
+            // closing should affect new handles
+            let mut s3 = t!(s.try_clone());
+            assert!(s3.write(&[0]).is_err());
+            assert_eq!(s3.read(&mut b), Ok(0));
+
+            // make sure these don't die
+            let _ = s2.shutdown(Shutdown::Read);
+            let _ = s2.shutdown(Shutdown::Write);
+            let _ = s3.shutdown(Shutdown::Read);
+            let _ = s3.shutdown(Shutdown::Write);
+            drop(tx);
+        })
+    }
+
+    #[test]
+    fn close_read_wakes_up() {
+        each_ip(&mut |addr| {
+            let a = t!(TcpListener::bind(&addr));
+            let (tx1, rx) = channel::<()>();
+            let _t = Thread::scoped(move|| {
+                let _s = t!(a.accept());
+                let _ = rx.recv();
+            });
+
+            let s = t!(TcpStream::connect(&addr));
+            let s2 = t!(s.try_clone());
+            let (tx, rx) = channel();
+            let _t = Thread::scoped(move|| {
+                let mut s2 = s2;
+                assert_eq!(t!(s2.read(&mut [0])), 0);
+                tx.send(()).unwrap();
+            });
+            // this should wake up the child task
+            t!(s.shutdown(Shutdown::Read));
+
+            // this test will never finish if the child doesn't wake up
+            rx.recv().unwrap();
+            drop(tx1);
+        })
+    }
+
+    #[test]
+    fn clone_while_reading() {
+        each_ip(&mut |addr| {
+            let accept = t!(TcpListener::bind(&addr));
+
+            // Enqueue a task to write to a socket
+            let (tx, rx) = channel();
+            let (txdone, rxdone) = channel();
+            let txdone2 = txdone.clone();
+            let _t = Thread::scoped(move|| {
+                let mut tcp = t!(TcpStream::connect(&addr));
+                rx.recv().unwrap();
+                t!(tcp.write(&[0]));
+                txdone2.send(()).unwrap();
+            });
+
+            // Spawn off a reading clone
+            let tcp = t!(accept.accept()).0;
+            let tcp2 = t!(tcp.try_clone());
+            let txdone3 = txdone.clone();
+            let _t = Thread::scoped(move|| {
+                let mut tcp2 = tcp2;
+                t!(tcp2.read(&mut [0]));
+                txdone3.send(()).unwrap();
+            });
+
+            // Try to ensure that the reading clone is indeed reading
+            for _ in 0..50 {
+                Thread::yield_now();
+            }
+
+            // clone the handle again while it's reading, then let it finish the
+            // read.
+            let _ = t!(tcp.try_clone());
+            tx.send(()).unwrap();
+            rxdone.recv().unwrap();
+            rxdone.recv().unwrap();
+        })
+    }
+
+    #[test]
+    fn clone_accept_smoke() {
+        each_ip(&mut |addr| {
+            let a = t!(TcpListener::bind(&addr));
+            let a2 = t!(a.try_clone());
+
+            let _t = Thread::scoped(move|| {
+                let _ = TcpStream::connect(&addr);
+            });
+            let _t = Thread::scoped(move|| {
+                let _ = TcpStream::connect(&addr);
+            });
+
+            t!(a.accept());
+            t!(a2.accept());
+        })
+    }
+
+    #[test]
+    fn clone_accept_concurrent() {
+        each_ip(&mut |addr| {
+            let a = t!(TcpListener::bind(&addr));
+            let a2 = t!(a.try_clone());
+
+            let (tx, rx) = channel();
+            let tx2 = tx.clone();
+
+            let _t = Thread::scoped(move|| {
+                tx.send(t!(a.accept())).unwrap();
+            });
+            let _t = Thread::scoped(move|| {
+                tx2.send(t!(a2.accept())).unwrap();
+            });
+
+            let _t = Thread::scoped(move|| {
+                let _ = TcpStream::connect(&addr);
+            });
+            let _t = Thread::scoped(move|| {
+                let _ = TcpStream::connect(&addr);
+            });
+
+            rx.recv().unwrap();
+            rx.recv().unwrap();
+        })
+    }
+}
diff --git a/src/libstd/net/test.rs b/src/libstd/net/test.rs
new file mode 100644
index 00000000000..971fb4b69c8
--- /dev/null
+++ b/src/libstd/net/test.rs
@@ -0,0 +1,39 @@
+// Copyright 2015 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 prelude::v1::*;
+
+use env;
+use net::{SocketAddr, IpAddr};
+use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+
+pub fn next_test_ip4() -> SocketAddr {
+    static PORT: AtomicUsize = ATOMIC_USIZE_INIT;
+    SocketAddr::new(IpAddr::new_v4(127, 0, 0, 1),
+                    PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port())
+}
+
+pub fn next_test_ip6() -> SocketAddr {
+    static PORT: AtomicUsize = ATOMIC_USIZE_INIT;
+    SocketAddr::new(IpAddr::new_v6(0, 0, 0, 0, 0, 0, 0, 1),
+                    PORT.fetch_add(1, Ordering::SeqCst) as u16 + base_port())
+}
+
+// The bots run multiple builds at the same time, and these builds
+// all want to use ports. This function figures out which workspace
+// it is running in and assigns a port range based on it.
+fn base_port() -> u16 {
+    let cwd = env::current_dir().unwrap();
+    let dirs = ["32-opt", "32-nopt", "64-opt", "64-nopt", "64-opt-vg",
+                "all-opt", "snap3", "dist"];
+    dirs.iter().enumerate().find(|&(i, dir)| {
+        cwd.as_str().unwrap().contains(dir)
+    }).map(|p| p.0).unwrap_or(0) as u16 * 1000 + 19600
+}
diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs
new file mode 100644
index 00000000000..d162a29790e
--- /dev/null
+++ b/src/libstd/net/udp.rs
@@ -0,0 +1,291 @@
+// Copyright 2015 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 prelude::v1::*;
+
+use io::{self, Error, ErrorKind};
+use net::{ToSocketAddrs, SocketAddr, IpAddr};
+use sys_common::net2 as net_imp;
+use sys_common::AsInner;
+
+/// A User Datagram Protocol socket.
+///
+/// This is an implementation of a bound UDP socket. This supports both IPv4 and
+/// IPv6 addresses, and there is no corresponding notion of a server because UDP
+/// is a datagram protocol.
+///
+/// # Example
+///
+/// ```no_run
+/// use std::net::UdpSocket;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let mut socket = try!(UdpSocket::bind("127.0.0.1:34254"));
+///
+/// let mut buf = [0; 10];
+/// let (amt, src) = try!(socket.recv_from(&mut buf));
+///
+/// // Send a reply to the socket we received data from
+/// let buf = &mut buf[..amt];
+/// buf.reverse();
+/// try!(socket.send_to(buf, &src));
+///
+/// drop(socket); // close the socket
+/// # Ok(())
+/// # }
+/// ```
+pub struct UdpSocket(net_imp::UdpSocket);
+
+impl UdpSocket {
+    /// Creates a UDP socket from the given address.
+    ///
+    /// Address type can be any implementor of `ToSocketAddr` trait. See its
+    /// documentation for concrete examples.
+    pub fn bind<A: ToSocketAddrs + ?Sized>(addr: &A) -> io::Result<UdpSocket> {
+        super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket)
+    }
+
+    /// Receives data from the socket. On success, returns the number of bytes
+    /// read and the address from whence the data came.
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.0.recv_from(buf)
+    }
+
+    /// Sends data on the socket to the given address. Returns nothing on
+    /// success.
+    ///
+    /// Address type can be any implementor of `ToSocketAddrs` trait. See its
+    /// documentation for concrete examples.
+    pub fn send_to<A: ToSocketAddrs + ?Sized>(&self, buf: &[u8], addr: &A)
+                                              -> io::Result<usize> {
+        match try!(addr.to_socket_addrs()).next() {
+            Some(addr) => self.0.send_to(buf, &addr),
+            None => Err(Error::new(ErrorKind::InvalidInput,
+                                   "no addresses to send data to", None)),
+        }
+    }
+
+    /// Returns the socket address that this socket was created from.
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        self.0.socket_addr()
+    }
+
+    /// Create a new independently owned handle to the underlying socket.
+    ///
+    /// The returned `UdpSocket` is a reference to the same socket that this
+    /// object references. Both handles will read and write the same port, and
+    /// options set on one socket will be propagated to the other.
+    pub fn try_clone(&self) -> io::Result<UdpSocket> {
+        self.0.duplicate().map(UdpSocket)
+    }
+
+    /// Sets the broadcast flag on or off
+    pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
+        self.0.set_broadcast(on)
+    }
+
+    /// Set the multicast loop flag to the specified value
+    ///
+    /// This lets multicast packets loop back to local sockets (if enabled)
+    pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> {
+        self.0.set_multicast_loop(on)
+    }
+
+    /// Joins a multicast IP address (becomes a member of it)
+    pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> {
+        self.0.join_multicast(multi)
+    }
+
+    /// Leaves a multicast IP address (drops membership from it)
+    pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> {
+        self.0.leave_multicast(multi)
+    }
+
+    /// Sets the multicast TTL
+    pub fn set_multicast_time_to_live(&self, ttl: i32) -> io::Result<()> {
+        self.0.multicast_time_to_live(ttl)
+    }
+
+    /// Sets this socket's TTL
+    pub fn set_time_to_live(&self, ttl: i32) -> io::Result<()> {
+        self.0.time_to_live(ttl)
+    }
+}
+
+impl AsInner<net_imp::UdpSocket> for UdpSocket {
+    fn as_inner(&self) -> &net_imp::UdpSocket { &self.0 }
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::v1::*;
+
+    use io::ErrorKind;
+    use net::*;
+    use net::test::{next_test_ip4, next_test_ip6};
+    use sync::mpsc::channel;
+    use thread::Thread;
+
+    fn each_ip(f: &mut FnMut(SocketAddr, SocketAddr)) {
+        f(next_test_ip4(), next_test_ip4());
+        f(next_test_ip6(), next_test_ip6());
+    }
+
+    macro_rules! t {
+        ($e:expr) => {
+            match $e {
+                Ok(t) => t,
+                Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
+            }
+        }
+    }
+
+    // FIXME #11530 this fails on android because tests are run as root
+    #[cfg_attr(any(windows, target_os = "android"), ignore)]
+    #[test]
+    fn bind_error() {
+        let addr = SocketAddr::new(IpAddr::new_v4(0, 0, 0, 0), 1);
+        match UdpSocket::bind(&addr) {
+            Ok(..) => panic!(),
+            Err(e) => assert_eq!(e.kind(), ErrorKind::PermissionDenied),
+        }
+    }
+
+    #[test]
+    fn socket_smoke_test_ip4() {
+        each_ip(&mut |server_ip, client_ip| {
+            let (tx1, rx1) = channel();
+            let (tx2, rx2) = channel();
+
+            let _t = Thread::spawn(move|| {
+                let client = t!(UdpSocket::bind(&client_ip));
+                rx1.recv().unwrap();
+                t!(client.send_to(&[99], &server_ip));
+                tx2.send(()).unwrap();
+            });
+
+            let server = t!(UdpSocket::bind(&server_ip));
+            tx1.send(()).unwrap();
+            let mut buf = [0];
+            let (nread, src) = t!(server.recv_from(&mut buf));
+            assert_eq!(nread, 1);
+            assert_eq!(buf[0], 99);
+            assert_eq!(src, client_ip);
+            rx2.recv().unwrap();
+        })
+    }
+
+    #[test]
+    fn socket_name_ip4() {
+        each_ip(&mut |addr, _| {
+            let server = t!(UdpSocket::bind(&addr));
+            assert_eq!(addr, t!(server.socket_addr()));
+        })
+    }
+
+    #[test]
+    fn udp_clone_smoke() {
+        each_ip(&mut |addr1, addr2| {
+            let sock1 = t!(UdpSocket::bind(&addr1));
+            let sock2 = t!(UdpSocket::bind(&addr2));
+
+            let _t = Thread::spawn(move|| {
+                let mut buf = [0, 0];
+                assert_eq!(sock2.recv_from(&mut buf), Ok((1, addr1)));
+                assert_eq!(buf[0], 1);
+                t!(sock2.send_to(&[2], &addr1));
+            });
+
+            let sock3 = t!(sock1.try_clone());
+
+            let (tx1, rx1) = channel();
+            let (tx2, rx2) = channel();
+            let _t = Thread::spawn(move|| {
+                rx1.recv().unwrap();
+                t!(sock3.send_to(&[1], &addr2));
+                tx2.send(()).unwrap();
+            });
+            tx1.send(()).unwrap();
+            let mut buf = [0, 0];
+            assert_eq!(sock1.recv_from(&mut buf), Ok((1, addr2)));
+            rx2.recv().unwrap();
+        })
+    }
+
+    #[test]
+    fn udp_clone_two_read() {
+        each_ip(&mut |addr1, addr2| {
+            let sock1 = t!(UdpSocket::bind(&addr1));
+            let sock2 = t!(UdpSocket::bind(&addr2));
+            let (tx1, rx) = channel();
+            let tx2 = tx1.clone();
+
+            let _t = Thread::spawn(move|| {
+                t!(sock2.send_to(&[1], &addr1));
+                rx.recv().unwrap();
+                t!(sock2.send_to(&[2], &addr1));
+                rx.recv().unwrap();
+            });
+
+            let sock3 = t!(sock1.try_clone());
+
+            let (done, rx) = channel();
+            let _t = Thread::spawn(move|| {
+                let mut buf = [0, 0];
+                t!(sock3.recv_from(&mut buf));
+                tx2.send(()).unwrap();
+                done.send(()).unwrap();
+            });
+            let mut buf = [0, 0];
+            t!(sock1.recv_from(&mut buf));
+            tx1.send(()).unwrap();
+
+            rx.recv().unwrap();
+        })
+    }
+
+    #[test]
+    fn udp_clone_two_write() {
+        each_ip(&mut |addr1, addr2| {
+            let sock1 = t!(UdpSocket::bind(&addr1));
+            let sock2 = t!(UdpSocket::bind(&addr2));
+
+            let (tx, rx) = channel();
+            let (serv_tx, serv_rx) = channel();
+
+            let _t = Thread::spawn(move|| {
+                let mut buf = [0, 1];
+                rx.recv().unwrap();
+                t!(sock2.recv_from(&mut buf));
+                serv_tx.send(()).unwrap();
+            });
+
+            let sock3 = t!(sock1.try_clone());
+
+            let (done, rx) = channel();
+            let tx2 = tx.clone();
+            let _t = Thread::spawn(move|| {
+                match sock3.send_to(&[1], &addr2) {
+                    Ok(..) => { let _ = tx2.send(()); }
+                    Err(..) => {}
+                }
+                done.send(()).unwrap();
+            });
+            match sock1.send_to(&[2], &addr2) {
+                Ok(..) => { let _ = tx.send(()); }
+                Err(..) => {}
+            }
+            drop(tx);
+
+            rx.recv().unwrap();
+            serv_rx.recv().unwrap();
+        })
+    }
+}
diff --git a/src/libstd/old_io/mem.rs b/src/libstd/old_io/mem.rs
index 8f32703f200..0f4d9c8b4ea 100644
--- a/src/libstd/old_io/mem.rs
+++ b/src/libstd/old_io/mem.rs
@@ -66,6 +66,7 @@ impl Writer for Vec<u8> {
 #[deprecated(since = "1.0.0",
              reason = "use the Vec<u8> Writer implementation directly")]
 #[derive(Clone)]
+#[allow(deprecated)]
 pub struct MemWriter {
     buf: Vec<u8>,
 }
diff --git a/src/libstd/old_io/mod.rs b/src/libstd/old_io/mod.rs
index c3e4e7fc80d..94f4af8e558 100644
--- a/src/libstd/old_io/mod.rs
+++ b/src/libstd/old_io/mod.rs
@@ -50,7 +50,8 @@
 //!     ```rust
 //!     use std::old_io as io;
 //!
-//!     for line in io::stdin().lock().lines() {
+//!     let mut stdin = io::stdin();
+//!     for line in stdin.lock().lines() {
 //!         print!("{}", line.unwrap());
 //!     }
 //!     ```
@@ -249,7 +250,7 @@ use char::CharExt;
 use default::Default;
 use error::Error;
 use fmt;
-use int;
+use isize;
 use iter::{Iterator, IteratorExt};
 use marker::Sized;
 use mem::transmute;
@@ -265,7 +266,7 @@ use slice::SliceExt;
 use str::StrExt;
 use str;
 use string::String;
-use uint;
+use usize;
 use unicode;
 use vec::Vec;
 
@@ -711,28 +712,28 @@ pub trait Reader {
     ///
     /// The number of bytes returned is system-dependent.
     fn read_le_uint(&mut self) -> IoResult<uint> {
-        self.read_le_uint_n(uint::BYTES).map(|i| i as uint)
+        self.read_le_uint_n(usize::BYTES).map(|i| i as uint)
     }
 
     /// Reads a little-endian integer.
     ///
     /// The number of bytes returned is system-dependent.
     fn read_le_int(&mut self) -> IoResult<int> {
-        self.read_le_int_n(int::BYTES).map(|i| i as int)
+        self.read_le_int_n(isize::BYTES).map(|i| i as int)
     }
 
     /// Reads a big-endian unsigned integer.
     ///
     /// The number of bytes returned is system-dependent.
     fn read_be_uint(&mut self) -> IoResult<uint> {
-        self.read_be_uint_n(uint::BYTES).map(|i| i as uint)
+        self.read_be_uint_n(usize::BYTES).map(|i| i as uint)
     }
 
     /// Reads a big-endian integer.
     ///
     /// The number of bytes returned is system-dependent.
     fn read_be_int(&mut self) -> IoResult<int> {
-        self.read_be_int_n(int::BYTES).map(|i| i as int)
+        self.read_be_int_n(isize::BYTES).map(|i| i as int)
     }
 
     /// Reads a big-endian `u64`.
@@ -1095,25 +1096,25 @@ pub trait Writer {
     /// Write a little-endian uint (number of bytes depends on system).
     #[inline]
     fn write_le_uint(&mut self, n: uint) -> IoResult<()> {
-        extensions::u64_to_le_bytes(n as u64, uint::BYTES, |v| self.write_all(v))
+        extensions::u64_to_le_bytes(n as u64, usize::BYTES, |v| self.write_all(v))
     }
 
     /// Write a little-endian int (number of bytes depends on system).
     #[inline]
     fn write_le_int(&mut self, n: int) -> IoResult<()> {
-        extensions::u64_to_le_bytes(n as u64, int::BYTES, |v| self.write_all(v))
+        extensions::u64_to_le_bytes(n as u64, isize::BYTES, |v| self.write_all(v))
     }
 
     /// Write a big-endian uint (number of bytes depends on system).
     #[inline]
     fn write_be_uint(&mut self, n: uint) -> IoResult<()> {
-        extensions::u64_to_be_bytes(n as u64, uint::BYTES, |v| self.write_all(v))
+        extensions::u64_to_be_bytes(n as u64, usize::BYTES, |v| self.write_all(v))
     }
 
     /// Write a big-endian int (number of bytes depends on system).
     #[inline]
     fn write_be_int(&mut self, n: int) -> IoResult<()> {
-        extensions::u64_to_be_bytes(n as u64, int::BYTES, |v| self.write_all(v))
+        extensions::u64_to_be_bytes(n as u64, isize::BYTES, |v| self.write_all(v))
     }
 
     /// Write a big-endian u64 (8 bytes).
@@ -1843,7 +1844,7 @@ mod tests {
     use self::BadReaderBehavior::*;
     use super::{IoResult, Reader, MemReader, NoProgress, InvalidInput, Writer};
     use prelude::v1::{Ok, Vec, Buffer, SliceExt};
-    use uint;
+    use usize;
 
     #[derive(Clone, PartialEq, Debug)]
     enum BadReaderBehavior {
@@ -1890,24 +1891,24 @@ mod tests {
     #[test]
     fn test_read_at_least() {
         let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
-                                   vec![GoodBehavior(uint::MAX)]);
+                                   vec![GoodBehavior(usize::MAX)]);
         let buf = &mut [0u8; 5];
         assert!(r.read_at_least(1, buf).unwrap() >= 1);
         assert!(r.read_exact(5).unwrap().len() == 5); // read_exact uses read_at_least
         assert!(r.read_at_least(0, buf).is_ok());
 
         let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
-                                   vec![BadBehavior(50), GoodBehavior(uint::MAX)]);
+                                   vec![BadBehavior(50), GoodBehavior(usize::MAX)]);
         assert!(r.read_at_least(1, buf).unwrap() >= 1);
 
         let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
                                    vec![BadBehavior(1), GoodBehavior(1),
-                                        BadBehavior(50), GoodBehavior(uint::MAX)]);
+                                        BadBehavior(50), GoodBehavior(usize::MAX)]);
         assert!(r.read_at_least(1, buf).unwrap() >= 1);
         assert!(r.read_at_least(1, buf).unwrap() >= 1);
 
         let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
-                                   vec![BadBehavior(uint::MAX)]);
+                                   vec![BadBehavior(usize::MAX)]);
         assert_eq!(r.read_at_least(1, buf).unwrap_err().kind, NoProgress);
 
         let mut r = MemReader::new(b"hello, world!".to_vec());
@@ -1918,23 +1919,23 @@ mod tests {
     #[test]
     fn test_push_at_least() {
         let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
-                                   vec![GoodBehavior(uint::MAX)]);
+                                   vec![GoodBehavior(usize::MAX)]);
         let mut buf = Vec::new();
         assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1);
         assert!(r.push_at_least(0, 5, &mut buf).is_ok());
 
         let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
-                                   vec![BadBehavior(50), GoodBehavior(uint::MAX)]);
+                                   vec![BadBehavior(50), GoodBehavior(usize::MAX)]);
         assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1);
 
         let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
                                    vec![BadBehavior(1), GoodBehavior(1),
-                                        BadBehavior(50), GoodBehavior(uint::MAX)]);
+                                        BadBehavior(50), GoodBehavior(usize::MAX)]);
         assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1);
         assert!(r.push_at_least(1, 5, &mut buf).unwrap() >= 1);
 
         let mut r = BadReader::new(MemReader::new(b"hello, world!".to_vec()),
-                                   vec![BadBehavior(uint::MAX)]);
+                                   vec![BadBehavior(usize::MAX)]);
         assert_eq!(r.push_at_least(1, 5, &mut buf).unwrap_err().kind, NoProgress);
 
         let mut r = MemReader::new(b"hello, world!".to_vec());
diff --git a/src/libstd/old_io/stdio.rs b/src/libstd/old_io/stdio.rs
index 70400619bea..8e55251d285 100644
--- a/src/libstd/old_io/stdio.rs
+++ b/src/libstd/old_io/stdio.rs
@@ -48,7 +48,7 @@ use str::StrExt;
 use string::String;
 use sys::{fs, tty};
 use sync::{Arc, Mutex, MutexGuard, Once, ONCE_INIT};
-use uint;
+use usize;
 use vec::Vec;
 
 // And so begins the tale of acquiring a uv handle to a stdio stream on all
@@ -143,7 +143,8 @@ impl StdinReader {
     /// ```rust
     /// use std::old_io;
     ///
-    /// for line in old_io::stdin().lock().lines() {
+    /// let mut stdin = old_io::stdin();
+    /// for line in stdin.lock().lines() {
     ///     println!("{}", line.unwrap());
     /// }
     /// ```
@@ -383,12 +384,14 @@ pub fn println(s: &str) {
 
 /// Similar to `print`, but takes a `fmt::Arguments` structure to be compatible
 /// with the `format_args!` macro.
+#[stable(feature = "rust1", since = "1.0.0")]
 pub fn print_args(fmt: fmt::Arguments) {
     with_task_stdout(|io| write!(io, "{}", fmt))
 }
 
 /// Similar to `println`, but takes a `fmt::Arguments` structure to be
 /// compatible with the `format_args!` macro.
+#[stable(feature = "rust1", since = "1.0.0")]
 pub fn println_args(fmt: fmt::Arguments) {
     with_task_stdout(|io| writeln!(io, "{}", fmt))
 }
@@ -510,7 +513,7 @@ impl Writer for StdWriter {
         //
         // [1]: https://tahoe-lafs.org/trac/tahoe-lafs/ticket/1232
         // [2]: http://www.mail-archive.com/log4net-dev@logging.apache.org/msg00661.html
-        let max_size = if cfg!(windows) {8192} else {uint::MAX};
+        let max_size = if cfg!(windows) {8192} else {usize::MAX};
         for chunk in buf.chunks(max_size) {
             try!(match self.inner {
                 TTY(ref mut tty) => tty.write(chunk),
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 526b5edd4cb..2a0206d9ff0 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -125,7 +125,7 @@ pub fn getcwd() -> IoResult<Path> {
 #[deprecated(since = "1.0.0", reason = "use env::vars instead")]
 #[unstable(feature = "os")]
 pub fn env() -> Vec<(String,String)> {
-    env::vars().map(|(k, v)| {
+    env::vars_os().map(|(k, v)| {
         (k.to_string_lossy().into_owned(), v.to_string_lossy().into_owned())
     }).collect()
 }
@@ -135,7 +135,7 @@ pub fn env() -> Vec<(String,String)> {
 #[deprecated(since = "1.0.0", reason = "use env::vars instead")]
 #[unstable(feature = "os")]
 pub fn env_as_bytes() -> Vec<(Vec<u8>, Vec<u8>)> {
-    env::vars().map(|(k, v)| (byteify(k), byteify(v))).collect()
+    env::vars_os().map(|(k, v)| (byteify(k), byteify(v))).collect()
 }
 
 /// Fetches the environment variable `n` from the current process, returning
@@ -159,10 +159,10 @@ pub fn env_as_bytes() -> Vec<(Vec<u8>, Vec<u8>)> {
 ///     None => println!("{} is not defined in the environment.", key)
 /// }
 /// ```
-#[deprecated(since = "1.0.0", reason = "use env::var or env::var_string instead")]
+#[deprecated(since = "1.0.0", reason = "use env::var or env::var_os instead")]
 #[unstable(feature = "os")]
 pub fn getenv(n: &str) -> Option<String> {
-    env::var_string(n).ok()
+    env::var(n).ok()
 }
 
 /// Fetches the environment variable `n` byte vector from the current process,
@@ -174,7 +174,7 @@ pub fn getenv(n: &str) -> Option<String> {
 #[deprecated(since = "1.0.0", reason = "use env::var instead")]
 #[unstable(feature = "os")]
 pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
-    env::var(n).map(byteify)
+    env::var_os(n).map(byteify)
 }
 
 #[cfg(unix)]
@@ -317,6 +317,7 @@ pub unsafe fn pipe() -> IoResult<Pipe> {
 #[cfg(not(target_os="ios"))]
 #[deprecated(since = "1.0.0", reason = "this function will be removed, use the constants directly")]
 #[unstable(feature = "os")]
+#[allow(deprecated)]
 pub fn dll_filename(base: &str) -> String {
     format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
 }
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 776fa270867..4984b4f9aba 100755
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -878,7 +878,8 @@ impl PathBuf {
 
     /// Truncate `self` to `self.parent()`.
     ///
-    /// Returns `None` and does nothing if `self.parent()` is `None`.
+    /// Returns `false` and does nothing if `self.parent()` is `None`.
+    /// Otherwise, returns `true`.
     pub fn pop(&mut self) -> bool {
         match self.parent().map(|p| p.as_u8_slice().len()) {
             Some(len) => {
diff --git a/src/libstd/rt/backtrace.rs b/src/libstd/rt/backtrace.rs
index 2af5a486d0d..ced84d7551e 100644
--- a/src/libstd/rt/backtrace.rs
+++ b/src/libstd/rt/backtrace.rs
@@ -29,7 +29,7 @@ pub fn log_enabled() -> bool {
         _ => {}
     }
 
-    let val = match env::var("RUST_BACKTRACE") {
+    let val = match env::var_os("RUST_BACKTRACE") {
         Some(..) => 2,
         None => 1,
     };
diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs
index e064663b9e7..659e787a9ff 100644
--- a/src/libstd/rt/unwind.rs
+++ b/src/libstd/rt/unwind.rs
@@ -494,6 +494,7 @@ pub extern fn rust_begin_unwind(msg: fmt::Arguments,
 /// on (e.g.) the inlining of other functions as possible), by moving
 /// the actual formatting into this shared place.
 #[inline(never)] #[cold]
+#[stable(since = "1.0.0", feature = "rust1")]
 pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, uint)) -> ! {
     use fmt::Writer;
 
@@ -509,6 +510,7 @@ pub fn begin_unwind_fmt(msg: fmt::Arguments, file_line: &(&'static str, uint)) -
 
 /// This is the entry point of unwinding for panic!() and assert!().
 #[inline(never)] #[cold] // avoid code bloat at the call sites as much as possible
+#[stable(since = "1.0.0", feature = "rust1")]
 pub fn begin_unwind<M: Any + Send>(msg: M, file_line: &(&'static str, uint)) -> ! {
     // Note that this should be the only allocation performed in this code path.
     // Currently this means that panic!() on OOM will invoke this code path,
diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs
index 703dca4d29b..bb57d19ed26 100644
--- a/src/libstd/rt/util.rs
+++ b/src/libstd/rt/util.rs
@@ -52,7 +52,7 @@ pub fn min_stack() -> uint {
         0 => {}
         n => return n - 1,
     }
-    let amt = env::var_string("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
+    let amt = env::var("RUST_MIN_STACK").ok().and_then(|s| s.parse().ok());
     let amt = amt.unwrap_or(2 * 1024 * 1024);
     // 0 is our sentinel value, so ensure that we'll never see 0 after
     // initialization has run
@@ -63,7 +63,7 @@ pub fn min_stack() -> uint {
 /// Get's the number of scheduler threads requested by the environment
 /// either `RUST_THREADS` or `num_cpus`.
 pub fn default_sched_threads() -> uint {
-    match env::var_string("RUST_THREADS") {
+    match env::var("RUST_THREADS") {
         Ok(nstr) => {
             let opt_n: Option<uint> = nstr.parse().ok();
             match opt_n {
diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs
index 85c7572404b..babae93b2d4 100644
--- a/src/libstd/sync/mpsc/select.rs
+++ b/src/libstd/sync/mpsc/select.rs
@@ -61,7 +61,7 @@ use core::cell::Cell;
 use core::marker;
 use core::mem;
 use core::ptr;
-use core::uint;
+use core::usize;
 
 use sync::mpsc::{Receiver, RecvError};
 use sync::mpsc::blocking::{self, SignalToken};
@@ -228,7 +228,7 @@ impl Select {
             // A rewrite should focus on avoiding a yield loop, and for now this
             // implementation is tying us over to a more efficient "don't
             // iterate over everything every time" implementation.
-            let mut ready_id = uint::MAX;
+            let mut ready_id = usize::MAX;
             for handle in self.iter() {
                 if (*handle).packet.abort_selection() {
                     ready_id = (*handle).id;
@@ -236,7 +236,7 @@ impl Select {
             }
 
             // We must have found a ready receiver
-            assert!(ready_id != uint::MAX);
+            assert!(ready_id != usize::MAX);
             return ready_id;
         }
     }
diff --git a/src/libstd/sync/mpsc/shared.rs b/src/libstd/sync/mpsc/shared.rs
index c97af4c6bca..6c31fb92591 100644
--- a/src/libstd/sync/mpsc/shared.rs
+++ b/src/libstd/sync/mpsc/shared.rs
@@ -23,7 +23,7 @@ pub use self::Failure::*;
 use core::prelude::*;
 
 use core::cmp;
-use core::int;
+use core::isize;
 
 use sync::atomic::{AtomicUsize, AtomicIsize, AtomicBool, Ordering};
 use sync::mpsc::blocking::{self, SignalToken};
@@ -33,17 +33,17 @@ use sync::mpsc::select::StartResult;
 use sync::{Mutex, MutexGuard};
 use thread::Thread;
 
-const DISCONNECTED: int = int::MIN;
-const FUDGE: int = 1024;
+const DISCONNECTED: isize = isize::MIN;
+const FUDGE: isize = 1024;
 #[cfg(test)]
-const MAX_STEALS: int = 5;
+const MAX_STEALS: isize = 5;
 #[cfg(not(test))]
-const MAX_STEALS: int = 1 << 20;
+const MAX_STEALS: isize = 1 << 20;
 
 pub struct Packet<T> {
     queue: mpsc::Queue<T>,
     cnt: AtomicIsize, // How many items are on this channel
-    steals: int, // How many times has a port received without blocking?
+    steals: isize, // How many times has a port received without blocking?
     to_wake: AtomicUsize, // SignalToken for wake up
 
     // The number of channels which are currently using this packet.
diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs
index a03add8c532..ab9bd6b2ed7 100644
--- a/src/libstd/sync/mpsc/stream.rs
+++ b/src/libstd/sync/mpsc/stream.rs
@@ -25,7 +25,7 @@ use self::Message::*;
 use core::prelude::*;
 
 use core::cmp;
-use core::int;
+use core::isize;
 use thread::Thread;
 
 use sync::atomic::{AtomicIsize, AtomicUsize, Ordering, AtomicBool};
@@ -33,11 +33,11 @@ use sync::mpsc::Receiver;
 use sync::mpsc::blocking::{self, SignalToken};
 use sync::mpsc::spsc_queue as spsc;
 
-const DISCONNECTED: int = int::MIN;
+const DISCONNECTED: isize = isize::MIN;
 #[cfg(test)]
-const MAX_STEALS: int = 5;
+const MAX_STEALS: isize = 5;
 #[cfg(not(test))]
-const MAX_STEALS: int = 1 << 20;
+const MAX_STEALS: isize = 1 << 20;
 
 pub struct Packet<T> {
     queue: spsc::Queue<Message<T>>, // internal queue for all message
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index 2df211f3768..29c2051e5ad 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -13,7 +13,7 @@
 //! This primitive is meant to be used to run one-time initialization. An
 //! example use case would be for initializing an FFI library.
 
-use int;
+use isize;
 use marker::Sync;
 use mem::drop;
 use ops::FnOnce;
@@ -99,9 +99,9 @@ impl Once {
 
         let prev = self.cnt.fetch_add(1, Ordering::SeqCst);
         if prev < 0 {
-            // Make sure we never overflow, we'll never have int::MIN
+            // Make sure we never overflow, we'll never have isize::MIN
             // simultaneous calls to `call_once` to make this value go back to 0
-            self.cnt.store(int::MIN, Ordering::SeqCst);
+            self.cnt.store(isize::MIN, Ordering::SeqCst);
             return
         }
 
@@ -111,7 +111,7 @@ impl Once {
         let guard = self.mutex.lock();
         if self.cnt.load(Ordering::SeqCst) > 0 {
             f();
-            let prev = self.cnt.swap(int::MIN, Ordering::SeqCst);
+            let prev = self.cnt.swap(isize::MIN, Ordering::SeqCst);
             self.lock_cnt.store(prev, Ordering::SeqCst);
         }
         drop(guard);
diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs
index 80fa5f64597..5054f72ea98 100644
--- a/src/libstd/sys/common/mod.rs
+++ b/src/libstd/sys/common/mod.rs
@@ -24,6 +24,7 @@ pub mod condvar;
 pub mod helper_thread;
 pub mod mutex;
 pub mod net;
+pub mod net2;
 pub mod rwlock;
 pub mod stack;
 pub mod thread;
diff --git a/src/libstd/sys/common/net2.rs b/src/libstd/sys/common/net2.rs
new file mode 100644
index 00000000000..5af59ec6d2b
--- /dev/null
+++ b/src/libstd/sys/common/net2.rs
@@ -0,0 +1,393 @@
+// Copyright 2013-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.
+
+use prelude::v1::*;
+
+use ffi::CString;
+use io::{self, Error, ErrorKind};
+use libc::{self, c_int, c_char, c_void, socklen_t};
+use mem;
+use net::{IpAddr, SocketAddr, Shutdown};
+use num::Int;
+use sys::c;
+use sys::net::{cvt, cvt_r, cvt_gai, Socket, init, wrlen_t};
+use sys_common::{AsInner, FromInner, IntoInner};
+
+////////////////////////////////////////////////////////////////////////////////
+// sockaddr and misc bindings
+////////////////////////////////////////////////////////////////////////////////
+
+fn hton<I: Int>(i: I) -> I { i.to_be() }
+fn ntoh<I: Int>(i: I) -> I { Int::from_be(i) }
+
+fn setsockopt<T>(sock: &Socket, opt: c_int, val: c_int,
+                     payload: T) -> io::Result<()> {
+    unsafe {
+        let payload = &payload as *const T as *const c_void;
+        try!(cvt(libc::setsockopt(*sock.as_inner(), opt, val, payload,
+                                  mem::size_of::<T>() as socklen_t)));
+        Ok(())
+    }
+}
+
+#[allow(dead_code)]
+fn getsockopt<T: Copy>(sock: &Socket, opt: c_int,
+                           val: c_int) -> io::Result<T> {
+    unsafe {
+        let mut slot: T = mem::zeroed();
+        let mut len = mem::size_of::<T>() as socklen_t;
+        let ret = try!(cvt(c::getsockopt(*sock.as_inner(), opt, val,
+                                         &mut slot as *mut _ as *mut _,
+                                         &mut len)));
+        assert_eq!(ret as usize, mem::size_of::<T>());
+        Ok(slot)
+    }
+}
+
+fn sockname<F>(f: F) -> io::Result<SocketAddr>
+    where F: FnOnce(*mut libc::sockaddr, *mut socklen_t) -> c_int
+{
+    unsafe {
+        let mut storage: libc::sockaddr_storage = mem::zeroed();
+        let mut len = mem::size_of_val(&storage) as socklen_t;
+        try!(cvt(f(&mut storage as *mut _ as *mut _, &mut len)));
+        sockaddr_to_addr(&storage, len as usize)
+    }
+}
+
+fn sockaddr_to_addr(storage: &libc::sockaddr_storage,
+                    len: usize) -> io::Result<SocketAddr> {
+    match storage.ss_family as libc::c_int {
+        libc::AF_INET => {
+            assert!(len as usize >= mem::size_of::<libc::sockaddr_in>());
+            Ok(FromInner::from_inner(unsafe {
+                *(storage as *const _ as *const libc::sockaddr_in)
+            }))
+        }
+        libc::AF_INET6 => {
+            assert!(len as usize >= mem::size_of::<libc::sockaddr_in6>());
+            Ok(FromInner::from_inner(unsafe {
+                *(storage as *const _ as *const libc::sockaddr_in6)
+            }))
+        }
+        _ => {
+            Err(Error::new(ErrorKind::InvalidInput, "invalid argument", None))
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// get_host_addresses
+////////////////////////////////////////////////////////////////////////////////
+
+extern "system" {
+    fn getaddrinfo(node: *const c_char, service: *const c_char,
+                   hints: *const libc::addrinfo,
+                   res: *mut *mut libc::addrinfo) -> c_int;
+    fn freeaddrinfo(res: *mut libc::addrinfo);
+}
+
+pub struct LookupHost {
+    original: *mut libc::addrinfo,
+    cur: *mut libc::addrinfo,
+}
+
+impl Iterator for LookupHost {
+    type Item = io::Result<SocketAddr>;
+    fn next(&mut self) -> Option<io::Result<SocketAddr>> {
+        unsafe {
+            if self.cur.is_null() { return None }
+            let ret = sockaddr_to_addr(mem::transmute((*self.cur).ai_addr),
+                                       (*self.cur).ai_addrlen as usize);
+            self.cur = (*self.cur).ai_next as *mut libc::addrinfo;
+            Some(ret)
+        }
+    }
+}
+
+impl Drop for LookupHost {
+    fn drop(&mut self) {
+        unsafe { freeaddrinfo(self.original) }
+    }
+}
+
+pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
+    init();
+
+    let c_host = CString::from_slice(host.as_bytes());
+    let mut res = 0 as *mut _;
+    unsafe {
+        try!(cvt_gai(getaddrinfo(c_host.as_ptr(), 0 as *const _, 0 as *const _,
+                                 &mut res)));
+        Ok(LookupHost { original: res, cur: res })
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TCP streams
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct TcpStream {
+    inner: Socket,
+}
+
+impl TcpStream {
+    pub fn connect(addr: &SocketAddr) -> io::Result<TcpStream> {
+        init();
+
+        let sock = try!(Socket::new(addr, libc::SOCK_STREAM));
+
+        let (addrp, len) = addr.into_inner();
+        try!(cvt_r(|| unsafe { libc::connect(*sock.as_inner(), addrp, len) }));
+        Ok(TcpStream { inner: sock })
+    }
+
+    pub fn socket(&self) -> &Socket { &self.inner }
+
+    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+        setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_NODELAY,
+                   nodelay as c_int)
+    }
+
+    pub fn set_keepalive(&self, seconds: Option<u32>) -> io::Result<()> {
+        let ret = setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_KEEPALIVE,
+                             seconds.is_some() as c_int);
+        match seconds {
+            Some(n) => ret.and_then(|()| self.set_tcp_keepalive(n)),
+            None => ret,
+        }
+    }
+
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> {
+        setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPALIVE,
+                   seconds as c_int)
+    }
+    #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
+    fn set_tcp_keepalive(&self, seconds: u32) -> io::Result<()> {
+        setsockopt(&self.inner, libc::IPPROTO_TCP, libc::TCP_KEEPIDLE,
+                   seconds as c_int)
+    }
+    #[cfg(not(any(target_os = "macos",
+                  target_os = "ios",
+                  target_os = "freebsd",
+                  target_os = "dragonfly")))]
+    fn set_tcp_keepalive(&self, _seconds: u32) -> io::Result<()> {
+        Ok(())
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.inner.read(buf)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let ret = try!(cvt(unsafe {
+            libc::send(*self.inner.as_inner(),
+                       buf.as_ptr() as *const c_void,
+                       buf.len() as wrlen_t,
+                       0)
+        }));
+        Ok(ret as usize)
+    }
+
+    pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+        sockname(|buf, len| unsafe {
+            libc::getpeername(*self.inner.as_inner(), buf, len)
+        })
+    }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        sockname(|buf, len| unsafe {
+            libc::getsockname(*self.inner.as_inner(), buf, len)
+        })
+    }
+
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        use libc::consts::os::bsd44::SHUT_RDWR;
+
+        let how = match how {
+            Shutdown::Write => libc::SHUT_WR,
+            Shutdown::Read => libc::SHUT_RD,
+            Shutdown::Both => SHUT_RDWR,
+        };
+        try!(cvt(unsafe { libc::shutdown(*self.inner.as_inner(), how) }));
+        Ok(())
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpStream> {
+        self.inner.duplicate().map(|s| TcpStream { inner: s })
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// TCP listeners
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct TcpListener {
+    inner: Socket,
+}
+
+impl TcpListener {
+    pub fn bind(addr: &SocketAddr) -> io::Result<TcpListener> {
+        init();
+
+        let sock = try!(Socket::new(addr, libc::SOCK_STREAM));
+
+        // On platforms with Berkeley-derived sockets, this allows
+        // to quickly rebind a socket, without needing to wait for
+        // the OS to clean up the previous one.
+        if !cfg!(windows) {
+            try!(setsockopt(&sock, libc::SOL_SOCKET, libc::SO_REUSEADDR,
+                            1 as c_int));
+        }
+
+        // Bind our new socket
+        let (addrp, len) = addr.into_inner();
+        try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) }));
+
+        // Start listening
+        try!(cvt(unsafe { libc::listen(*sock.as_inner(), 128) }));
+        Ok(TcpListener { inner: sock })
+    }
+
+    pub fn socket(&self) -> &Socket { &self.inner }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        sockname(|buf, len| unsafe {
+            libc::getsockname(*self.inner.as_inner(), buf, len)
+        })
+    }
+
+    pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
+        let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
+        let mut len = mem::size_of_val(&storage) as socklen_t;
+        let sock = try!(self.inner.accept(&mut storage as *mut _ as *mut _,
+                                          &mut len));
+        let addr = try!(sockaddr_to_addr(&storage, len as usize));
+        Ok((TcpStream { inner: sock, }, addr))
+    }
+
+    pub fn duplicate(&self) -> io::Result<TcpListener> {
+        self.inner.duplicate().map(|s| TcpListener { inner: s })
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// UDP
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UdpSocket {
+    inner: Socket,
+}
+
+impl UdpSocket {
+    pub fn bind(addr: &SocketAddr) -> io::Result<UdpSocket> {
+        init();
+
+        let sock = try!(Socket::new(addr, libc::SOCK_DGRAM));
+        let (addrp, len) = addr.into_inner();
+        try!(cvt(unsafe { libc::bind(*sock.as_inner(), addrp, len) }));
+        Ok(UdpSocket { inner: sock })
+    }
+
+    pub fn socket(&self) -> &Socket { &self.inner }
+
+    pub fn socket_addr(&self) -> io::Result<SocketAddr> {
+        sockname(|buf, len| unsafe {
+            libc::getsockname(*self.inner.as_inner(), buf, len)
+        })
+    }
+
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
+        let mut addrlen = mem::size_of_val(&storage) as socklen_t;
+
+        let n = try!(cvt(unsafe {
+            libc::recvfrom(*self.inner.as_inner(),
+                           buf.as_mut_ptr() as *mut c_void,
+                           buf.len() as wrlen_t, 0,
+                           &mut storage as *mut _ as *mut _, &mut addrlen)
+        }));
+        Ok((n as usize, try!(sockaddr_to_addr(&storage, addrlen as usize))))
+    }
+
+    pub fn send_to(&self, buf: &[u8], dst: &SocketAddr) -> io::Result<usize> {
+        let (dstp, dstlen) = dst.into_inner();
+        let ret = try!(cvt(unsafe {
+            libc::sendto(*self.inner.as_inner(),
+                         buf.as_ptr() as *const c_void, buf.len() as wrlen_t,
+                         0, dstp, dstlen)
+        }));
+        Ok(ret as usize)
+    }
+
+    pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
+        setsockopt(&self.inner, libc::SOL_SOCKET, libc::SO_BROADCAST,
+                   on as c_int)
+    }
+
+    pub fn set_multicast_loop(&self, on: bool) -> io::Result<()> {
+        setsockopt(&self.inner, libc::IPPROTO_IP,
+                   libc::IP_MULTICAST_LOOP, on as c_int)
+    }
+
+    pub fn join_multicast(&self, multi: &IpAddr) -> io::Result<()> {
+        match *multi {
+            IpAddr::V4(..) => {
+                self.set_membership(multi, libc::IP_ADD_MEMBERSHIP)
+            }
+            IpAddr::V6(..) => {
+                self.set_membership(multi, libc::IPV6_ADD_MEMBERSHIP)
+            }
+        }
+    }
+    pub fn leave_multicast(&self, multi: &IpAddr) -> io::Result<()> {
+        match *multi {
+            IpAddr::V4(..) => {
+                self.set_membership(multi, libc::IP_DROP_MEMBERSHIP)
+            }
+            IpAddr::V6(..) => {
+                self.set_membership(multi, libc::IPV6_DROP_MEMBERSHIP)
+            }
+        }
+    }
+    fn set_membership(&self, addr: &IpAddr, opt: c_int) -> io::Result<()> {
+        match *addr {
+            IpAddr::V4(ref addr) => {
+                let mreq = libc::ip_mreq {
+                    imr_multiaddr: *addr.as_inner(),
+                    // interface == INADDR_ANY
+                    imr_interface: libc::in_addr { s_addr: 0x0 },
+                };
+                setsockopt(&self.inner, libc::IPPROTO_IP, opt, mreq)
+            }
+            IpAddr::V6(ref addr) => {
+                let mreq = libc::ip6_mreq {
+                    ipv6mr_multiaddr: *addr.as_inner(),
+                    ipv6mr_interface: 0,
+                };
+                setsockopt(&self.inner, libc::IPPROTO_IPV6, opt, mreq)
+            }
+        }
+    }
+
+    pub fn multicast_time_to_live(&self, ttl: i32) -> io::Result<()> {
+        setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_MULTICAST_TTL,
+                   ttl as c_int)
+    }
+
+    pub fn time_to_live(&self, ttl: i32) -> io::Result<()> {
+        setsockopt(&self.inner, libc::IPPROTO_IP, libc::IP_TTL, ttl as c_int)
+    }
+
+    pub fn duplicate(&self) -> io::Result<UdpSocket> {
+        self.inner.duplicate().map(|s| UdpSocket { inner: s })
+    }
+}
diff --git a/src/libstd/sys/common/thread.rs b/src/libstd/sys/common/thread.rs
index 048e33399a3..b725b6c7e6e 100644
--- a/src/libstd/sys/common/thread.rs
+++ b/src/libstd/sys/common/thread.rs
@@ -12,7 +12,7 @@ use core::prelude::*;
 
 use boxed::Box;
 use mem;
-use uint;
+use usize;
 use libc;
 use thunk::Thunk;
 use sys_common::stack;
@@ -25,7 +25,7 @@ use sys::{thread, stack_overflow};
 #[no_stack_check]
 pub fn start_thread(main: *mut libc::c_void) -> thread::rust_thread_return {
     unsafe {
-        stack::record_os_managed_stack_bounds(0, uint::MAX);
+        stack::record_os_managed_stack_bounds(0, usize::MAX);
         let handler = stack_overflow::Handler::new();
         let f: Box<Thunk> = mem::transmute(main);
         f.invoke(());
diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs
index edd16e0c062..905fac07c5d 100644
--- a/src/libstd/sys/common/thread_local.rs
+++ b/src/libstd/sys/common/thread_local.rs
@@ -84,14 +84,17 @@ use sys::thread_local as imp;
 ///     KEY.set(1 as *mut u8);
 /// }
 /// ```
+#[stable(feature = "rust1", since = "1.0.0")]
 pub struct StaticKey {
     /// Inner static TLS key (internals), created with by `INIT_INNER` in this
     /// module.
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub inner: StaticKeyInner,
     /// Destructor for the TLS value.
     ///
     /// See `Key::new` for information about when the destructor runs and how
     /// it runs.
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub dtor: Option<unsafe extern fn(*mut u8)>,
 }
 
@@ -128,6 +131,7 @@ pub struct Key {
 /// Constant initialization value for static TLS keys.
 ///
 /// This value specifies no destructor by default.
+#[stable(feature = "rust1", since = "1.0.0")]
 pub const INIT: StaticKey = StaticKey {
     inner: INIT_INNER,
     dtor: None,
@@ -136,6 +140,7 @@ pub const INIT: StaticKey = StaticKey {
 /// Constant initialization value for the inner part of static TLS keys.
 ///
 /// This value allows specific configuration of the destructor for a TLS key.
+#[stable(feature = "rust1", since = "1.0.0")]
 pub const INIT_INNER: StaticKeyInner = StaticKeyInner {
     key: atomic::ATOMIC_USIZE_INIT,
 };
diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs
index cf05733cc18..345808189a0 100644
--- a/src/libstd/sys/unix/c.rs
+++ b/src/libstd/sys/unix/c.rs
@@ -157,6 +157,7 @@ extern {
 
     pub fn utimes(filename: *const libc::c_char,
                   times: *const libc::timeval) -> libc::c_int;
+    pub fn gai_strerror(errcode: libc::c_int) -> *const libc::c_char;
 }
 
 #[cfg(any(target_os = "macos", target_os = "ios"))]
@@ -179,20 +180,20 @@ mod select {
           target_os = "openbsd",
           target_os = "linux"))]
 mod select {
-    use uint;
+    use usize;
     use libc;
 
-    pub const FD_SETSIZE: uint = 1024;
+    pub const FD_SETSIZE: usize = 1024;
 
     #[repr(C)]
     pub struct fd_set {
         // FIXME: shouldn't this be a c_ulong?
-        fds_bits: [libc::uintptr_t; (FD_SETSIZE / uint::BITS)]
+        fds_bits: [libc::uintptr_t; (FD_SETSIZE / usize::BITS)]
     }
 
     pub fn fd_set(set: &mut fd_set, fd: i32) {
         let fd = fd as uint;
-        set.fds_bits[fd / uint::BITS] |= 1 << (fd % uint::BITS);
+        set.fds_bits[fd / usize::BITS] |= 1 << (fd % usize::BITS);
     }
 }
 
diff --git a/src/libstd/sys/unix/ext.rs b/src/libstd/sys/unix/ext.rs
index 689bbda8322..1d95f1cce7e 100644
--- a/src/libstd/sys/unix/ext.rs
+++ b/src/libstd/sys/unix/ext.rs
@@ -32,8 +32,8 @@
 #![unstable(feature = "std_misc")]
 
 use ffi::{OsStr, OsString};
-use fs::{Permissions, OpenOptions};
-use fs;
+use fs::{self, Permissions, OpenOptions};
+use net;
 use libc;
 use mem;
 use sys::os_str::Buf;
@@ -111,6 +111,16 @@ impl AsRawFd for old_io::net::udp::UdpSocket {
     }
 }
 
+impl AsRawFd for net::TcpStream {
+    fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
+}
+impl AsRawFd for net::TcpListener {
+    fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
+}
+impl AsRawFd for net::UdpSocket {
+    fn as_raw_fd(&self) -> Fd { *self.as_inner().socket().as_inner() }
+}
+
 // Unix-specific extensions to `OsString`.
 pub trait OsStringExt {
     /// Create an `OsString` from a byte vector.
diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs
index f0943de5378..327d117823e 100644
--- a/src/libstd/sys/unix/fd.rs
+++ b/src/libstd/sys/unix/fd.rs
@@ -15,8 +15,7 @@ use io;
 use libc::{self, c_int, size_t, c_void};
 use mem;
 use sys::cvt;
-
-pub type fd_t = c_int;
+use sys_common::AsInner;
 
 pub struct FileDesc {
     fd: c_int,
@@ -55,6 +54,10 @@ impl FileDesc {
     }
 }
 
+impl AsInner<c_int> for FileDesc {
+    fn as_inner(&self) -> &c_int { &self.fd }
+}
+
 impl Drop for FileDesc {
     fn drop(&mut self) {
         // closing stdio file handles makes no sense, so never do it. Also, note
diff --git a/src/libstd/sys/unix/fs2.rs b/src/libstd/sys/unix/fs2.rs
index 070b3248349..77d5503b683 100644
--- a/src/libstd/sys/unix/fs2.rs
+++ b/src/libstd/sys/unix/fs2.rs
@@ -159,7 +159,7 @@ impl OpenOptions {
             flags: 0,
             read: false,
             write: false,
-            mode: libc::S_IRUSR | libc::S_IWUSR,
+            mode: 0o666,
         }
     }
 
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index b5a24278a20..96a18a956c6 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -18,12 +18,11 @@
 use prelude::v1::*;
 
 use ffi;
-use io::ErrorKind;
+use io::{self, ErrorKind};
 use libc;
 use num::{Int, SignedInt};
 use num;
 use old_io::{self, IoResult, IoError};
-use io;
 use str;
 use sys_common::mkerr_libc;
 
@@ -47,6 +46,7 @@ pub mod fs;  // support for std::old_io
 pub mod fs2; // support for std::fs
 pub mod helper_signal;
 pub mod mutex;
+pub mod net;
 pub mod os;
 pub mod os_str;
 pub mod pipe;
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
new file mode 100644
index 00000000000..54aec7cf4b1
--- /dev/null
+++ b/src/libstd/sys/unix/net.rs
@@ -0,0 +1,74 @@
+// Copyright 2015 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 prelude::v1::*;
+
+use ffi;
+use io;
+use libc::{self, c_int, size_t};
+use str;
+use sys::c;
+use net::{SocketAddr, IpAddr};
+use sys::fd::FileDesc;
+use sys_common::AsInner;
+
+pub use sys::{cvt, cvt_r};
+
+pub type wrlen_t = size_t;
+
+pub struct Socket(FileDesc);
+
+pub fn init() {}
+
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+    if err == 0 { return Ok(()) }
+
+    let detail = unsafe {
+        str::from_utf8(ffi::c_str_to_bytes(&c::gai_strerror(err))).unwrap()
+            .to_string()
+    };
+    Err(io::Error::new(io::ErrorKind::Other,
+                       "failed to lookup address information", Some(detail)))
+}
+
+impl Socket {
+    pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+        let fam = match addr.ip() {
+            IpAddr::V4(..) => libc::AF_INET,
+            IpAddr::V6(..) => libc::AF_INET6,
+        };
+        unsafe {
+            let fd = try!(cvt(libc::socket(fam, ty, 0)));
+            Ok(Socket(FileDesc::new(fd)))
+        }
+    }
+
+    pub fn accept(&self, storage: *mut libc::sockaddr,
+                  len: *mut libc::socklen_t) -> io::Result<Socket> {
+        let fd = try!(cvt_r(|| unsafe {
+            libc::accept(self.0.raw(), storage, len)
+        }));
+        Ok(Socket(FileDesc::new(fd)))
+    }
+
+    pub fn duplicate(&self) -> io::Result<Socket> {
+        cvt(unsafe { libc::dup(self.0.raw()) }).map(|fd| {
+            Socket(FileDesc::new(fd))
+        })
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.0.read(buf)
+    }
+}
+
+impl AsInner<c_int> for Socket {
+    fn as_inner(&self) -> &c_int { self.0.as_inner() }
+}
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index 0355565cf00..3a1b797eeb4 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -19,7 +19,9 @@ pub use self::FILE_INFO_BY_HANDLE_CLASS::*;
 pub use libc::consts::os::extra::{
     FILE_ATTRIBUTE_READONLY,
     FILE_ATTRIBUTE_DIRECTORY,
+    WSAPROTOCOL_LEN,
 };
+pub use libc::types::os::arch::extra::{GROUP, GUID, WSAPROTOCOLCHAIN};
 
 pub const WSADESCRIPTION_LEN: usize = 256;
 pub const WSASYS_STATUS_LEN: usize = 128;
@@ -41,6 +43,7 @@ pub const WSA_INFINITE: libc::DWORD = libc::INFINITE;
 pub const WSA_WAIT_TIMEOUT: libc::DWORD = libc::consts::os::extra::WAIT_TIMEOUT;
 pub const WSA_WAIT_EVENT_0: libc::DWORD = libc::consts::os::extra::WAIT_OBJECT_0;
 pub const WSA_WAIT_FAILED: libc::DWORD = libc::consts::os::extra::WAIT_FAILED;
+pub const WSAESHUTDOWN: libc::c_int = 10058;
 
 pub const ERROR_NO_MORE_FILES: libc::DWORD = 18;
 pub const TOKEN_READ: libc::DWORD = 0x20008;
@@ -81,6 +84,33 @@ pub type LPWSANETWORKEVENTS = *mut WSANETWORKEVENTS;
 pub type WSAEVENT = libc::HANDLE;
 
 #[repr(C)]
+#[derive(Copy)]
+pub struct WSAPROTOCOL_INFO {
+    pub dwServiceFlags1: libc::DWORD,
+    pub dwServiceFlags2: libc::DWORD,
+    pub dwServiceFlags3: libc::DWORD,
+    pub dwServiceFlags4: libc::DWORD,
+    pub dwProviderFlags: libc::DWORD,
+    pub ProviderId: GUID,
+    pub dwCatalogEntryId: libc::DWORD,
+    pub ProtocolChain: WSAPROTOCOLCHAIN,
+    pub iVersion: libc::c_int,
+    pub iAddressFamily: libc::c_int,
+    pub iMaxSockAddr: libc::c_int,
+    pub iMinSockAddr: libc::c_int,
+    pub iSocketType: libc::c_int,
+    pub iProtocol: libc::c_int,
+    pub iProtocolMaxOffset: libc::c_int,
+    pub iNetworkByteOrder: libc::c_int,
+    pub iSecurityScheme: libc::c_int,
+    pub dwMessageSize: libc::DWORD,
+    pub dwProviderReserved: libc::DWORD,
+    pub szProtocol: [u16; (WSAPROTOCOL_LEN as usize) + 1us],
+}
+
+pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
+
+#[repr(C)]
 pub struct fd_set {
     fd_count: libc::c_uint,
     fd_array: [libc::SOCKET; FD_SETSIZE],
@@ -184,6 +214,7 @@ pub struct FILE_END_OF_FILE_INFO {
 extern "system" {
     pub fn WSAStartup(wVersionRequested: libc::WORD,
                       lpWSAData: LPWSADATA) -> libc::c_int;
+    pub fn WSACleanup() -> libc::c_int;
     pub fn WSAGetLastError() -> libc::c_int;
     pub fn WSACloseEvent(hEvent: WSAEVENT) -> libc::BOOL;
     pub fn WSACreateEvent() -> WSAEVENT;
@@ -200,6 +231,17 @@ extern "system" {
                                 hEventObject: WSAEVENT,
                                 lpNetworkEvents: LPWSANETWORKEVENTS)
                                 -> libc::c_int;
+    pub fn WSADuplicateSocketW(s: libc::SOCKET,
+                               dwProcessId: libc::DWORD,
+                               lpProtocolInfo: LPWSAPROTOCOL_INFO)
+                               -> libc::c_int;
+    pub fn GetCurrentProcessId() -> libc::DWORD;
+    pub fn WSASocketW(af: libc::c_int,
+                      kind: libc::c_int,
+                      protocol: libc::c_int,
+                      lpProtocolInfo: LPWSAPROTOCOL_INFO,
+                      g: GROUP,
+                      dwFlags: libc::DWORD) -> libc::SOCKET;
 
     pub fn ioctlsocket(s: libc::SOCKET, cmd: libc::c_long,
                        argp: *mut libc::c_ulong) -> libc::c_int;
diff --git a/src/libstd/sys/windows/ext.rs b/src/libstd/sys/windows/ext.rs
index dc874c2c791..ac1006e653f 100644
--- a/src/libstd/sys/windows/ext.rs
+++ b/src/libstd/sys/windows/ext.rs
@@ -21,6 +21,7 @@ pub use sys_common::wtf8::{Wtf8Buf, EncodeWide};
 use ffi::{OsStr, OsString};
 use fs::{self, OpenOptions};
 use libc;
+use net;
 use sys::os_str::Buf;
 use sys_common::{AsInner, FromInner, AsInnerMut};
 
@@ -103,6 +104,16 @@ impl AsRawSocket for old_io::net::udp::UdpSocket {
     }
 }
 
+impl AsRawSocket for net::TcpStream {
+    fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
+}
+impl AsRawSocket for net::TcpListener {
+    fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
+}
+impl AsRawSocket for net::UdpSocket {
+    fn as_raw_socket(&self) -> Socket { *self.as_inner().socket().as_inner() }
+}
+
 // Windows-specific extensions to `OsString`.
 pub trait OsStringExt {
     /// Create an `OsString` from a potentially ill-formed UTF-16 slice of 16-bit code units.
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index 140bdb14501..0fa9aaf4323 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -43,6 +43,7 @@ pub mod fs2;
 pub mod handle;
 pub mod helper_signal;
 pub mod mutex;
+pub mod net;
 pub mod os;
 pub mod os_str;
 pub mod pipe;
diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs
new file mode 100644
index 00000000000..3451232f40a
--- /dev/null
+++ b/src/libstd/sys/windows/net.rs
@@ -0,0 +1,121 @@
+// Copyright 2015 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 prelude::v1::*;
+
+use io;
+use libc::consts::os::extra::INVALID_SOCKET;
+use libc::{self, c_int, c_void};
+use mem;
+use net::{SocketAddr, IpAddr};
+use num::{SignedInt, Int};
+use rt;
+use sync::{Once, ONCE_INIT};
+use sys::c;
+use sys_common::AsInner;
+
+pub type wrlen_t = i32;
+
+pub struct Socket(libc::SOCKET);
+
+pub fn init() {
+    static START: Once = ONCE_INIT;
+
+    START.call_once(|| unsafe {
+        let mut data: c::WSADATA = mem::zeroed();
+        let ret = c::WSAStartup(0x202, // version 2.2
+                                &mut data);
+        assert_eq!(ret, 0);
+
+        rt::at_exit(|| { c::WSACleanup(); })
+    });
+}
+
+fn last_error() -> io::Error {
+    io::Error::from_os_error(unsafe { c::WSAGetLastError() })
+}
+
+pub fn cvt<T: SignedInt>(t: T) -> io::Result<T> {
+    let one: T = Int::one();
+    if t == -one {
+        Err(last_error())
+    } else {
+        Ok(t)
+    }
+}
+
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+    if err == 0 { return Ok(()) }
+    cvt(err).map(|_| ())
+}
+
+pub fn cvt_r<T: SignedInt, F>(mut f: F) -> io::Result<T> where F: FnMut() -> T {
+    cvt(f())
+}
+
+impl Socket {
+    pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+        let fam = match addr.ip() {
+            IpAddr::V4(..) => libc::AF_INET,
+            IpAddr::V6(..) => libc::AF_INET6,
+        };
+        match unsafe { libc::socket(fam, ty, 0) } {
+            INVALID_SOCKET => Err(last_error()),
+            n => Ok(Socket(n)),
+        }
+    }
+
+    pub fn accept(&self, storage: *mut libc::sockaddr,
+                  len: *mut libc::socklen_t) -> io::Result<Socket> {
+        match unsafe { libc::accept(self.0, storage, len) } {
+            INVALID_SOCKET => Err(last_error()),
+            n => Ok(Socket(n)),
+        }
+    }
+
+    pub fn duplicate(&self) -> io::Result<Socket> {
+        unsafe {
+            let mut info: c::WSAPROTOCOL_INFO = mem::zeroed();
+            try!(cvt(c::WSADuplicateSocketW(self.0,
+                                            c::GetCurrentProcessId(),
+                                            &mut info)));
+            match c::WSASocketW(info.iAddressFamily,
+                                info.iSocketType,
+                                info.iProtocol,
+                                &mut info, 0, 0) {
+                INVALID_SOCKET => Err(last_error()),
+                n => Ok(Socket(n)),
+            }
+        }
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        // On unix when a socket is shut down all further reads return 0, so we
+        // do the same on windows to map a shut down socket to returning EOF.
+        unsafe {
+            match libc::recv(self.0, buf.as_mut_ptr() as *mut c_void,
+                             buf.len() as i32, 0) {
+                -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0),
+                -1 => Err(last_error()),
+                n => Ok(n as usize)
+            }
+        }
+    }
+}
+
+impl Drop for Socket {
+    fn drop(&mut self) {
+        unsafe { let _ = libc::closesocket(self.0); }
+    }
+}
+
+impl AsInner<libc::SOCKET> for Socket {
+    fn as_inner(&self) -> &libc::SOCKET { &self.0 }
+}
diff --git a/src/libstd/thread_local/mod.rs b/src/libstd/thread_local/mod.rs
index 9de5fd1c770..eab9cd84539 100644
--- a/src/libstd/thread_local/mod.rs
+++ b/src/libstd/thread_local/mod.rs
@@ -335,6 +335,7 @@ mod imp {
     use ptr;
 
     #[doc(hidden)]
+    #[stable(since = "1.0.0", feature = "rust1")]
     pub struct Key<T> {
         // Place the inner bits in an `UnsafeCell` to currently get around the
         // "only Sync statics" restriction. This allows any type to be placed in
@@ -342,11 +343,14 @@ mod imp {
         //
         // Note that all access requires `T: 'static` so it can't be a type with
         // any borrowed pointers still.
+        #[stable(since = "1.0.0", feature = "rust1")]
         pub inner: UnsafeCell<T>,
 
         // Metadata to keep track of the state of the destructor. Remember that
         // these variables are thread-local, not global.
+        #[stable(since = "1.0.0", feature = "rust1")]
         pub dtor_registered: UnsafeCell<bool>, // should be Cell
+        #[stable(since = "1.0.0", feature = "rust1")]
         pub dtor_running: UnsafeCell<bool>, // should be Cell
     }
 
@@ -448,6 +452,7 @@ mod imp {
     }
 
     #[doc(hidden)]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
         let ptr = ptr as *mut Key<T>;
         // Right before we run the user destructor be sure to flag the
@@ -468,12 +473,15 @@ mod imp {
     use sys_common::thread_local::StaticKey as OsStaticKey;
 
     #[doc(hidden)]
+    #[stable(since = "1.0.0", feature = "rust1")]
     pub struct Key<T> {
         // Statically allocated initialization expression, using an `UnsafeCell`
         // for the same reasons as above.
+        #[stable(since = "1.0.0", feature = "rust1")]
         pub inner: UnsafeCell<T>,
 
         // OS-TLS key that we'll use to key off.
+        #[stable(since = "1.0.0", feature = "rust1")]
         pub os: OsStaticKey,
     }
 
@@ -516,6 +524,7 @@ mod imp {
     }
 
     #[doc(hidden)]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub unsafe extern fn destroy_value<T: 'static>(ptr: *mut u8) {
         // The OS TLS ensures that this key contains a NULL value when this
         // destructor starts to run. We set it back to a sentinel value of 1 to
diff --git a/src/libstd/thread_local/scoped.rs b/src/libstd/thread_local/scoped.rs
index 1a20612d60a..01220e7bc1f 100644
--- a/src/libstd/thread_local/scoped.rs
+++ b/src/libstd/thread_local/scoped.rs
@@ -81,6 +81,7 @@ macro_rules! __scoped_thread_local_inner {
         #[cfg_attr(not(any(windows,
                            target_os = "android",
                            target_os = "ios",
+                           target_os = "openbsd",
                            target_arch = "aarch64")),
                    thread_local)]
         static $name: ::std::thread_local::scoped::Key<$t> =
@@ -90,6 +91,7 @@ macro_rules! __scoped_thread_local_inner {
         #[cfg_attr(not(any(windows,
                            target_os = "android",
                            target_os = "ios",
+                           target_os = "openbsd",
                            target_arch = "aarch64")),
                    thread_local)]
         pub static $name: ::std::thread_local::scoped::Key<$t> =
@@ -98,14 +100,22 @@ macro_rules! __scoped_thread_local_inner {
     ($t:ty) => ({
         use std::thread_local::scoped::Key as __Key;
 
-        #[cfg(not(any(windows, target_os = "android", target_os = "ios", target_arch = "aarch64")))]
+        #[cfg(not(any(windows,
+                      target_os = "android",
+                      target_os = "ios",
+                      target_os = "openbsd",
+                      target_arch = "aarch64")))]
         const _INIT: __Key<$t> = __Key {
             inner: ::std::thread_local::scoped::__impl::KeyInner {
                 inner: ::std::cell::UnsafeCell { value: 0 as *mut _ },
             }
         };
 
-        #[cfg(any(windows, target_os = "android", target_os = "ios", target_arch = "aarch64"))]
+        #[cfg(any(windows,
+                  target_os = "android",
+                  target_os = "ios",
+                  target_os = "openbsd",
+                  target_arch = "aarch64"))]
         const _INIT: __Key<$t> = __Key {
             inner: ::std::thread_local::scoped::__impl::KeyInner {
                 inner: ::std::thread_local::scoped::__impl::OS_INIT,
@@ -205,7 +215,11 @@ impl<T> Key<T> {
     }
 }
 
-#[cfg(not(any(windows, target_os = "android", target_os = "ios", target_arch = "aarch64")))]
+#[cfg(not(any(windows,
+              target_os = "android",
+              target_os = "ios",
+              target_os = "openbsd",
+              target_arch = "aarch64")))]
 mod imp {
     use std::cell::UnsafeCell;
 
@@ -223,7 +237,11 @@ mod imp {
     }
 }
 
-#[cfg(any(windows, target_os = "android", target_os = "ios", target_arch = "aarch64"))]
+#[cfg(any(windows,
+          target_os = "android",
+          target_os = "ios",
+          target_os = "openbsd",
+          target_arch = "aarch64"))]
 mod imp {
     use marker;
     use sys_common::thread_local::StaticKey as OsStaticKey;
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 5979d339e17..d6778be553e 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -366,6 +366,14 @@ pub struct DefId {
     pub node: NodeId,
 }
 
+impl DefId {
+    /// Read the node id, asserting that this def-id is krate-local.
+    pub fn local_id(&self) -> NodeId {
+        assert_eq!(self.krate, LOCAL_CRATE);
+        self.node
+    }
+}
+
 /// Item definitions in the currently-compiled crate would have the CrateNum
 /// LOCAL_CRATE in their DefId.
 pub const LOCAL_CRATE: CrateNum = 0;
diff --git a/src/libsyntax/ext/env.rs b/src/libsyntax/ext/env.rs
index ef9d3799879..5d56707c87a 100644
--- a/src/libsyntax/ext/env.rs
+++ b/src/libsyntax/ext/env.rs
@@ -30,7 +30,7 @@ pub fn expand_option_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenT
         Some(v) => v
     };
 
-    let e = match env::var_string(&var[]) {
+    let e = match env::var(&var[]) {
       Err(..) => {
           cx.expr_path(cx.path_all(sp,
                                    true,
@@ -101,7 +101,7 @@ pub fn expand_env<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
         }
     }
 
-    let e = match env::var_string(&var[]) {
+    let e = match env::var(&var[]) {
         Err(_) => {
             cx.span_err(sp, &msg);
             cx.expr_usize(sp, 0)
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 1a328f87c19..ca7ae32f09e 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -129,6 +129,10 @@ static KNOWN_FEATURES: &'static [(&'static str, &'static str, Status)] = &[
 
     // Allows using `box` in patterns; RFC 469
     ("box_patterns", "1.0.0", Active),
+
+    // Allows using the unsafe_no_drop_flag attribute (unlikely to
+    // switch to Accepted; see RFC 320)
+    ("unsafe_no_drop_flag", "1.0.0", Active),
 ];
 
 enum Status {
@@ -477,6 +481,12 @@ impl<'a, 'v> Visitor<'v> for PostExpansionVisitor<'a> {
             self.gate_feature("no_std", attr.span,
                               "no_std is experimental");
         }
+
+        if attr.check_name("unsafe_no_drop_flag") {
+            self.gate_feature("unsafe_no_drop_flag", attr.span,
+                              "unsafe_no_drop_flag has unstable semantics \
+                               and may be removed in the future");
+        }
     }
 
     fn visit_pat(&mut self, pattern: &ast::Pat) {
diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs
index 1a8cb2b376a..6511dffa6bf 100644
--- a/src/libsyntax/test.rs
+++ b/src/libsyntax/test.rs
@@ -436,40 +436,28 @@ fn mk_main(cx: &mut TestCtxt) -> P<ast::Item> {
     let sp = ignored_span(cx, DUMMY_SP);
     let ecx = &cx.ext_cx;
 
-    // std::slice::AsSlice
-    let as_slice_path = ecx.path(sp, vec![token::str_to_ident("std"),
-                                          token::str_to_ident("slice"),
-                                          token::str_to_ident("AsSlice")]);
     // test::test_main_static
     let test_main_path = ecx.path(sp, vec![token::str_to_ident("test"),
                                            token::str_to_ident("test_main_static")]);
-    // ::std::os::args
+    // ::std::env::args
     let os_args_path = ecx.path_global(sp, vec![token::str_to_ident("std"),
-                                                token::str_to_ident("os"),
+                                                token::str_to_ident("env"),
                                                 token::str_to_ident("args")]);
-    // use std::slice::AsSlice
-    let as_slice_path = P(nospan(ast::ViewPathSimple(token::str_to_ident("AsSlice"),
-                                                     as_slice_path)));
-    let use_as_slice = ecx.item_use(sp, ast::Inherited, as_slice_path);
-    let use_as_slice = ecx.stmt_item(sp, use_as_slice);
-    // ::std::os::args()
+    // ::std::env::args()
     let os_args_path_expr = ecx.expr_path(os_args_path);
     let call_os_args = ecx.expr_call(sp, os_args_path_expr, vec![]);
-    // ::std::os::args().as_slice()
-    let call_as_slice = ecx.expr_method_call(sp, call_os_args,
-                                             token::str_to_ident("as_slice"), vec![]);
     // test::test_main_static(...)
     let test_main_path_expr = ecx.expr_path(test_main_path);
     let tests_ident_expr = ecx.expr_ident(sp, token::str_to_ident("TESTS"));
     let call_test_main = ecx.expr_call(sp, test_main_path_expr,
-                                       vec![call_as_slice, tests_ident_expr]);
+                                       vec![call_os_args, tests_ident_expr]);
     let call_test_main = ecx.stmt_expr(call_test_main);
     // #![main]
     let main_meta = ecx.meta_word(sp, token::intern_and_get_ident("main"));
     let main_attr = ecx.attribute(sp, main_meta);
     // pub fn main() { ... }
     let main_ret_ty = ecx.ty(sp, ast::TyTup(vec![]));
-    let main_body = ecx.block_all(sp, vec![use_as_slice, call_test_main], None);
+    let main_body = ecx.block_all(sp, vec![call_test_main], None);
     let main = ast::ItemFn(ecx.fn_decl(vec![], main_ret_ty),
                            ast::Unsafety::Normal, ::abi::Rust, empty_generics(), main_body);
     let main = P(ast::Item {
diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs
index 084152f107c..1bb038603c3 100644
--- a/src/libterm/lib.rs
+++ b/src/libterm/lib.rs
@@ -50,6 +50,7 @@
        html_playground_url = "http://play.rust-lang.org/")]
 #![deny(missing_docs)]
 
+#![feature(core)]
 #![feature(box_syntax)]
 #![feature(collections)]
 #![feature(int_uint)]
diff --git a/src/libterm/terminfo/mod.rs b/src/libterm/terminfo/mod.rs
index 0a1439ebee0..758191a6e11 100644
--- a/src/libterm/terminfo/mod.rs
+++ b/src/libterm/terminfo/mod.rs
@@ -172,7 +172,7 @@ impl<T: Writer+Send> TerminfoTerminal<T> {
     /// Returns `None` whenever the terminal cannot be created for some
     /// reason.
     pub fn new(out: T) -> Option<Box<Terminal<T>+Send+'static>> {
-        let term = match env::var_string("TERM") {
+        let term = match env::var("TERM") {
             Ok(t) => t,
             Err(..) => {
                 debug!("TERM environment variable not defined");
@@ -182,7 +182,7 @@ impl<T: Writer+Send> TerminfoTerminal<T> {
 
         let entry = open(&term[]);
         if entry.is_err() {
-            if env::var_string("MSYSCON").ok().map_or(false, |s| {
+            if env::var("MSYSCON").ok().map_or(false, |s| {
                     "mintty.exe" == s
                 }) {
                 // msys terminal
diff --git a/src/libterm/terminfo/searcher.rs b/src/libterm/terminfo/searcher.rs
index 6ee477fc808..fd6e6a843e1 100644
--- a/src/libterm/terminfo/searcher.rs
+++ b/src/libterm/terminfo/searcher.rs
@@ -28,14 +28,14 @@ pub fn get_dbpath_for_term(term: &str) -> Option<Box<Path>> {
     let first_char = term.char_at(0);
 
     // Find search directory
-    match env::var_string("TERMINFO") {
+    match env::var("TERMINFO") {
         Ok(dir) => dirs_to_search.push(Path::new(dir)),
         Err(..) => {
             if homedir.is_some() {
                 // ncurses compatibility;
                 dirs_to_search.push(homedir.unwrap().join(".terminfo"))
             }
-            match env::var_string("TERMINFO_DIRS") {
+            match env::var("TERMINFO_DIRS") {
                 Ok(dirs) => for i in dirs.split(':') {
                     if i == "" {
                         dirs_to_search.push(Path::new("/usr/share/terminfo"));
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index f3edd90b4fa..cc468df87f3 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -265,7 +265,8 @@ pub fn test_main(args: &[String], tests: Vec<TestDescAndFn> ) {
 // a ~[TestDescAndFn] is used in order to effect ownership-transfer
 // semantics into parallel test runners, which in turn requires a ~[]
 // rather than a &[].
-pub fn test_main_static(args: &[String], tests: &[TestDescAndFn]) {
+pub fn test_main_static(args: env::Args, tests: &[TestDescAndFn]) {
+    let args = args.collect::<Vec<_>>();
     let owned_tests = tests.iter().map(|t| {
         match t.testfn {
             StaticTestFn(f) => TestDescAndFn { testfn: StaticTestFn(f), desc: t.desc.clone() },
@@ -273,7 +274,7 @@ pub fn test_main_static(args: &[String], tests: &[TestDescAndFn]) {
             _ => panic!("non-static tests passed to test::test_main_static")
         }
     }).collect();
-    test_main(args, owned_tests)
+    test_main(&args, owned_tests)
 }
 
 #[derive(Copy)]
@@ -385,7 +386,7 @@ pub fn parse_opts(args: &[String]) -> Option<OptRes> {
 
     let mut nocapture = matches.opt_present("nocapture");
     if !nocapture {
-        nocapture = env::var("RUST_TEST_NOCAPTURE").is_some();
+        nocapture = env::var("RUST_TEST_NOCAPTURE").is_ok();
     }
 
     let color = match matches.opt_str("color").as_ref().map(|s| &**s) {
@@ -811,7 +812,7 @@ fn run_tests<F>(opts: &TestOpts,
 
 fn get_concurrency() -> uint {
     use std::rt;
-    match env::var_string("RUST_TEST_TASKS") {
+    match env::var("RUST_TEST_TASKS") {
         Ok(s) => {
             let opt_n: Option<uint> = s.parse().ok();
             match opt_n {
diff --git a/src/libunicode/lib.rs b/src/libunicode/lib.rs
index 54c8fcd205b..0ac569b9c8e 100644
--- a/src/libunicode/lib.rs
+++ b/src/libunicode/lib.rs
@@ -60,7 +60,7 @@ mod u_str;
 /// As such, only values in the ranges \[0x0,0xD7FF\] and \[0xE000,0x10FFFF\]
 /// (inclusive) are allowed. A `char` can always be safely cast to a `u32`;
 /// however the converse is not always true due to the above range limits
-/// and, as such, should be performed via the `from_u32` function..
+/// and, as such, should be performed via the `from_u32` function.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub mod char {
     pub use core::char::{MAX, from_u32, from_digit};
diff --git a/src/test/auxiliary/i8.rs b/src/test/auxiliary/i8.rs
new file mode 100644
index 00000000000..44e62b99a96
--- /dev/null
+++ b/src/test/auxiliary/i8.rs
@@ -0,0 +1,13 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// A crate named after a built-in type.
+
+pub struct Test;
diff --git a/src/test/auxiliary/issue-10028.rs b/src/test/auxiliary/issue-10028.rs
index 00fdb3e40b9..a21deb44fcc 100644
--- a/src/test/auxiliary/issue-10028.rs
+++ b/src/test/auxiliary/issue-10028.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(unsafe_no_drop_flag)]
+
 #[unsafe_no_drop_flag]
 pub struct ZeroLengthThingWithDestructor;
 impl Drop for ZeroLengthThingWithDestructor {
diff --git a/src/test/auxiliary/issue-2631-a.rs b/src/test/auxiliary/issue-2631-a.rs
index e340331dbfd..dd1ad413a3d 100644
--- a/src/test/auxiliary/issue-2631-a.rs
+++ b/src/test/auxiliary/issue-2631-a.rs
@@ -19,5 +19,6 @@ pub type header_map = HashMap<String, Rc<RefCell<Vec<Rc<String>>>>>;
 
 // the unused ty param is necessary so this gets monomorphized
 pub fn request<T>(req: &header_map) {
-  let _x = req["METHOD".to_string()].clone().borrow().clone()[0].clone();
+  let data = req["METHOD".to_string()].clone();
+  let _x = data.borrow().clone()[0].clone();
 }
diff --git a/src/test/bench/shootout-k-nucleotide.rs b/src/test/bench/shootout-k-nucleotide.rs
index 474e5464293..74d21687972 100644
--- a/src/test/bench/shootout-k-nucleotide.rs
+++ b/src/test/bench/shootout-k-nucleotide.rs
@@ -295,7 +295,9 @@ fn main() {
         let fd = std::old_io::File::open(&Path::new("shootout-k-nucleotide.data"));
         get_sequence(&mut std::old_io::BufferedReader::new(fd), ">THREE")
     } else {
-        get_sequence(&mut *std::old_io::stdin().lock(), ">THREE")
+        let mut stdin = std::old_io::stdin();
+        let mut stdin = stdin.lock();
+        get_sequence(&mut *stdin, ">THREE")
     };
     let input = Arc::new(input);
 
diff --git a/src/test/bench/sudoku.rs b/src/test/bench/sudoku.rs
index 4a248384e10..c5a64db95e6 100644
--- a/src/test/bench/sudoku.rs
+++ b/src/test/bench/sudoku.rs
@@ -274,7 +274,9 @@ fn main() {
     let mut sudoku = if use_default {
         Sudoku::from_vec(&DEFAULT_SUDOKU)
     } else {
-        Sudoku::read(&mut *old_io::stdin().lock())
+        let mut stdin = old_io::stdin();
+        let mut stdin = stdin.lock();
+        Sudoku::read(&mut *stdin)
     };
     sudoku.solve();
     sudoku.write(&mut old_io::stdout());
diff --git a/src/test/compile-fail/borrowck-partial-reinit-1.rs b/src/test/compile-fail/borrowck-partial-reinit-1.rs
new file mode 100644
index 00000000000..1ee040a0705
--- /dev/null
+++ b/src/test/compile-fail/borrowck-partial-reinit-1.rs
@@ -0,0 +1,49 @@
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Test;
+
+struct Test2 {
+    b: Option<Test>,
+}
+
+struct Test3(Option<Test>);
+
+impl Drop for Test {
+    fn drop(&mut self) {
+        println!("dropping!");
+    }
+}
+
+impl Drop for Test2 {
+    fn drop(&mut self) {}
+}
+
+impl Drop for Test3 {
+    fn drop(&mut self) {}
+}
+
+fn stuff() {
+    let mut t = Test2 { b: None };
+    let u = Test;
+    drop(t);
+    t.b = Some(u);
+    //~^ ERROR partial reinitialization of uninitialized structure `t`
+
+    let mut t = Test3(None);
+    let u = Test;
+    drop(t);
+    t.0 = Some(u);
+    //~^ ERROR partial reinitialization of uninitialized structure `t`
+}
+
+fn main() {
+    stuff()
+}
diff --git a/src/test/compile-fail/borrowck-partial-reinit-2.rs b/src/test/compile-fail/borrowck-partial-reinit-2.rs
new file mode 100644
index 00000000000..0926ba6e432
--- /dev/null
+++ b/src/test/compile-fail/borrowck-partial-reinit-2.rs
@@ -0,0 +1,34 @@
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Test {
+    a: isize,
+    b: Option<Box<Test>>,
+}
+
+impl Drop for Test {
+    fn drop(&mut self) {
+        println!("Dropping {}", self.a);
+    }
+}
+
+fn stuff() {
+    let mut t = Test { a: 1, b: None};
+    let mut u = Test { a: 2, b: Some(Box::new(t))};
+    t.b = Some(Box::new(u));
+    //~^ ERROR partial reinitialization of uninitialized structure `t`
+    println!("done");
+}
+
+fn main() {
+    stuff();
+    println!("Hello, world!")
+}
+
diff --git a/src/test/compile-fail/borrowck-partial-reinit-3.rs b/src/test/compile-fail/borrowck-partial-reinit-3.rs
new file mode 100644
index 00000000000..0aa73892b82
--- /dev/null
+++ b/src/test/compile-fail/borrowck-partial-reinit-3.rs
@@ -0,0 +1,22 @@
+// Copyright 2015 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 std::mem;
+
+struct Test { f: usize }
+impl Drop for Test {
+    fn drop(&mut self) {}
+}
+
+fn main() {
+    let mut x = (Test { f: 2 }, Test { f: 4 });
+    mem::drop(x.0);
+    x.0.f = 3;
+    //~^ ERROR partial reinitialization of uninitialized structure `x.0`
+}
diff --git a/src/test/compile-fail/borrowck-partial-reinit-4.rs b/src/test/compile-fail/borrowck-partial-reinit-4.rs
new file mode 100644
index 00000000000..774e04ecb29
--- /dev/null
+++ b/src/test/compile-fail/borrowck-partial-reinit-4.rs
@@ -0,0 +1,33 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Test;
+
+struct Test2(Option<Test>);
+
+impl Drop for Test {
+    fn drop(&mut self) {
+        println!("dropping!");
+    }
+}
+
+impl Drop for Test2 {
+    fn drop(&mut self) {}
+}
+
+fn stuff() {
+    let mut x : (Test2, Test2);
+    (x.0).0 = Some(Test);
+    //~^ ERROR partial reinitialization of uninitialized structure `x.0`
+}
+
+fn main() {
+    stuff()
+}
diff --git a/src/test/compile-fail/destructor-restrictions.rs b/src/test/compile-fail/destructor-restrictions.rs
new file mode 100644
index 00000000000..0836cd1695d
--- /dev/null
+++ b/src/test/compile-fail/destructor-restrictions.rs
@@ -0,0 +1,21 @@
+// 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.
+
+// Tests the new destructor semantics.
+
+use std::cell::RefCell;
+
+fn main() {
+    let b = {
+        let a = Box::new(RefCell::new(4i8));
+        *a.borrow() + 1i8    //~ ERROR `*a` does not live long enough
+    };
+    println!("{}", b);
+}
diff --git a/src/test/compile-fail/dropck_arr_cycle_checked.rs b/src/test/compile-fail/dropck_arr_cycle_checked.rs
new file mode 100644
index 00000000000..3aa2fae2826
--- /dev/null
+++ b/src/test/compile-fail/dropck_arr_cycle_checked.rs
@@ -0,0 +1,115 @@
+// Copyright 2015 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.
+
+// Reject mixing cyclic structure and Drop when using fixed length
+// arrays.
+//
+// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
+
+#![feature(unsafe_destructor)]
+
+use std::cell::Cell;
+use id::Id;
+
+mod s {
+    #![allow(unstable)]
+    use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+
+    static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+
+    pub fn next_count() -> usize {
+        S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
+    }
+}
+
+mod id {
+    use s;
+    #[derive(Debug)]
+    pub struct Id {
+        orig_count: usize,
+        count: usize,
+    }
+
+    impl Id {
+        pub fn new() -> Id {
+            let c = s::next_count();
+            println!("building Id {}", c);
+            Id { orig_count: c, count: c }
+        }
+        pub fn count(&self) -> usize {
+            println!("Id::count on {} returns {}", self.orig_count, self.count);
+            self.count
+        }
+    }
+
+    impl Drop for Id {
+        fn drop(&mut self) {
+            println!("dropping Id {}", self.count);
+            self.count = 0;
+        }
+    }
+}
+
+trait HasId {
+    fn count(&self) -> usize;
+}
+
+#[derive(Debug)]
+struct CheckId<T:HasId> {
+    v: T
+}
+
+#[allow(non_snake_case)]
+fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
+
+#[unsafe_destructor]
+impl<T:HasId> Drop for CheckId<T> {
+    fn drop(&mut self) {
+        assert!(self.v.count() > 0);
+    }
+}
+
+#[derive(Debug)]
+struct B<'a> {
+    id: Id,
+    a: [CheckId<Cell<Option<&'a B<'a>>>>; 2]
+}
+
+impl<'a> HasId for Cell<Option<&'a B<'a>>> {
+    fn count(&self) -> usize {
+        match self.get() {
+            None => 1,
+            Some(b) => b.id.count(),
+        }
+    }
+}
+
+impl<'a> B<'a> {
+    fn new() -> B<'a> {
+        B { id: Id::new(), a: [CheckId(Cell::new(None)), CheckId(Cell::new(None))] }
+    }
+}
+
+fn f() {
+    let (b1, b2, b3);
+    b1 = B::new();
+    b2 = B::new();
+    b3 = B::new();
+    b1.a[0].v.set(Some(&b2)); //~ ERROR `b2` does not live long enough
+    b1.a[1].v.set(Some(&b3)); //~ ERROR `b3` does not live long enough
+    b2.a[0].v.set(Some(&b2)); //~ ERROR `b2` does not live long enough
+    b2.a[1].v.set(Some(&b3)); //~ ERROR `b3` does not live long enough
+    b3.a[0].v.set(Some(&b1)); //~ ERROR `b1` does not live long enough
+    b3.a[1].v.set(Some(&b2)); //~ ERROR `b2` does not live long enough
+}
+
+fn main() {
+    f();
+}
diff --git a/src/test/compile-fail/dropck_direct_cycle_with_drop.rs b/src/test/compile-fail/dropck_direct_cycle_with_drop.rs
new file mode 100644
index 00000000000..b9df71322ad
--- /dev/null
+++ b/src/test/compile-fail/dropck_direct_cycle_with_drop.rs
@@ -0,0 +1,55 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// A simple example of an unsound mixing of cyclic structure and Drop.
+//
+// Each `D` has a name and an optional reference to another `D`
+// sibling, but also implements a drop method that prints out its own
+// name as well as the name of its sibling.
+//
+// By setting up a cyclic structure, the drop code cannot possibly
+// work. Therefore this code must be rejected.
+//
+// (As it turns out, essentially any attempt to install a sibling here
+//  will be rejected, regardless of whether it forms a cyclic
+//  structure or not. This is because the use of the same lifetime
+//  `'a` in `&'a D<'a>` cannot be satisfied when `D<'a>` implements
+//  `Drop`.)
+
+#![feature(unsafe_destructor)]
+
+use std::cell::Cell;
+
+struct D<'a> {
+    name: String,
+    p: Cell<Option<&'a D<'a>>>,
+}
+
+impl<'a> D<'a> {
+    fn new(name: String) -> D<'a> { D { name: name, p: Cell::new(None) } }
+}
+
+#[unsafe_destructor]
+impl<'a> Drop for D<'a> {
+    fn drop(&mut self) {
+        println!("dropping {} whose sibling is {:?}",
+                 self.name, self.p.get().map(|d| &d.name));
+    }
+}
+
+fn g() {
+    let (d1, d2) = (D::new(format!("d1")), D::new(format!("d2")));
+    d1.p.set(Some(&d2)); //~ ERROR `d2` does not live long enough
+    d2.p.set(Some(&d1)); //~ ERROR `d1` does not live long enough
+}
+
+fn main() {
+    g();
+}
diff --git a/src/test/compile-fail/dropck_tarena_cycle_checked.rs b/src/test/compile-fail/dropck_tarena_cycle_checked.rs
new file mode 100644
index 00000000000..74e3c724b67
--- /dev/null
+++ b/src/test/compile-fail/dropck_tarena_cycle_checked.rs
@@ -0,0 +1,130 @@
+// Copyright 2015 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.
+
+// Reject mixing cyclic structure and Drop when using TypedArena.
+//
+// (Compare against compile-fail/dropck_vec_cycle_checked.rs)
+//
+// (Also compare against compile-fail/dropck_tarena_unsound_drop.rs,
+//  which is a reduction of this code to more directly show the reason
+//  for the error message we see here.)
+
+#![allow(unstable)]
+#![feature(unsafe_destructor)]
+
+extern crate arena;
+
+use arena::TypedArena;
+use std::cell::Cell;
+use id::Id;
+
+mod s {
+    #![allow(unstable)]
+    use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+
+    static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+
+    pub fn next_count() -> usize {
+        S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
+    }
+}
+
+mod id {
+    use s;
+    #[derive(Debug)]
+    pub struct Id {
+        orig_count: usize,
+        count: usize,
+    }
+
+    impl Id {
+        pub fn new() -> Id {
+            let c = s::next_count();
+            println!("building Id {}", c);
+            Id { orig_count: c, count: c }
+        }
+        pub fn count(&self) -> usize {
+            println!("Id::count on {} returns {}", self.orig_count, self.count);
+            self.count
+        }
+    }
+
+    impl Drop for Id {
+        fn drop(&mut self) {
+            println!("dropping Id {}", self.count);
+            self.count = 0;
+        }
+    }
+}
+
+trait HasId {
+    fn count(&self) -> usize;
+}
+
+#[derive(Debug)]
+struct CheckId<T:HasId> {
+    v: T
+}
+
+#[allow(non_snake_case)]
+fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
+
+#[unsafe_destructor]
+impl<T:HasId> Drop for CheckId<T> {
+    fn drop(&mut self) {
+        assert!(self.v.count() > 0);
+    }
+}
+
+#[derive(Debug)]
+struct C<'a> {
+    id: Id,
+    v: Vec<CheckId<Cell<Option<&'a C<'a>>>>>,
+}
+
+impl<'a> HasId for Cell<Option<&'a C<'a>>> {
+    fn count(&self) -> usize {
+        match self.get() {
+            None => 1,
+            Some(c) => c.id.count(),
+        }
+    }
+}
+
+impl<'a> C<'a> {
+    fn new() -> C<'a> {
+        C { id: Id::new(), v: Vec::new() }
+    }
+}
+
+fn f<'a>(arena: &'a TypedArena<C<'a>>) {
+    let c1 = arena.alloc(C::new());
+    let c2 = arena.alloc(C::new());
+    let c3 = arena.alloc(C::new());
+
+    c1.v.push(CheckId(Cell::new(None)));
+    c1.v.push(CheckId(Cell::new(None)));
+    c2.v.push(CheckId(Cell::new(None)));
+    c2.v.push(CheckId(Cell::new(None)));
+    c3.v.push(CheckId(Cell::new(None)));
+    c3.v.push(CheckId(Cell::new(None)));
+
+    c1.v[0].v.set(Some(c2));
+    c1.v[1].v.set(Some(c3));
+    c2.v[0].v.set(Some(c2));
+    c2.v[1].v.set(Some(c3));
+    c3.v[0].v.set(Some(c1));
+    c3.v[1].v.set(Some(c2));
+}
+
+fn main() {
+    let arena = TypedArena::new();
+    f(&arena); //~ ERROR `arena` does not live long enough
+}
diff --git a/src/test/compile-fail/dropck_tarena_unsound_drop.rs b/src/test/compile-fail/dropck_tarena_unsound_drop.rs
new file mode 100644
index 00000000000..64d77e97fa7
--- /dev/null
+++ b/src/test/compile-fail/dropck_tarena_unsound_drop.rs
@@ -0,0 +1,54 @@
+// Copyright 2015 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.
+
+// Check that a arena (TypedArena) cannot carry elements whose drop
+// methods might access borrowed data of lifetime that does not
+// strictly outlive the arena itself.
+//
+// Compare against run-pass/dropck_tarena_sound_drop.rs, which shows a
+// similar setup, but loosens `f` so that the struct `C<'a>` can be
+// fed a lifetime longer than that of the arena.
+//
+// (Also compare against dropck_tarena_cycle_checked.rs, from which
+// this was reduced to better understand its error message.)
+
+#![allow(unstable)]
+#![feature(unsafe_destructor)]
+
+extern crate arena;
+
+use arena::TypedArena;
+
+trait HasId { fn count(&self) -> usize; }
+
+struct CheckId<T:HasId> { v: T }
+
+// In the code below, the impl of HasId for `&'a usize` does not
+// actually access the borrowed data, but the point is that the
+// interface to CheckId does not (and cannot) know that, and therefore
+// when encountering the a value V of type CheckId<S>, we must
+// conservatively force the type S to strictly outlive V.
+#[unsafe_destructor]
+impl<T:HasId> Drop for CheckId<T> {
+    fn drop(&mut self) {
+        assert!(self.v.count() > 0);
+    }
+}
+
+struct C<'a> { v: CheckId<&'a usize>, }
+
+impl<'a> HasId for &'a usize { fn count(&self) -> usize { 1 } }
+
+fn f<'a>(_arena: &'a TypedArena<C<'a>>) {}
+
+fn main() {
+    let arena: TypedArena<C> = TypedArena::new();
+    f(&arena); //~ ERROR `arena` does not live long enough
+}
diff --git a/src/test/compile-fail/dropck_vec_cycle_checked.rs b/src/test/compile-fail/dropck_vec_cycle_checked.rs
new file mode 100644
index 00000000000..3f69c7d1a9c
--- /dev/null
+++ b/src/test/compile-fail/dropck_vec_cycle_checked.rs
@@ -0,0 +1,122 @@
+// Copyright 2015 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.
+
+// Reject mixing cyclic structure and Drop when using Vec.
+//
+// (Compare against compile-fail/dropck_arr_cycle_checked.rs)
+
+#![feature(unsafe_destructor)]
+
+use std::cell::Cell;
+use id::Id;
+
+mod s {
+    #![allow(unstable)]
+    use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+
+    static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+
+    pub fn next_count() -> usize {
+        S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
+    }
+}
+
+mod id {
+    use s;
+    #[derive(Debug)]
+    pub struct Id {
+        orig_count: usize,
+        count: usize,
+    }
+
+    impl Id {
+        pub fn new() -> Id {
+            let c = s::next_count();
+            println!("building Id {}", c);
+            Id { orig_count: c, count: c }
+        }
+        pub fn count(&self) -> usize {
+            println!("Id::count on {} returns {}", self.orig_count, self.count);
+            self.count
+        }
+    }
+
+    impl Drop for Id {
+        fn drop(&mut self) {
+            println!("dropping Id {}", self.count);
+            self.count = 0;
+        }
+    }
+}
+
+trait HasId {
+    fn count(&self) -> usize;
+}
+
+#[derive(Debug)]
+struct CheckId<T:HasId> {
+    v: T
+}
+
+#[allow(non_snake_case)]
+fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
+
+#[unsafe_destructor]
+impl<T:HasId> Drop for CheckId<T> {
+    fn drop(&mut self) {
+        assert!(self.v.count() > 0);
+    }
+}
+
+#[derive(Debug)]
+struct C<'a> {
+    id: Id,
+    v: Vec<CheckId<Cell<Option<&'a C<'a>>>>>,
+}
+
+impl<'a> HasId for Cell<Option<&'a C<'a>>> {
+    fn count(&self) -> usize {
+        match self.get() {
+            None => 1,
+            Some(c) => c.id.count(),
+        }
+    }
+}
+
+impl<'a> C<'a> {
+    fn new() -> C<'a> {
+        C { id: Id::new(), v: Vec::new() }
+    }
+}
+
+fn f() {
+    let (mut c1, mut c2, mut c3);
+    c1 = C::new();
+    c2 = C::new();
+    c3 = C::new();
+
+    c1.v.push(CheckId(Cell::new(None)));
+    c1.v.push(CheckId(Cell::new(None)));
+    c2.v.push(CheckId(Cell::new(None)));
+    c2.v.push(CheckId(Cell::new(None)));
+    c3.v.push(CheckId(Cell::new(None)));
+    c3.v.push(CheckId(Cell::new(None)));
+
+    c1.v[0].v.set(Some(&c2)); //~ ERROR `c2` does not live long enough
+    c1.v[1].v.set(Some(&c3)); //~ ERROR `c3` does not live long enough
+    c2.v[0].v.set(Some(&c2)); //~ ERROR `c2` does not live long enough
+    c2.v[1].v.set(Some(&c3)); //~ ERROR `c3` does not live long enough
+    c3.v[0].v.set(Some(&c1)); //~ ERROR `c1` does not live long enough
+    c3.v[1].v.set(Some(&c2)); //~ ERROR `c2` does not live long enough
+}
+
+fn main() {
+    f();
+}
diff --git a/src/test/compile-fail/feature-gate-simd-ffi.rs b/src/test/compile-fail/feature-gate-simd-ffi.rs
index 409c85b7198..9ee3fcee023 100644
--- a/src/test/compile-fail/feature-gate-simd-ffi.rs
+++ b/src/test/compile-fail/feature-gate-simd-ffi.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(simd)]
+#![feature(simd, core)]
 #![allow(dead_code)]
 
 use std::simd::f32x4;
diff --git a/src/test/compile-fail/issue-20427.rs b/src/test/compile-fail/issue-20427.rs
new file mode 100644
index 00000000000..96d4fae8b03
--- /dev/null
+++ b/src/test/compile-fail/issue-20427.rs
@@ -0,0 +1,66 @@
+// Copyright 2015 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.
+
+// aux-build:i8.rs
+extern crate i8;
+use std::string as i16;
+static i32: i32 = 0;
+const i64: i64 = 0;
+fn u8(f32: f32) {}
+fn f<f64>(f64: f64) {}
+//~^ ERROR user-defined types or type parameters cannot shadow the primitive types
+type u16 = u16; //~ ERROR user-defined types or type parameters cannot shadow the primitive types
+enum u32 {} //~ ERROR user-defined types or type parameters cannot shadow the primitive types
+struct u64; //~ ERROR user-defined types or type parameters cannot shadow the primitive types
+trait bool {} //~ ERROR user-defined types or type parameters cannot shadow the primitive types
+
+mod char {
+    extern crate i8;
+    static i32_: i32 = 0;
+    const i64_: i64 = 0;
+    fn u8_(f32: f32) {}
+    fn f_<f64_>(f64: f64_) {}
+    type u16_ = u16;
+    enum u32_ {}
+    struct u64_;
+    trait bool_ {}
+    mod char_ {}
+
+    mod str {
+        use super::i8 as i8;
+        use super::i32_ as i32;
+        use super::i64_ as i64;
+        use super::u8_ as u8;
+        use super::f_ as f64;
+        use super::u16_ as u16;
+        //~^ ERROR user-defined types or type parameters cannot shadow the primitive types
+        use super::u32_ as u32;
+        //~^ ERROR user-defined types or type parameters cannot shadow the primitive types
+        use super::u64_ as u64;
+        //~^ ERROR user-defined types or type parameters cannot shadow the primitive types
+        use super::bool_ as bool;
+        //~^ ERROR user-defined types or type parameters cannot shadow the primitive types
+        use super::char_ as char;
+    }
+}
+
+trait isize_ {
+    type isize; //~ ERROR user-defined types or type parameters cannot shadow the primitive types
+}
+
+fn usize<'usize>(usize: &'usize usize) -> &'usize usize { usize }
+
+fn main() {
+    let bool = true;
+    match bool {
+        str @ true => if str { i32 as i64 } else { 0 },
+        false => i64,
+    }
+}
diff --git a/src/test/compile-fail/lint-stability.rs b/src/test/compile-fail/lint-stability.rs
index 4cf75bf15de..5c187176fb2 100644
--- a/src/test/compile-fail/lint-stability.rs
+++ b/src/test/compile-fail/lint-stability.rs
@@ -98,12 +98,10 @@ mod cross_crate {
         // Eventually, we will want to lint the contents of the
         // macro in the module *defining* it. Also, stability levels
         // on macros themselves are not yet linted.
-        macro_test!();
         macro_test_arg!(deprecated_text()); //~ ERROR use of deprecated item: text
         macro_test_arg!(deprecated_unstable_text()); //~ ERROR use of deprecated item: text
         //~^ WARNING use of unstable library feature
         macro_test_arg!(macro_test_arg!(deprecated_text())); //~ ERROR use of deprecated item: text
-        macro_test_arg_nested!(deprecated_text);
     }
 
     fn test_method_param<F: Trait>(foo: F) {
@@ -139,7 +137,7 @@ mod cross_crate {
 
 mod inheritance {
     extern crate inherited_stability; //~ WARNING: use of unstable library feature
-    use self::inherited_stability::*;
+    use self::inherited_stability::*; //~ WARNING: use of unstable library feature
 
     fn test_inheritance() {
         unstable(); //~ WARNING use of unstable library feature
diff --git a/src/test/compile-fail/lint-stability2.rs b/src/test/compile-fail/lint-stability2.rs
new file mode 100644
index 00000000000..d2ec00d6495
--- /dev/null
+++ b/src/test/compile-fail/lint-stability2.rs
@@ -0,0 +1,23 @@
+// Copyright 2015 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.
+
+// aux-build:lint_stability.rs
+// error-pattern: use of deprecated item
+
+#![deny(deprecated)]
+
+#[macro_use]
+extern crate lint_stability;
+
+use lint_stability::*;
+
+fn main() {
+    macro_test!();
+}
diff --git a/src/test/compile-fail/lint-stability3.rs b/src/test/compile-fail/lint-stability3.rs
new file mode 100644
index 00000000000..88a93134b47
--- /dev/null
+++ b/src/test/compile-fail/lint-stability3.rs
@@ -0,0 +1,25 @@
+// Copyright 2015 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.
+
+// aux-build:lint_stability.rs
+// error-pattern: use of deprecated item
+
+#![deny(deprecated)]
+#![allow(warnings)]
+
+#[macro_use]
+extern crate lint_stability;
+
+use lint_stability::*;
+
+fn main() {
+    macro_test_arg_nested!(deprecated_text);
+}
+
diff --git a/src/test/compile-fail/lint-unexported-no-mangle.rs b/src/test/compile-fail/lint-unexported-no-mangle.rs
index 3227a78c2ef..216fcf93535 100644
--- a/src/test/compile-fail/lint-unexported-no-mangle.rs
+++ b/src/test/compile-fail/lint-unexported-no-mangle.rs
@@ -8,17 +8,32 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// compile-flags:-F private_no_mangle_fns
+// compile-flags:-F private_no_mangle_fns -F no_mangle_const_items -F private_no_mangle_statics
 
 // FIXME(#19495) no_mangle'ing main ICE's.
 #[no_mangle]
 fn foo() { //~ ERROR function foo is marked #[no_mangle], but not exported
 }
 
+#[allow(dead_code)]
+#[no_mangle]
+const FOO: u64 = 1; //~ ERROR const items should never be #[no_mangle]
+
+#[no_mangle]
+pub const PUB_FOO: u64 = 1; //~ ERROR const items should never be #[no_mangle]
+
 #[no_mangle]
 pub fn bar()  {
 }
 
+#[no_mangle]
+pub static BAR: u64 = 1;
+
+#[allow(dead_code)]
+#[no_mangle]
+static PRIVATE_BAR: u64 = 1; //~ ERROR static PRIVATE_BAR is marked #[no_mangle], but not exported
+
+
 fn main() {
     foo();
     bar();
diff --git a/src/test/compile-fail/macro-reexport-undef.rs b/src/test/compile-fail/macro-reexport-undef.rs
new file mode 100644
index 00000000000..e9b3ceff83d
--- /dev/null
+++ b/src/test/compile-fail/macro-reexport-undef.rs
@@ -0,0 +1,20 @@
+// Copyright 2015 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.
+
+// aux-build:two_macros.rs
+// ignore-stage1
+
+#[macro_use(macro_two)]
+#[macro_reexport(no_way)] //~ ERROR reexported macro not found
+extern crate two_macros;
+
+pub fn main() {
+    macro_two!();
+}
diff --git a/src/test/compile-fail/macro-use-undef.rs b/src/test/compile-fail/macro-use-undef.rs
new file mode 100644
index 00000000000..a5a350bd30e
--- /dev/null
+++ b/src/test/compile-fail/macro-use-undef.rs
@@ -0,0 +1,19 @@
+// Copyright 2015 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.
+
+// aux-build:two_macros.rs
+// ignore-stage1
+
+#[macro_use(macro_two, no_way)] //~ ERROR imported macro not found
+extern crate two_macros;
+
+pub fn main() {
+    macro_two!();
+}
diff --git a/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs b/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs
new file mode 100644
index 00000000000..6aaf51278af
--- /dev/null
+++ b/src/test/compile-fail/vec-must-not-hide-type-from-dropck.rs
@@ -0,0 +1,135 @@
+// Copyright 2015 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.
+
+// Checking that `Vec<T>` cannot hide lifetimes within `T` when `T`
+// implements `Drop` and might access methods of values that have
+// since been deallocated.
+//
+// In this case, the values in question hold (non-zero) unique-ids
+// that zero themselves out when dropped, and are wrapped in another
+// type with a destructor that asserts that the ids it references are
+// indeed non-zero (i.e., effectively checking that the id's are not
+// dropped while there are still any outstanding references).
+//
+// However, the values in question are also formed into a
+// cyclic-structure, ensuring that there is no way for all of the
+// conditions above to be satisfied, meaning that if the dropck is
+// sound, it should reject this code.
+
+#![feature(unsafe_destructor)]
+
+use std::cell::Cell;
+use id::Id;
+
+mod s {
+    #![allow(unstable)]
+    use std::sync::atomic::{AtomicUint, ATOMIC_UINT_INIT, Ordering};
+
+    static S_COUNT: AtomicUint = ATOMIC_UINT_INIT;
+
+    /// generates globally unique count (global across the current
+    /// process, that is)
+    pub fn next_count() -> usize {
+        S_COUNT.fetch_add(1, Ordering::SeqCst) + 1
+    }
+}
+
+mod id {
+    use s;
+
+    /// Id represents a globally unique identifier (global across the
+    /// current process, that is). When dropped, it automatically
+    /// clears its `count` field, but leaves `orig_count` untouched,
+    /// so that if there are subsequent (erroneous) invocations of its
+    /// method (which is unsound), we can observe it by seeing that
+    /// the `count` is 0 while the `orig_count` is non-zero.
+    #[derive(Debug)]
+    pub struct Id {
+        orig_count: usize,
+        count: usize,
+    }
+
+    impl Id {
+        /// Creates an `Id` with a globally unique count.
+        pub fn new() -> Id {
+            let c = s::next_count();
+            println!("building Id {}", c);
+            Id { orig_count: c, count: c }
+        }
+        /// returns the `count` of self; should be non-zero if
+        /// everything is working.
+        pub fn count(&self) -> usize {
+            println!("Id::count on {} returns {}", self.orig_count, self.count);
+            self.count
+        }
+    }
+
+    impl Drop for Id {
+        fn drop(&mut self) {
+            println!("dropping Id {}", self.count);
+            self.count = 0;
+        }
+    }
+}
+
+trait HasId {
+    fn count(&self) -> usize;
+}
+
+#[derive(Debug)]
+struct CheckId<T:HasId> {
+    v: T
+}
+
+#[allow(non_snake_case)]
+fn CheckId<T:HasId>(t: T) -> CheckId<T> { CheckId{ v: t } }
+
+#[unsafe_destructor]
+impl<T:HasId> Drop for CheckId<T> {
+    fn drop(&mut self) {
+        assert!(self.v.count() > 0);
+    }
+}
+
+#[derive(Debug)]
+struct C<'a> {
+    id: Id,
+    v: Vec<CheckId<Cell<Option<&'a C<'a>>>>>,
+}
+
+impl<'a> HasId for Cell<Option<&'a C<'a>>> {
+    fn count(&self) -> usize {
+        match self.get() {
+            None => 1,
+            Some(c) => c.id.count(),
+        }
+    }
+}
+
+impl<'a> C<'a> {
+    fn new() -> C<'a> {
+        C { id: Id::new(), v: Vec::new() }
+    }
+}
+
+fn f() {
+    let (mut c1, mut c2);
+    c1 = C::new();
+    c2 = C::new();
+
+    c1.v.push(CheckId(Cell::new(None)));
+    c2.v.push(CheckId(Cell::new(None)));
+    c1.v[0].v.set(Some(&c2)); //~ ERROR `c2` does not live long enough
+    c2.v[0].v.set(Some(&c1)); //~ ERROR `c1` does not live long enough
+}
+
+fn main() {
+    f();
+}
diff --git a/src/test/compile-fail/vec_refs_data_with_early_death.rs b/src/test/compile-fail/vec_refs_data_with_early_death.rs
new file mode 100644
index 00000000000..a191b3e56c4
--- /dev/null
+++ b/src/test/compile-fail/vec_refs_data_with_early_death.rs
@@ -0,0 +1,31 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test is a simple example of code that violates the dropck
+// rules: it pushes `&x` and `&y` into `v`, but the referenced data
+// will be dropped before the vector itself is.
+
+// (In principle we know that `Vec` does not reference the data it
+//  owns from within its drop code, apart from calling drop on each
+//  element it owns; thus, for data like this, it seems like we could
+//  loosen the restrictions here if we wanted. But it also is not
+//  clear whether such loosening is terribly important.)
+
+fn main() {
+    let mut v = Vec::new();
+
+    let x: i8 = 3;
+    let y: i8 = 4;
+
+    v.push(&x); //~ ERROR `x` does not live long enough
+    v.push(&y); //~ ERROR `y` does not live long enough
+
+    assert_eq!(v.as_slice(), [&3, &4]);
+}
diff --git a/src/test/run-make/empty-file/Makefile b/src/test/run-make/empty-file/Makefile
deleted file mode 100644
index f55a2cc3bb1..00000000000
--- a/src/test/run-make/empty-file/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
--include ../tools.mk
-
-all:
-	$(RUSTC) --emit=asm,llvm-bc,llvm-ir,obj,dep-info empty.rs
-	$(RUSTC) --emit=link --crate-type=rlib,dylib,staticlib empty.rs
diff --git a/src/test/run-make/empty-file/empty.rs b/src/test/run-make/empty-file/empty.rs
deleted file mode 100644
index e69de29bb2d..00000000000
--- a/src/test/run-make/empty-file/empty.rs
+++ /dev/null
diff --git a/src/test/run-pass/arr_cycle.rs b/src/test/run-pass/arr_cycle.rs
new file mode 100644
index 00000000000..80434f36b42
--- /dev/null
+++ b/src/test/run-pass/arr_cycle.rs
@@ -0,0 +1,39 @@
+// Copyright 2015 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 std::cell::Cell;
+
+#[derive(Show)]
+struct B<'a> {
+    a: [Cell<Option<&'a B<'a>>>; 2]
+}
+
+impl<'a> B<'a> {
+    fn new() -> B<'a> {
+        B { a: [Cell::new(None), Cell::new(None)] }
+    }
+}
+
+fn f() {
+    let (b1, b2, b3);
+    b1 = B::new();
+    b2 = B::new();
+    b3 = B::new();
+    b1.a[0].set(Some(&b2));
+    b1.a[1].set(Some(&b3));
+    b2.a[0].set(Some(&b2));
+    b2.a[1].set(Some(&b3));
+    b3.a[0].set(Some(&b1));
+    b3.a[1].set(Some(&b2));
+}
+
+fn main() {
+    f();
+}
diff --git a/src/test/run-pass/associated-types-issue-20220.rs b/src/test/run-pass/associated-types-issue-20220.rs
new file mode 100644
index 00000000000..a253fbde563
--- /dev/null
+++ b/src/test/run-pass/associated-types-issue-20220.rs
@@ -0,0 +1,36 @@
+// Copyright 2015 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.
+
+// Test references to `Self::Item` in the trait. Issue #20220.
+
+use std::vec;
+
+trait IntoIteratorX {
+    type Item;
+    type IntoIter: Iterator<Item=Self::Item>;
+
+    fn into_iter_x(self) -> Self::IntoIter;
+}
+
+impl<T> IntoIteratorX for Vec<T> {
+    type Item = T;
+    type IntoIter = vec::IntoIter<T>;
+
+    fn into_iter_x(self) -> vec::IntoIter<T> {
+        self.into_iter()
+    }
+}
+
+fn main() {
+    let vec = vec![1, 2, 3];
+    for (i, e) in vec.into_iter().enumerate() {
+        assert_eq!(i+1, e);
+    }
+}
diff --git a/src/test/run-pass/associated-types-stream.rs b/src/test/run-pass/associated-types-stream.rs
new file mode 100644
index 00000000000..ef7fbe87b30
--- /dev/null
+++ b/src/test/run-pass/associated-types-stream.rs
@@ -0,0 +1,47 @@
+// Copyright 2015 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.
+
+// Test references to the trait `Stream` in the bounds for associated
+// types defined on `Stream`. Issue #20551.
+
+trait Stream {
+    type Car;
+    type Cdr: Stream;
+
+    fn car(&self) -> Self::Car;
+    fn cdr(self) -> Self::Cdr;
+}
+
+impl Stream for () {
+    type Car = ();
+    type Cdr = ();
+    fn car(&self) -> () { () }
+    fn cdr(self) -> () { self }
+}
+
+impl<T,U> Stream for (T, U)
+    where T : Clone, U : Stream
+{
+    type Car = T;
+    type Cdr = U;
+    fn car(&self) -> T { self.0.clone() }
+    fn cdr(self) -> U { self.1 }
+}
+
+fn main() {
+    let p = (22, (44, (66, ())));
+    assert_eq!(p.car(), 22);
+
+    let p = p.cdr();
+    assert_eq!(p.car(), 44);
+
+    let p = p.cdr();
+    assert_eq!(p.car(), 66);
+}
diff --git a/src/test/run-pass/astconv-cycle-between-trait-and-type.rs b/src/test/run-pass/astconv-cycle-between-trait-and-type.rs
new file mode 100644
index 00000000000..0c6d91eda26
--- /dev/null
+++ b/src/test/run-pass/astconv-cycle-between-trait-and-type.rs
@@ -0,0 +1,36 @@
+// Copyright 2015 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.
+
+// Test that we are able to successfully compile a setup where a trait
+// (`Trait1`) references a struct (`SomeType<u32>`) which in turn
+// carries a predicate that references the trait (`u32 : Trait1`,
+// substituted).
+
+#![allow(dead_code)]
+
+trait Trait1 : Trait2<SomeType<u32>> {
+    fn dumb(&self) { }
+}
+
+trait Trait2<A> {
+    fn dumber(&self, _: A) { }
+}
+
+struct SomeType<A>
+    where A : Trait1
+{
+    a: A
+}
+
+impl Trait1 for u32 { }
+
+impl Trait2<SomeType<u32>> for u32 { }
+
+fn main() { }
diff --git a/src/test/run-pass/attr-no-drop-flag-size.rs b/src/test/run-pass/attr-no-drop-flag-size.rs
index b3fb1627900..bd799917842 100644
--- a/src/test/run-pass/attr-no-drop-flag-size.rs
+++ b/src/test/run-pass/attr-no-drop-flag-size.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 #![feature(unsafe_destructor)]
+#![feature(unsafe_no_drop_flag)]
 
 use std::mem::size_of;
 
diff --git a/src/test/run-pass/dropck_tarena_sound_drop.rs b/src/test/run-pass/dropck_tarena_sound_drop.rs
new file mode 100644
index 00000000000..ad71f725864
--- /dev/null
+++ b/src/test/run-pass/dropck_tarena_sound_drop.rs
@@ -0,0 +1,51 @@
+// Copyright 2015 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.
+
+// Check that a arena (TypedArena) can carry elements whose drop
+// methods might access borrowed data, as long as the borrowed data
+// has lifetime that strictly outlives the arena itself.
+//
+// Compare against compile-fail/dropck_tarena_unsound_drop.rs, which
+// shows a similar setup, but restricts `f` so that the struct `C<'a>`
+// is force-fed a lifetime equal to that of the borrowed arena.
+
+#![allow(unstable)]
+#![feature(unsafe_destructor)]
+
+extern crate arena;
+
+use arena::TypedArena;
+
+trait HasId { fn count(&self) -> usize; }
+
+struct CheckId<T:HasId> { v: T }
+
+// In the code below, the impl of HasId for `&'a usize` does not
+// actually access the borrowed data, but the point is that the
+// interface to CheckId does not (and cannot) know that, and therefore
+// when encountering the a value V of type CheckId<S>, we must
+// conservatively force the type S to strictly outlive V.
+#[unsafe_destructor]
+impl<T:HasId> Drop for CheckId<T> {
+    fn drop(&mut self) {
+        assert!(self.v.count() > 0);
+    }
+}
+
+struct C<'a> { _v: CheckId<&'a usize>, }
+
+impl<'a> HasId for &'a usize { fn count(&self) -> usize { 1 } }
+
+fn f<'a, 'b>(_arena: &'a TypedArena<C<'b>>) {}
+
+fn main() {
+    let arena: TypedArena<C> = TypedArena::new();
+    f(&arena);
+}
diff --git a/src/test/run-pass/env-vars.rs b/src/test/run-pass/env-vars.rs
index 892041b9648..659e5b3a8c2 100644
--- a/src/test/run-pass/env-vars.rs
+++ b/src/test/run-pass/env-vars.rs
@@ -11,8 +11,8 @@
 use std::env::*;
 
 fn main() {
-    for (k, v) in vars() {
-        let v2 = var(&k);
+    for (k, v) in vars_os() {
+        let v2 = var_os(&k);
         // MingW seems to set some funky environment variables like
         // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
         // from vars() but not visible from var().
diff --git a/src/test/run-pass/issue-10734.rs b/src/test/run-pass/issue-10734.rs
index 1c267f48337..a6af2327c9e 100644
--- a/src/test/run-pass/issue-10734.rs
+++ b/src/test/run-pass/issue-10734.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(unsafe_no_drop_flag)]
+
 static mut drop_count: uint = 0;
 
 #[unsafe_no_drop_flag]
diff --git a/src/test/run-pass/issue-13304.rs b/src/test/run-pass/issue-13304.rs
index f979235da71..4dc824d9068 100644
--- a/src/test/run-pass/issue-13304.rs
+++ b/src/test/run-pass/issue-13304.rs
@@ -37,7 +37,8 @@ fn parent() {
 }
 
 fn child() {
-    for line in old_io::stdin().lock().lines() {
+    let mut stdin = old_io::stdin();
+    for line in stdin.lock().lines() {
         println!("{}", line.unwrap());
     }
 }
diff --git a/src/test/run-pass/issue-14456.rs b/src/test/run-pass/issue-14456.rs
index 5f44eb7dcd2..1c8066bc3c9 100644
--- a/src/test/run-pass/issue-14456.rs
+++ b/src/test/run-pass/issue-14456.rs
@@ -27,7 +27,8 @@ fn main() {
 fn child() {
     old_io::stdout().write_line("foo").unwrap();
     old_io::stderr().write_line("bar").unwrap();
-    assert_eq!(old_io::stdin().lock().read_line().err().unwrap().kind, old_io::EndOfFile);
+    let mut stdin = old_io::stdin();
+    assert_eq!(stdin.lock().read_line().err().unwrap().kind, old_io::EndOfFile);
 }
 
 fn test() {
diff --git a/src/test/run-pass/issue-20343.rs b/src/test/run-pass/issue-20343.rs
new file mode 100644
index 00000000000..79034a4a4a6
--- /dev/null
+++ b/src/test/run-pass/issue-20343.rs
@@ -0,0 +1,38 @@
+// Copyright 2015 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.
+
+// Regression test for Issue #20343.
+
+#![deny(dead_code)]
+
+struct B { b: u32 }
+struct C;
+struct D;
+
+trait T<A> {}
+impl<A> T<A> for () {}
+
+impl B {
+    // test for unused code in arguments
+    fn foo(B { b }: B) -> u32 { b }
+
+    // test for unused code in return type
+    fn bar() -> C { unsafe { ::std::mem::transmute(()) } }
+
+    // test for unused code in generics
+    fn baz<A: T<D>>() {}
+}
+
+pub fn main() {
+    let b = B { b: 3 };
+    B::foo(b);
+    B::bar();
+    B::baz::<()>();
+}
diff --git a/src/test/run-pass/issue-22036.rs b/src/test/run-pass/issue-22036.rs
new file mode 100644
index 00000000000..c06a29c09f7
--- /dev/null
+++ b/src/test/run-pass/issue-22036.rs
@@ -0,0 +1,33 @@
+// Copyright 2015 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.
+
+trait DigitCollection: Sized {
+    type Iter: Iterator<Item = u8>;
+    fn digit_iter(self) -> Self::Iter;
+
+    fn digit_sum(self) -> u32 {
+        self.digit_iter()
+            .map(|digit: u8| digit as u32)
+            .fold(0, |sum, digit| sum + digit)
+    }
+}
+
+impl<I> DigitCollection for I where I: Iterator<Item=u8> {
+    type Iter = I;
+
+    fn digit_iter(self) -> I {
+        self
+    }
+}
+
+fn main() {
+    let xs = vec![1u8, 2, 3, 4, 5];
+    assert_eq!(xs.into_iter().digit_sum(), 15);
+}
diff --git a/src/test/run-pass/multidispatch-conditional-impl-not-considered.rs b/src/test/run-pass/multidispatch-conditional-impl-not-considered.rs
index 5db5a6267bf..49ecef9c735 100644
--- a/src/test/run-pass/multidispatch-conditional-impl-not-considered.rs
+++ b/src/test/run-pass/multidispatch-conditional-impl-not-considered.rs
@@ -29,5 +29,5 @@ impl Bar {
 
 fn main() {
     let b = RefCell::new(Bar);
-    b.borrow().foo()
+    b.borrow().foo();
 }
diff --git a/src/test/run-pass/nondrop-cycle.rs b/src/test/run-pass/nondrop-cycle.rs
new file mode 100644
index 00000000000..bbce9a8f4a6
--- /dev/null
+++ b/src/test/run-pass/nondrop-cycle.rs
@@ -0,0 +1,38 @@
+// Copyright 2015 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 std::cell::Cell;
+
+struct C<'a> {
+    p: Cell<Option<&'a C<'a>>>,
+}
+
+impl<'a> C<'a> {
+    fn new() -> C<'a> { C { p: Cell::new(None) } }
+}
+
+fn f1() {
+    let (c1, c2) = (C::new(), C::new());
+    c1.p.set(Some(&c2));
+    c2.p.set(Some(&c1));
+}
+
+fn f2() {
+    let (c1, c2);
+    c1 = C::new();
+    c2 = C::new();
+    c1.p.set(Some(&c2));
+    c2.p.set(Some(&c1));
+}
+
+fn main() {
+    f1();
+    f2();
+}
diff --git a/src/test/run-pass/overloaded-autoderef.rs b/src/test/run-pass/overloaded-autoderef.rs
index fcf0feb6e30..faa79f71d9e 100644
--- a/src/test/run-pass/overloaded-autoderef.rs
+++ b/src/test/run-pass/overloaded-autoderef.rs
@@ -22,8 +22,9 @@ struct Point {
 }
 
 pub fn main() {
+    let box_5 = box 5u;
     assert_eq!(Rc::new(5u).to_uint(), Some(5));
-    assert_eq!((box &box &Rc::new(box box &box 5u)).to_uint(), Some(5));
+    assert_eq!((box &box &Rc::new(box box &box_5)).to_uint(), Some(5));
     let point = Rc::new(Point {x: 2, y: 4});
     assert_eq!(point.x, 2);
     assert_eq!(point.y, 4);
diff --git a/src/test/run-pass/regions-refcell.rs b/src/test/run-pass/regions-refcell.rs
new file mode 100644
index 00000000000..019db2a977e
--- /dev/null
+++ b/src/test/run-pass/regions-refcell.rs
@@ -0,0 +1,53 @@
+// 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.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This is a regression test for something that only came up while
+// attempting to bootstrap librustc with new destructor lifetime
+// semantics.
+
+use std::collections::HashMap;
+use std::cell::RefCell;
+
+// This version does not yet work (associated type issues)...
+#[cfg(cannot_use_this_yet)]
+fn foo<'a>(map: RefCell<HashMap<&'static str, &'a [u8]>>) {
+    let one = [1u];
+    assert_eq!(map.borrow().get("one"), Some(&one[]));
+}
+
+#[cfg(cannot_use_this_yet_either)]
+// ... and this version does not work (the lifetime of `one` is
+// supposed to match the lifetime `'a`) ...
+fn foo<'a>(map: RefCell<HashMap<&'static str, &'a [u8]>>) {
+    let one = [1u];
+    assert_eq!(map.borrow().get("one"), Some(&one.as_slice()));
+}
+
+#[cfg(all(not(cannot_use_this_yet),not(cannot_use_this_yet_either)))]
+fn foo<'a>(map: RefCell<HashMap<&'static str, &'a [u8]>>) {
+    // ...so instead we walk through the trivial slice and make sure
+    // it contains the element we expect.
+
+    for (i, &x) in map.borrow().get("one").unwrap().iter().enumerate() {
+        assert_eq!((i, x), (0, 1));
+    }
+}
+
+fn main() {
+    let zer = [0u8];
+    let one = [1u8];
+    let two = [2u8];
+    let mut map = HashMap::new();
+    map.insert("zero", &zer[]);
+    map.insert("one",  &one[]);
+    map.insert("two",  &two[]);
+    let map = RefCell::new(map);
+    foo(map);
+}
diff --git a/src/test/run-pass/regions-trait-object-1.rs b/src/test/run-pass/regions-trait-object-1.rs
new file mode 100644
index 00000000000..eb3bec77326
--- /dev/null
+++ b/src/test/run-pass/regions-trait-object-1.rs
@@ -0,0 +1,43 @@
+// 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.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This is a regression test for something that only came up while
+// attempting to bootstrap libsyntax; it is adapted from
+// `syntax::ext::tt::generic_extension`.
+
+pub struct E<'a> {
+    pub f: &'a u8,
+}
+impl<'b> E<'b> {
+    pub fn m(&self) -> &'b u8 { self.f }
+}
+
+pub struct P<'c> {
+    pub g: &'c u8,
+}
+pub trait M {
+    fn n(&self) -> u8;
+}
+impl<'d> M for P<'d> {
+    fn n(&self) -> u8 { *self.g }
+}
+
+fn extension<'e>(x: &'e E<'e>) -> Box<M+'e> {
+    loop {
+        let p = P { g: x.m() };
+        return Box::new(p) as Box<M+'e>;
+    }
+}
+
+fn main() {
+    let w = E { f: &10u8 };
+    let o = extension(&w);
+    assert_eq!(o.n(), 10u8);
+}
diff --git a/src/test/run-pass/trait-object-with-lifetime-bound.rs b/src/test/run-pass/trait-object-with-lifetime-bound.rs
new file mode 100644
index 00000000000..4e481910aa9
--- /dev/null
+++ b/src/test/run-pass/trait-object-with-lifetime-bound.rs
@@ -0,0 +1,42 @@
+// 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.
+
+// Uncovered during work on new scoping rules for safe destructors
+// as an important use case to support properly.
+
+pub struct E<'a> {
+    pub f: &'a u8,
+}
+impl<'b> E<'b> {
+    pub fn m(&self) -> &'b u8 { self.f }
+}
+
+pub struct P<'c> {
+    pub g: &'c u8,
+}
+pub trait M {
+    fn n(&self) -> u8;
+}
+impl<'d> M for P<'d> {
+    fn n(&self) -> u8 { *self.g }
+}
+
+fn extension<'e>(x: &'e E<'e>) -> Box<M+'e> {
+    loop {
+        let p = P { g: x.m() };
+        return Box::new(p) as Box<M+'e>;
+    }
+}
+
+fn main() {
+    let w = E { f: &10u8 };
+    let o = extension(&w);
+    assert_eq!(o.n(), 10u8);
+}
diff --git a/src/test/run-pass/vec_cycle.rs b/src/test/run-pass/vec_cycle.rs
new file mode 100644
index 00000000000..65522bd95df
--- /dev/null
+++ b/src/test/run-pass/vec_cycle.rs
@@ -0,0 +1,47 @@
+// Copyright 2015 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 std::cell::Cell;
+
+#[derive(Show)]
+struct C<'a> {
+    v: Vec<Cell<Option<&'a C<'a>>>>,
+}
+
+impl<'a> C<'a> {
+    fn new() -> C<'a> {
+        C { v: Vec::new() }
+    }
+}
+
+fn f() {
+    let (mut c1, mut c2, mut c3);
+    c1 = C::new();
+    c2 = C::new();
+    c3 = C::new();
+
+    c1.v.push(Cell::new(None));
+    c1.v.push(Cell::new(None));
+    c2.v.push(Cell::new(None));
+    c2.v.push(Cell::new(None));
+    c3.v.push(Cell::new(None));
+    c3.v.push(Cell::new(None));
+
+    c1.v[0].set(Some(&c2));
+    c1.v[1].set(Some(&c3));
+    c2.v[0].set(Some(&c2));
+    c2.v[1].set(Some(&c3));
+    c3.v[0].set(Some(&c1));
+    c3.v[1].set(Some(&c2));
+}
+
+fn main() {
+    f();
+}
diff --git a/src/test/run-pass/vec_cycle_wrapped.rs b/src/test/run-pass/vec_cycle_wrapped.rs
new file mode 100644
index 00000000000..f179df90b34
--- /dev/null
+++ b/src/test/run-pass/vec_cycle_wrapped.rs
@@ -0,0 +1,58 @@
+// Copyright 2015 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 std::cell::Cell;
+
+#[derive(Show)]
+struct Refs<'a> {
+    v: Vec<Cell<Option<&'a C<'a>>>>,
+}
+
+#[derive(Show)]
+struct C<'a> {
+    refs: Refs<'a>,
+}
+
+impl<'a> Refs<'a> {
+    fn new() -> Refs<'a> {
+        Refs { v: Vec::new() }
+    }
+}
+
+impl<'a> C<'a> {
+    fn new() -> C<'a> {
+        C { refs: Refs::new() }
+    }
+}
+
+fn f() {
+    let (mut c1, mut c2, mut c3);
+    c1 = C::new();
+    c2 = C::new();
+    c3 = C::new();
+
+    c1.refs.v.push(Cell::new(None));
+    c1.refs.v.push(Cell::new(None));
+    c2.refs.v.push(Cell::new(None));
+    c2.refs.v.push(Cell::new(None));
+    c3.refs.v.push(Cell::new(None));
+    c3.refs.v.push(Cell::new(None));
+
+    c1.refs.v[0].set(Some(&c2));
+    c1.refs.v[1].set(Some(&c3));
+    c2.refs.v[0].set(Some(&c2));
+    c2.refs.v[1].set(Some(&c3));
+    c3.refs.v[0].set(Some(&c1));
+    c3.refs.v[1].set(Some(&c2));
+}
+
+fn main() {
+    f();
+}
diff --git a/src/test/run-pass/zero-size-type-destructors.rs b/src/test/run-pass/zero-size-type-destructors.rs
index fd272a47de9..f4d03a5cda4 100644
--- a/src/test/run-pass/zero-size-type-destructors.rs
+++ b/src/test/run-pass/zero-size-type-destructors.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(unsafe_no_drop_flag)]
+
 static mut destructions : int = 3;
 
 pub fn foo() {