about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthew <mjjasper1@gmail.com>2017-04-24 10:20:05 +0100
committerMatthew <mjjasper1@gmail.com>2017-04-24 10:20:05 +0100
commit158b085f06a41004ebf36d87afa3548f8b60861a (patch)
treee035c4787385e562748f7a3d04bb4e5018f82767
parent8a3ea01bcae85a3ed0c90ca5603cd88c469172c3 (diff)
parent15ce54096a589de277771ad1f55a334fe2661a64 (diff)
downloadrust-158b085f06a41004ebf36d87afa3548f8b60861a.tar.gz
rust-158b085f06a41004ebf36d87afa3548f8b60861a.zip
Fix more merge conflicts
m---------cargo0
-rw-r--r--src/doc/grammar.md5
-rw-r--r--src/doc/unstable-book/src/SUMMARY.md9
-rw-r--r--src/doc/unstable-book/src/library-features/as-unsafe-cell.md7
-rw-r--r--src/doc/unstable-book/src/library-features/binary-heap-extras.md7
-rw-r--r--src/doc/unstable-book/src/library-features/borrow-state.md7
-rw-r--r--src/doc/unstable-book/src/library-features/enumset.md7
-rw-r--r--src/doc/unstable-book/src/library-features/float-extras.md7
-rw-r--r--src/doc/unstable-book/src/library-features/is-unique.md7
-rw-r--r--src/doc/unstable-book/src/library-features/map-entry-recover-keys.md5
-rw-r--r--src/doc/unstable-book/src/library-features/rc-would-unwrap.md5
-rw-r--r--src/doc/unstable-book/src/library-features/zero-one.md7
-rw-r--r--src/liballoc/heap.rs6
-rw-r--r--src/liballoc/lib.rs1
-rw-r--r--src/liballoc/rc.rs54
-rw-r--r--src/libcollections/binary_heap.rs78
-rw-r--r--src/libcollections/btree/map.rs9
-rw-r--r--src/libcollections/btree/set.rs2
-rw-r--r--src/libcollections/enum_set.rs313
-rw-r--r--src/libcollections/lib.rs4
-rw-r--r--src/libcollections/linked_list.rs2
-rw-r--r--src/libcollections/tests/binary_heap.rs37
-rw-r--r--src/libcollections/tests/lib.rs1
-rw-r--r--src/libcollections/vec_deque.rs2
-rw-r--r--src/libcore/cell.rs89
-rw-r--r--src/libcore/fmt/num.rs5
-rw-r--r--src/libcore/num/dec2flt/rawfp.rs41
-rw-r--r--src/libcore/num/f32.rs45
-rw-r--r--src/libcore/num/f64.rs45
-rw-r--r--src/libcore/num/flt2dec/decoder.rs4
-rw-r--r--src/libcore/num/mod.rs123
-rw-r--r--src/libcore/tests/num/dec2flt/rawfp.rs47
-rw-r--r--src/librustc/dep_graph/dep_node.rs9
-rw-r--r--src/librustc/diagnostics.rs1
-rw-r--r--src/librustc/ich/impls_ty.rs9
-rw-r--r--src/librustc/infer/freshen.rs2
-rw-r--r--src/librustc/infer/region_inference/mod.rs8
-rw-r--r--src/librustc/middle/const_val.rs11
-rw-r--r--src/librustc/middle/cstore.rs16
-rw-r--r--src/librustc/middle/expr_use_visitor.rs2
-rw-r--r--src/librustc/middle/lang_items.rs7
-rw-r--r--src/librustc/middle/mem_categorization.rs4
-rw-r--r--src/librustc/middle/reachable.rs7
-rw-r--r--src/librustc/mir/mod.rs3
-rw-r--r--src/librustc/traits/fulfill.rs2
-rw-r--r--src/librustc/traits/mod.rs3
-rw-r--r--src/librustc/traits/select.rs29
-rw-r--r--src/librustc/traits/trans/mod.rs212
-rw-r--r--src/librustc/ty/context.rs21
-rw-r--r--src/librustc/ty/fold.rs22
-rw-r--r--src/librustc/ty/instance.rs5
-rw-r--r--src/librustc/ty/layout.rs54
-rw-r--r--src/librustc/ty/maps.rs49
-rw-r--r--src/librustc/ty/mod.rs229
-rw-r--r--src/librustc/ty/subst.rs3
-rw-r--r--src/librustc/ty/util.rs166
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/lifetime.rs2
-rw-r--r--src/librustc_const_eval/eval.rs264
-rw-r--r--src/librustc_const_eval/pattern.rs19
-rw-r--r--src/librustc_driver/driver.rs7
-rw-r--r--src/librustc_driver/test.rs4
-rw-r--r--src/librustc_metadata/creader.rs1
-rw-r--r--src/librustc_metadata/cstore.rs3
-rw-r--r--src/librustc_metadata/cstore_impl.rs29
-rw-r--r--src/librustc_metadata/decoder.rs40
-rw-r--r--src/librustc_mir/build/matches/test.rs2
-rw-r--r--src/librustc_mir/hair/cx/expr.rs3
-rw-r--r--src/librustc_mir/shim.rs5
-rw-r--r--src/librustc_mir/transform/erase_regions.rs4
-rw-r--r--src/librustc_mir/transform/inline.rs4
-rw-r--r--src/librustc_mir/transform/simplify.rs34
-rw-r--r--src/librustc_mir/util/elaborate_drops.rs5
-rw-r--r--src/librustc_trans/back/symbol_export.rs12
-rw-r--r--src/librustc_trans/back/symbol_names.rs157
-rw-r--r--src/librustc_trans/base.rs46
-rw-r--r--src/librustc_trans/callee.rs25
-rw-r--r--src/librustc_trans/collector.rs28
-rw-r--r--src/librustc_trans/common.rs4
-rw-r--r--src/librustc_trans/consts.rs13
-rw-r--r--src/librustc_trans/context.rs128
-rw-r--r--src/librustc_trans/lib.rs1
-rw-r--r--src/librustc_trans/mir/constant.rs14
-rw-r--r--src/librustc_trans/mir/mod.rs7
-rw-r--r--src/librustc_trans/mir/rvalue.rs2
-rw-r--r--src/librustc_trans/monomorphize.rs130
-rw-r--r--src/librustc_trans/partitioning.rs49
-rw-r--r--src/librustc_trans/symbol_cache.rs42
-rw-r--r--src/librustc_trans/symbol_map.rs5
-rw-r--r--src/librustc_trans/symbol_names_test.rs13
-rw-r--r--src/librustc_trans/trans_item.rs16
-rw-r--r--src/librustc_typeck/astconv.rs10
-rw-r--r--src/librustc_typeck/check/_match.rs2
-rw-r--r--src/librustc_typeck/check/dropck.rs412
-rw-r--r--src/librustc_typeck/check/intrinsic.rs2
-rw-r--r--src/librustc_typeck/check/method/probe.rs6
-rw-r--r--src/librustc_typeck/check/mod.rs4
-rw-r--r--src/librustc_typeck/check/regionck.rs9
-rw-r--r--src/librustc_typeck/check/writeback.rs8
-rw-r--r--src/librustc_typeck/collect.rs25
-rw-r--r--src/librustc_typeck/diagnostics.rs1
-rw-r--r--src/librustdoc/clean/inline.rs2
-rw-r--r--src/librustdoc/html/markdown.rs342
-rw-r--r--src/librustdoc/html/render.rs44
-rw-r--r--src/librustdoc/lib.rs20
-rw-r--r--src/librustdoc/markdown.rs14
-rw-r--r--src/librustdoc/test.rs53
-rw-r--r--src/libstd/collections/hash/map.rs9
-rw-r--r--src/libstd/collections/hash/set.rs2
-rw-r--r--src/libstd/f32.rs206
-rw-r--r--src/libstd/f64.rs179
-rw-r--r--src/libstd/lib.rs3
-rw-r--r--src/libstd/num.rs3
-rw-r--r--src/libstd/path.rs2
-rw-r--r--src/libstd/sync/mpsc/mod.rs2
-rw-r--r--src/libsyntax/parse/parser.rs101
-rw-r--r--src/test/codegen/drop.rs2
-rw-r--r--src/test/codegen/personality_lifetimes.rs1
-rw-r--r--src/test/compile-fail/const-call.rs2
-rw-r--r--src/test/compile-fail/const-pattern-not-const-evaluable.rs11
-rw-r--r--src/test/compile-fail/issue-39559.rs4
-rw-r--r--src/test/compile-fail/issue-41394.rs (renamed from src/test/rustdoc/check-hard-break.rs)16
-rw-r--r--src/test/parse-fail/bound-single-question-mark.rs13
-rw-r--r--src/test/parse-fail/trait-object-bad-parens.rs20
-rw-r--r--src/test/parse-fail/trait-object-lifetime-parens.rs18
-rw-r--r--src/test/parse-fail/trait-object-trait-parens.rs21
-rw-r--r--src/test/run-pass/auxiliary/issue-41394.rs26
-rw-r--r--src/test/run-pass/const-pattern-variant.rs38
-rw-r--r--src/test/run-pass/issue-23898.rs (renamed from src/test/compile-fail/non-constant-enum-for-vec-repeat.rs)5
-rw-r--r--src/test/run-pass/issue-41394.rs17
-rw-r--r--src/test/run-pass/issue-8460.rs35
-rw-r--r--src/test/run-pass/sync-send-iterators-in-libcollections.rs19
-rw-r--r--src/test/run-pass/union/union-transmute.rs8
-rw-r--r--src/test/run-pass/while-let.rs2
-rw-r--r--src/test/rustdoc/check-rule-image-footnote.rs44
-rw-r--r--src/tools/error_index_generator/main.rs4
135 files changed, 2040 insertions, 2700 deletions
diff --git a/cargo b/cargo
-Subproject c416fb60b11ecfd2a1ba0fb8567c9a92590b5d2
+Subproject 8326a3683a9045d825e4fdc4021af340ee3b375
diff --git a/src/doc/grammar.md b/src/doc/grammar.md
index 3fbf9f06d99..12daa24e857 100644
--- a/src/doc/grammar.md
+++ b/src/doc/grammar.md
@@ -781,10 +781,11 @@ never_type : "!" ;
 ### Type parameter bounds
 
 ```antlr
+bound-list := bound | bound '+' bound-list '+' ?
 bound := ty_bound | lt_bound
 lt_bound := lifetime
-ty_bound := [?] [ for<lt_param_defs> ] simple_path
-bound-list := bound | bound '+' bound-list '+' ?
+ty_bound := ty_bound_noparen | (ty_bound_noparen)
+ty_bound_noparen := [?] [ for<lt_param_defs> ] simple_path
 ```
 
 ### Self types
diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md
index 1cfb4653023..ef67941975b 100644
--- a/src/doc/unstable-book/src/SUMMARY.md
+++ b/src/doc/unstable-book/src/SUMMARY.md
@@ -101,11 +101,8 @@
     - [alloc_system](library-features/alloc-system.md)
     - [alloc](library-features/alloc.md)
     - [as_c_str](library-features/as-c-str.md)
-    - [as_unsafe_cell](library-features/as-unsafe-cell.md)
     - [ascii_ctype](library-features/ascii-ctype.md)
-    - [binary_heap_extras](library-features/binary-heap-extras.md)
     - [binary_heap_peek_mut_pop](library-features/binary-heap-peek-mut-pop.md)
-    - [borrow_state](library-features/borrow-state.md)
     - [box_heap](library-features/box-heap.md)
     - [c_void_variant](library-features/c-void-variant.md)
     - [char_escape_debug](library-features/char-escape-debug.md)
@@ -130,14 +127,12 @@
     - [derive_clone_copy](library-features/derive-clone-copy.md)
     - [derive_eq](library-features/derive-eq.md)
     - [discriminant_value](library-features/discriminant-value.md)
-    - [enumset](library-features/enumset.md)
     - [error_type_id](library-features/error-type-id.md)
     - [exact_size_is_empty](library-features/exact-size-is-empty.md)
     - [fd](library-features/fd.md)
     - [fd_read](library-features/fd-read.md)
     - [fixed_size_array](library-features/fixed-size-array.md)
     - [float_bits_conv](library-features/float-bits-conv.md)
-    - [float_extras](library-features/float-extras.md)
     - [flt2dec](library-features/flt2dec.md)
     - [fmt_flags_align](library-features/fmt-flags-align.md)
     - [fmt_internals](library-features/fmt-internals.md)
@@ -157,7 +152,6 @@
     - [io_error_internals](library-features/io-error-internals.md)
     - [io](library-features/io.md)
     - [ip](library-features/ip.md)
-    - [is_unique](library-features/is-unique.md)
     - [iter_rfind](library-features/iter-rfind.md)
     - [libstd_io_internals](library-features/libstd-io-internals.md)
     - [libstd_sys_internals](library-features/libstd-sys-internals.md)
@@ -165,7 +159,6 @@
     - [linked_list_extras](library-features/linked-list-extras.md)
     - [lookup_host](library-features/lookup-host.md)
     - [manually_drop](library-features/manually-drop.md)
-    - [map_entry_recover_keys](library-features/map-entry-recover-keys.md)
     - [mpsc_select](library-features/mpsc-select.md)
     - [n16](library-features/n16.md)
     - [never_type_impls](library-features/never-type-impls.md)
@@ -188,7 +181,6 @@
     - [rand](library-features/rand.md)
     - [range_contains](library-features/range-contains.md)
     - [raw](library-features/raw.md)
-    - [rc_would_unwrap](library-features/rc-would-unwrap.md)
     - [retain_hash_collection](library-features/retain-hash-collection.md)
     - [reverse_cmp_key](library-features/reverse-cmp-key.md)
     - [rt](library-features/rt.md)
@@ -224,4 +216,3 @@
     - [windows_handle](library-features/windows-handle.md)
     - [windows_net](library-features/windows-net.md)
     - [windows_stdio](library-features/windows-stdio.md)
-    - [zero_one](library-features/zero-one.md)
diff --git a/src/doc/unstable-book/src/library-features/as-unsafe-cell.md b/src/doc/unstable-book/src/library-features/as-unsafe-cell.md
deleted file mode 100644
index 79d7a7cad0b..00000000000
--- a/src/doc/unstable-book/src/library-features/as-unsafe-cell.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# `as_unsafe_cell`
-
-The tracking issue for this feature is: [#27708]
-
-[#27708]: https://github.com/rust-lang/rust/issues/27708
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/binary-heap-extras.md b/src/doc/unstable-book/src/library-features/binary-heap-extras.md
deleted file mode 100644
index aa535f3b678..00000000000
--- a/src/doc/unstable-book/src/library-features/binary-heap-extras.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# `binary_heap_extras`
-
-The tracking issue for this feature is: [#28147]
-
-[#28147]: https://github.com/rust-lang/rust/issues/28147
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/borrow-state.md b/src/doc/unstable-book/src/library-features/borrow-state.md
deleted file mode 100644
index 304b8dffe98..00000000000
--- a/src/doc/unstable-book/src/library-features/borrow-state.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# `borrow_state`
-
-The tracking issue for this feature is: [#27733]
-
-[#27733]: https://github.com/rust-lang/rust/issues/27733
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/enumset.md b/src/doc/unstable-book/src/library-features/enumset.md
deleted file mode 100644
index 24c8d8fa7db..00000000000
--- a/src/doc/unstable-book/src/library-features/enumset.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# `enumset`
-
-The tracking issue for this feature is: [#37966]
-
-[#37966]: https://github.com/rust-lang/rust/issues/37966
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/float-extras.md b/src/doc/unstable-book/src/library-features/float-extras.md
deleted file mode 100644
index ff2d20a545f..00000000000
--- a/src/doc/unstable-book/src/library-features/float-extras.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# `float_extras`
-
-The tracking issue for this feature is: [#27752]
-
-[#27752]: https://github.com/rust-lang/rust/issues/27752
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/is-unique.md b/src/doc/unstable-book/src/library-features/is-unique.md
deleted file mode 100644
index 6070006758b..00000000000
--- a/src/doc/unstable-book/src/library-features/is-unique.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# `is_unique`
-
-The tracking issue for this feature is: [#28356]
-
-[#28356]: https://github.com/rust-lang/rust/issues/28356
-
-------------------------
diff --git a/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md b/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md
deleted file mode 100644
index 2d15aa0e90d..00000000000
--- a/src/doc/unstable-book/src/library-features/map-entry-recover-keys.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# `map_entry_recover_keys`
-
-The tracking issue for this feature is: [#34285]
-
-[#34285]: https://github.com/rust-lang/rust/issues/34285
diff --git a/src/doc/unstable-book/src/library-features/rc-would-unwrap.md b/src/doc/unstable-book/src/library-features/rc-would-unwrap.md
deleted file mode 100644
index 462387dfdcc..00000000000
--- a/src/doc/unstable-book/src/library-features/rc-would-unwrap.md
+++ /dev/null
@@ -1,5 +0,0 @@
-# `rc_would_unwrap`
-
-The tracking issue for this feature is: [#28356]
-
-[#28356]: https://github.com/rust-lang/rust/issues/28356
diff --git a/src/doc/unstable-book/src/library-features/zero-one.md b/src/doc/unstable-book/src/library-features/zero-one.md
deleted file mode 100644
index 4d1cf38c3c2..00000000000
--- a/src/doc/unstable-book/src/library-features/zero-one.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# `zero_one`
-
-The tracking issue for this feature is: [#27739]
-
-[#27739]: https://github.com/rust-lang/rust/issues/27739
-
-------------------------
diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs
index 08a0b2a6d00..056af13016c 100644
--- a/src/liballoc/heap.rs
+++ b/src/liballoc/heap.rs
@@ -16,7 +16,6 @@
             issue = "27700")]
 
 use core::{isize, usize};
-#[cfg(not(test))]
 use core::intrinsics::{min_align_of_val, size_of_val};
 
 #[allow(improper_ctypes)]
@@ -158,10 +157,9 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
     }
 }
 
-#[cfg(not(test))]
-#[lang = "box_free"]
+#[cfg_attr(not(test), lang = "box_free")]
 #[inline]
-unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
+pub(crate) unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
     let size = size_of_val(&*ptr);
     let align = min_align_of_val(&*ptr);
     // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 0c01eabd593..c70d82392f9 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -87,6 +87,7 @@
 #![feature(needs_allocator)]
 #![feature(optin_builtin_traits)]
 #![feature(placement_in_syntax)]
+#![cfg_attr(stage0, feature(pub_restricted))]
 #![feature(shared)]
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index fed718e9be4..38dc9145835 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -239,7 +239,7 @@ use core::ops::CoerceUnsized;
 use core::ptr::{self, Shared};
 use core::convert::From;
 
-use heap::deallocate;
+use heap::{allocate, deallocate, box_free};
 use raw_vec::RawVec;
 
 struct RcBox<T: ?Sized> {
@@ -248,7 +248,6 @@ struct RcBox<T: ?Sized> {
     value: T,
 }
 
-
 /// A single-threaded reference-counting pointer.
 ///
 /// See the [module-level documentation](./index.html) for more details.
@@ -341,19 +340,6 @@ impl<T> Rc<T> {
         }
     }
 
-    /// Checks whether [`Rc::try_unwrap`][try_unwrap] would return
-    /// [`Ok`].
-    ///
-    /// [try_unwrap]: struct.Rc.html#method.try_unwrap
-    /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
-    #[unstable(feature = "rc_would_unwrap",
-               reason = "just added for niche usecase",
-               issue = "28356")]
-    #[rustc_deprecated(since = "1.15.0", reason = "too niche; use `strong_count` instead")]
-    pub fn would_unwrap(this: &Self) -> bool {
-        Rc::strong_count(&this) == 1
-    }
-
     /// Consumes the `Rc`, returning the wrapped pointer.
     ///
     /// To avoid a memory leak the pointer must be converted back to an `Rc` using
@@ -438,6 +424,38 @@ impl Rc<str> {
     }
 }
 
+impl<T> Rc<[T]> {
+    /// Constructs a new `Rc<[T]>` from a `Box<[T]>`.
+    #[doc(hidden)]
+    #[unstable(feature = "rustc_private",
+               reason = "for internal use in rustc",
+               issue = "0")]
+    pub fn __from_array(value: Box<[T]>) -> Rc<[T]> {
+        unsafe {
+            let ptr: *mut RcBox<[T]> =
+                mem::transmute([mem::align_of::<RcBox<[T; 1]>>(), value.len()]);
+            // FIXME(custom-DST): creating this invalid &[T] is dubiously defined,
+            // we should have a better way of getting the size/align
+            // of a DST from its unsized part.
+            let ptr = allocate(size_of_val(&*ptr), align_of_val(&*ptr));
+            let ptr: *mut RcBox<[T]> = mem::transmute([ptr as usize, value.len()]);
+
+            // Initialize the new RcBox.
+            ptr::write(&mut (*ptr).strong, Cell::new(1));
+            ptr::write(&mut (*ptr).weak, Cell::new(1));
+            ptr::copy_nonoverlapping(
+                value.as_ptr(),
+                &mut (*ptr).value as *mut [T] as *mut T,
+                value.len());
+
+            // Free the original allocation without freeing its (moved) contents.
+            box_free(Box::into_raw(value));
+
+            Rc { ptr: Shared::new(ptr as *const _) }
+        }
+    }
+}
+
 impl<T: ?Sized> Rc<T> {
     /// Creates a new [`Weak`][weak] pointer to this value.
     ///
@@ -501,11 +519,7 @@ impl<T: ?Sized> Rc<T> {
     ///
     /// [weak]: struct.Weak.html
     #[inline]
-    #[unstable(feature = "is_unique", reason = "uniqueness has unclear meaning",
-               issue = "28356")]
-    #[rustc_deprecated(since = "1.15.0",
-                       reason = "too niche; use `strong_count` and `weak_count` instead")]
-    pub fn is_unique(this: &Self) -> bool {
+    fn is_unique(this: &Self) -> bool {
         Rc::weak_count(this) == 0 && Rc::strong_count(this) == 1
     }
 
diff --git a/src/libcollections/binary_heap.rs b/src/libcollections/binary_heap.rs
index 149c285a72a..7d972403f65 100644
--- a/src/libcollections/binary_heap.rs
+++ b/src/libcollections/binary_heap.rs
@@ -555,82 +555,6 @@ impl<T: Ord> BinaryHeap<T> {
         self.sift_up(0, old_len);
     }
 
-    /// Pushes an item onto the binary heap, then pops the greatest item off the queue in
-    /// an optimized fashion.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// #![feature(binary_heap_extras)]
-    /// #![allow(deprecated)]
-    ///
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::new();
-    /// heap.push(1);
-    /// heap.push(5);
-    ///
-    /// assert_eq!(heap.push_pop(3), 5);
-    /// assert_eq!(heap.push_pop(9), 9);
-    /// assert_eq!(heap.len(), 2);
-    /// assert_eq!(heap.peek(), Some(&3));
-    /// ```
-    #[unstable(feature = "binary_heap_extras",
-               reason = "needs to be audited",
-               issue = "28147")]
-    #[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")]
-    pub fn push_pop(&mut self, mut item: T) -> T {
-        match self.data.get_mut(0) {
-            None => return item,
-            Some(top) => {
-                if *top > item {
-                    swap(&mut item, top);
-                } else {
-                    return item;
-                }
-            }
-        }
-
-        self.sift_down(0);
-        item
-    }
-
-    /// Pops the greatest item off the binary heap, then pushes an item onto the queue in
-    /// an optimized fashion. The push is done regardless of whether the binary heap
-    /// was empty.
-    ///
-    /// # Examples
-    ///
-    /// Basic usage:
-    ///
-    /// ```
-    /// #![feature(binary_heap_extras)]
-    /// #![allow(deprecated)]
-    ///
-    /// use std::collections::BinaryHeap;
-    /// let mut heap = BinaryHeap::new();
-    ///
-    /// assert_eq!(heap.replace(1), None);
-    /// assert_eq!(heap.replace(3), Some(1));
-    /// assert_eq!(heap.len(), 1);
-    /// assert_eq!(heap.peek(), Some(&3));
-    /// ```
-    #[unstable(feature = "binary_heap_extras",
-               reason = "needs to be audited",
-               issue = "28147")]
-    #[rustc_deprecated(since = "1.13.0", reason = "use `peek_mut` instead")]
-    pub fn replace(&mut self, mut item: T) -> Option<T> {
-        if !self.is_empty() {
-            swap(&mut item, &mut self.data[0]);
-            self.sift_down(0);
-            Some(item)
-        } else {
-            self.push(item);
-            None
-        }
-    }
-
     /// Consumes the `BinaryHeap` and returns the underlying vector
     /// in arbitrary order.
     ///
@@ -1042,7 +966,7 @@ impl<'a, T> FusedIterator for Iter<'a, T> {}
 
 /// An owning iterator over the elements of a `BinaryHeap`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`]
+/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`][`BinaryHeap`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`into_iter`]: struct.BinaryHeap.html#method.into_iter
diff --git a/src/libcollections/btree/map.rs b/src/libcollections/btree/map.rs
index fb0b852d102..d73c0254a74 100644
--- a/src/libcollections/btree/map.rs
+++ b/src/libcollections/btree/map.rs
@@ -298,7 +298,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> {
 
 /// An owning iterator over the entries of a `BTreeMap`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`]
+/// This `struct` is created by the [`into_iter`] method on [`BTreeMap`][`BTreeMap`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`into_iter`]: struct.BTreeMap.html#method.into_iter
@@ -2217,13 +2217,6 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> {
         self.handle.reborrow().into_kv().0
     }
 
-    /// Deprecated, renamed to `remove_entry`
-    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
-    #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")]
-    pub fn remove_pair(self) -> (K, V) {
-        self.remove_entry()
-    }
-
     /// Take ownership of the key and value from the map.
     ///
     /// # Examples
diff --git a/src/libcollections/btree/set.rs b/src/libcollections/btree/set.rs
index e05533aa50e..d32460da939 100644
--- a/src/libcollections/btree/set.rs
+++ b/src/libcollections/btree/set.rs
@@ -97,7 +97,7 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> {
 
 /// An owning iterator over the items of a `BTreeSet`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`]
+/// This `struct` is created by the [`into_iter`] method on [`BTreeSet`][`BTreeSet`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`BTreeSet`]: struct.BTreeSet.html
diff --git a/src/libcollections/enum_set.rs b/src/libcollections/enum_set.rs
deleted file mode 100644
index aaee567bf1d..00000000000
--- a/src/libcollections/enum_set.rs
+++ /dev/null
@@ -1,313 +0,0 @@
-// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! A structure for holding a set of enum variants.
-//!
-//! This module defines a container which uses an efficient bit mask
-//! representation to hold C-like enum variants.
-
-#![unstable(feature = "enumset",
-            reason = "matches collection reform specification, \
-                      waiting for dust to settle",
-            issue = "37966")]
-#![rustc_deprecated(since = "1.16.0", reason = "long since replaced")]
-#![allow(deprecated)]
-
-use core::marker;
-use core::fmt;
-use core::iter::{FromIterator, FusedIterator};
-use core::ops::{Sub, BitOr, BitAnd, BitXor};
-
-// FIXME(contentions): implement union family of methods? (general design may be
-// wrong here)
-
-/// A specialized set implementation to use enum types.
-///
-/// It is a logic error for an item to be modified in such a way that the
-/// transformation of the item to or from a `usize`, as determined by the
-/// `CLike` trait, changes while the item is in the set. This is normally only
-/// possible through `Cell`, `RefCell`, global state, I/O, or unsafe code.
-#[derive(PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct EnumSet<E> {
-    // We must maintain the invariant that no bits are set
-    // for which no variant exists
-    bits: usize,
-    marker: marker::PhantomData<E>,
-}
-
-impl<E> Copy for EnumSet<E> {}
-
-impl<E> Clone for EnumSet<E> {
-    fn clone(&self) -> EnumSet<E> {
-        *self
-    }
-}
-
-impl<E: CLike + fmt::Debug> fmt::Debug for EnumSet<E> {
-    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        fmt.debug_set().entries(self).finish()
-    }
-}
-
-/// An interface for casting C-like enum to usize and back.
-/// A typically implementation is as below.
-///
-/// ```{rust,ignore}
-/// #[repr(usize)]
-/// enum Foo {
-///     A, B, C
-/// }
-///
-/// impl CLike for Foo {
-///     fn to_usize(&self) -> usize {
-///         *self as usize
-///     }
-///
-///     fn from_usize(v: usize) -> Foo {
-///         unsafe { mem::transmute(v) }
-///     }
-/// }
-/// ```
-pub trait CLike {
-    /// Converts a C-like enum to a `usize`.
-    fn to_usize(&self) -> usize;
-    /// Converts a `usize` to a C-like enum.
-    fn from_usize(usize) -> Self;
-}
-
-fn bit<E: CLike>(e: &E) -> usize {
-    use core::mem;
-    let value = e.to_usize();
-    let bits = mem::size_of::<usize>() * 8;
-    assert!(value < bits,
-            "EnumSet only supports up to {} variants.",
-            bits - 1);
-    1 << value
-}
-
-impl<E: CLike> EnumSet<E> {
-    /// Returns an empty `EnumSet`.
-    pub fn new() -> EnumSet<E> {
-        EnumSet {
-            bits: 0,
-            marker: marker::PhantomData,
-        }
-    }
-
-    /// Returns the number of elements in the given `EnumSet`.
-    pub fn len(&self) -> usize {
-        self.bits.count_ones() as usize
-    }
-
-    /// Returns `true` if the `EnumSet` is empty.
-    pub fn is_empty(&self) -> bool {
-        self.bits == 0
-    }
-
-    pub fn clear(&mut self) {
-        self.bits = 0;
-    }
-
-    /// Returns `false` if the `EnumSet` contains any enum of the given `EnumSet`.
-    pub fn is_disjoint(&self, other: &EnumSet<E>) -> bool {
-        (self.bits & other.bits) == 0
-    }
-
-    /// Returns `true` if a given `EnumSet` is included in this `EnumSet`.
-    pub fn is_superset(&self, other: &EnumSet<E>) -> bool {
-        (self.bits & other.bits) == other.bits
-    }
-
-    /// Returns `true` if this `EnumSet` is included in the given `EnumSet`.
-    pub fn is_subset(&self, other: &EnumSet<E>) -> bool {
-        other.is_superset(self)
-    }
-
-    /// Returns the union of both `EnumSets`.
-    pub fn union(&self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {
-            bits: self.bits | e.bits,
-            marker: marker::PhantomData,
-        }
-    }
-
-    /// Returns the intersection of both `EnumSets`.
-    pub fn intersection(&self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {
-            bits: self.bits & e.bits,
-            marker: marker::PhantomData,
-        }
-    }
-
-    /// Adds an enum to the `EnumSet`, and returns `true` if it wasn't there before
-    pub fn insert(&mut self, e: E) -> bool {
-        let result = !self.contains(&e);
-        self.bits |= bit(&e);
-        result
-    }
-
-    /// Removes an enum from the EnumSet
-    pub fn remove(&mut self, e: &E) -> bool {
-        let result = self.contains(e);
-        self.bits &= !bit(e);
-        result
-    }
-
-    /// Returns `true` if an `EnumSet` contains a given enum.
-    pub fn contains(&self, e: &E) -> bool {
-        (self.bits & bit(e)) != 0
-    }
-
-    /// Returns an iterator over an `EnumSet`.
-    pub fn iter(&self) -> Iter<E> {
-        Iter::new(self.bits)
-    }
-}
-
-impl<E: CLike> Sub for EnumSet<E> {
-    type Output = EnumSet<E>;
-
-    fn sub(self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {
-            bits: self.bits & !e.bits,
-            marker: marker::PhantomData,
-        }
-    }
-}
-
-impl<E: CLike> BitOr for EnumSet<E> {
-    type Output = EnumSet<E>;
-
-    fn bitor(self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {
-            bits: self.bits | e.bits,
-            marker: marker::PhantomData,
-        }
-    }
-}
-
-impl<E: CLike> BitAnd for EnumSet<E> {
-    type Output = EnumSet<E>;
-
-    fn bitand(self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {
-            bits: self.bits & e.bits,
-            marker: marker::PhantomData,
-        }
-    }
-}
-
-impl<E: CLike> BitXor for EnumSet<E> {
-    type Output = EnumSet<E>;
-
-    fn bitxor(self, e: EnumSet<E>) -> EnumSet<E> {
-        EnumSet {
-            bits: self.bits ^ e.bits,
-            marker: marker::PhantomData,
-        }
-    }
-}
-
-/// An iterator over an `EnumSet`
-pub struct Iter<E> {
-    index: usize,
-    bits: usize,
-    marker: marker::PhantomData<E>,
-}
-
-impl<E: fmt::Debug> fmt::Debug for Iter<E> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.debug_tuple("Iter")
-         .field(&self.index)
-         .field(&self.bits)
-         .finish()
-    }
-}
-
-// FIXME(#19839) Remove in favor of `#[derive(Clone)]`
-impl<E> Clone for Iter<E> {
-    fn clone(&self) -> Iter<E> {
-        Iter {
-            index: self.index,
-            bits: self.bits,
-            marker: marker::PhantomData,
-        }
-    }
-}
-
-impl<E: CLike> Iter<E> {
-    fn new(bits: usize) -> Iter<E> {
-        Iter {
-            index: 0,
-            bits: bits,
-            marker: marker::PhantomData,
-        }
-    }
-}
-
-impl<E: CLike> Iterator for Iter<E> {
-    type Item = E;
-
-    fn next(&mut self) -> Option<E> {
-        if self.bits == 0 {
-            return None;
-        }
-
-        while (self.bits & 1) == 0 {
-            self.index += 1;
-            self.bits >>= 1;
-        }
-        let elem = CLike::from_usize(self.index);
-        self.index += 1;
-        self.bits >>= 1;
-        Some(elem)
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let exact = self.bits.count_ones() as usize;
-        (exact, Some(exact))
-    }
-}
-
-#[unstable(feature = "fused", issue = "35602")]
-impl<E: CLike> FusedIterator for Iter<E> {}
-
-impl<E: CLike> FromIterator<E> for EnumSet<E> {
-    fn from_iter<I: IntoIterator<Item = E>>(iter: I) -> EnumSet<E> {
-        let mut ret = EnumSet::new();
-        ret.extend(iter);
-        ret
-    }
-}
-
-impl<'a, E> IntoIterator for &'a EnumSet<E>
-    where E: CLike
-{
-    type Item = E;
-    type IntoIter = Iter<E>;
-
-    fn into_iter(self) -> Iter<E> {
-        self.iter()
-    }
-}
-
-impl<E: CLike> Extend<E> for EnumSet<E> {
-    fn extend<I: IntoIterator<Item = E>>(&mut self, iter: I) {
-        for element in iter {
-            self.insert(element);
-        }
-    }
-}
-
-impl<'a, E: 'a + CLike + Copy> Extend<&'a E> for EnumSet<E> {
-    fn extend<I: IntoIterator<Item = &'a E>>(&mut self, iter: I) {
-        self.extend(iter.into_iter().cloned());
-    }
-}
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index 3bea61f6220..8d056afdb57 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -89,9 +89,6 @@ pub use btree_set::BTreeSet;
 #[doc(no_inline)]
 pub use linked_list::LinkedList;
 #[doc(no_inline)]
-#[allow(deprecated)]
-pub use enum_set::EnumSet;
-#[doc(no_inline)]
 pub use vec_deque::VecDeque;
 #[doc(no_inline)]
 pub use string::String;
@@ -107,7 +104,6 @@ mod macros;
 pub mod binary_heap;
 mod btree;
 pub mod borrow;
-pub mod enum_set;
 pub mod fmt;
 pub mod linked_list;
 pub mod range;
diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs
index 1cc5e10418f..adfd91bec48 100644
--- a/src/libcollections/linked_list.rs
+++ b/src/libcollections/linked_list.rs
@@ -115,7 +115,7 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for IterMut<'a, T> {
 
 /// An owning iterator over the elements of a `LinkedList`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`LinkedList`]
+/// This `struct` is created by the [`into_iter`] method on [`LinkedList`][`LinkedList`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`into_iter`]: struct.LinkedList.html#method.into_iter
diff --git a/src/libcollections/tests/binary_heap.rs b/src/libcollections/tests/binary_heap.rs
index d284937a9e6..af18cddaddb 100644
--- a/src/libcollections/tests/binary_heap.rs
+++ b/src/libcollections/tests/binary_heap.rs
@@ -152,36 +152,6 @@ fn test_push_unique() {
     assert!(*heap.peek().unwrap() == box 103);
 }
 
-#[test]
-#[allow(deprecated)]
-fn test_push_pop() {
-    let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.push_pop(6), 6);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.push_pop(0), 5);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.push_pop(4), 5);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.push_pop(1), 4);
-    assert_eq!(heap.len(), 5);
-}
-
-#[test]
-#[allow(deprecated)]
-fn test_replace() {
-    let mut heap = BinaryHeap::from(vec![5, 5, 2, 1, 3]);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.replace(6).unwrap(), 5);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.replace(0).unwrap(), 6);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.replace(4).unwrap(), 5);
-    assert_eq!(heap.len(), 5);
-    assert_eq!(heap.replace(1).unwrap(), 4);
-    assert_eq!(heap.len(), 5);
-}
-
 fn check_to_vec(mut data: Vec<i32>) {
     let heap = BinaryHeap::from(data.clone());
     let mut v = heap.clone().into_vec();
@@ -228,13 +198,6 @@ fn test_empty_peek_mut() {
 }
 
 #[test]
-#[allow(deprecated)]
-fn test_empty_replace() {
-    let mut heap = BinaryHeap::new();
-    assert!(heap.replace(5).is_none());
-}
-
-#[test]
 fn test_from_iter() {
     let xs = vec![9, 8, 7, 6, 5, 4, 3, 2, 1];
 
diff --git a/src/libcollections/tests/lib.rs b/src/libcollections/tests/lib.rs
index 618eb386c0f..9c6e31d70a5 100644
--- a/src/libcollections/tests/lib.rs
+++ b/src/libcollections/tests/lib.rs
@@ -10,7 +10,6 @@
 
 #![deny(warnings)]
 
-#![feature(binary_heap_extras)]
 #![feature(binary_heap_peek_mut_pop)]
 #![feature(box_syntax)]
 #![feature(inclusive_range_syntax)]
diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs
index a9e795f9378..079d3acf376 100644
--- a/src/libcollections/vec_deque.rs
+++ b/src/libcollections/vec_deque.rs
@@ -2070,7 +2070,7 @@ impl<'a, T> FusedIterator for IterMut<'a, T> {}
 
 /// An owning iterator over the elements of a `VecDeque`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`VecDeque`]
+/// This `struct` is created by the [`into_iter`] method on [`VecDeque`][`VecDeque`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`into_iter`]: struct.VecDeque.html#method.into_iter
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index 0186d972782..ba04cbb0543 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -310,26 +310,6 @@ impl<T> Cell<T> {
         }
     }
 
-    /// Returns a reference to the underlying `UnsafeCell`.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(as_unsafe_cell)]
-    ///
-    /// use std::cell::Cell;
-    ///
-    /// let c = Cell::new(5);
-    ///
-    /// let uc = c.as_unsafe_cell();
-    /// ```
-    #[inline]
-    #[unstable(feature = "as_unsafe_cell", issue = "27708")]
-    #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")]
-    pub fn as_unsafe_cell(&self) -> &UnsafeCell<T> {
-        &self.value
-    }
-
     /// Returns a raw pointer to the underlying data in this cell.
     ///
     /// # Examples
@@ -480,20 +460,6 @@ pub struct RefCell<T: ?Sized> {
     value: UnsafeCell<T>,
 }
 
-/// An enumeration of values returned from the `state` method on a `RefCell<T>`.
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-#[unstable(feature = "borrow_state", issue = "27733")]
-#[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")]
-#[allow(deprecated)]
-pub enum BorrowState {
-    /// The cell is currently being read, there is at least one active `borrow`.
-    Reading,
-    /// The cell is currently being written to, there is an active `borrow_mut`.
-    Writing,
-    /// There are no outstanding borrows on this cell.
-    Unused,
-}
-
 /// An error returned by [`RefCell::try_borrow`](struct.RefCell.html#method.try_borrow).
 #[stable(feature = "try_borrow", since = "1.13.0")]
 pub struct BorrowError {
@@ -582,38 +548,6 @@ impl<T> RefCell<T> {
 }
 
 impl<T: ?Sized> RefCell<T> {
-    /// Query the current state of this `RefCell`
-    ///
-    /// The returned value can be dispatched on to determine if a call to
-    /// `borrow` or `borrow_mut` would succeed.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(borrow_state)]
-    ///
-    /// use std::cell::{BorrowState, RefCell};
-    ///
-    /// let c = RefCell::new(5);
-    ///
-    /// match c.borrow_state() {
-    ///     BorrowState::Writing => println!("Cannot be borrowed"),
-    ///     BorrowState::Reading => println!("Cannot be borrowed mutably"),
-    ///     BorrowState::Unused => println!("Can be borrowed (mutably as well)"),
-    /// }
-    /// ```
-    #[unstable(feature = "borrow_state", issue = "27733")]
-    #[rustc_deprecated(since = "1.15.0", reason = "use `try_borrow` instead")]
-    #[allow(deprecated)]
-    #[inline]
-    pub fn borrow_state(&self) -> BorrowState {
-        match self.borrow.get() {
-            WRITING => BorrowState::Writing,
-            UNUSED => BorrowState::Unused,
-            _ => BorrowState::Reading,
-        }
-    }
-
     /// Immutably borrows the wrapped value.
     ///
     /// The borrow lasts until the returned `Ref` exits scope. Multiple
@@ -769,29 +703,6 @@ impl<T: ?Sized> RefCell<T> {
         }
     }
 
-    /// Returns a reference to the underlying `UnsafeCell`.
-    ///
-    /// This can be used to circumvent `RefCell`'s safety checks.
-    ///
-    /// This function is `unsafe` because `UnsafeCell`'s field is public.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(as_unsafe_cell)]
-    ///
-    /// use std::cell::RefCell;
-    ///
-    /// let c = RefCell::new(5);
-    /// let c = unsafe { c.as_unsafe_cell() };
-    /// ```
-    #[inline]
-    #[unstable(feature = "as_unsafe_cell", issue = "27708")]
-    #[rustc_deprecated(since = "1.12.0", reason = "renamed to as_ptr")]
-    pub unsafe fn as_unsafe_cell(&self) -> &UnsafeCell<T> {
-        &self.value
-    }
-
     /// Returns a raw pointer to the underlying data in this cell.
     ///
     /// # Examples
diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs
index a324a4aed25..4ca303dee43 100644
--- a/src/libcore/fmt/num.rs
+++ b/src/libcore/fmt/num.rs
@@ -15,7 +15,6 @@
 // FIXME: #6220 Implement floating point formatting
 
 use fmt;
-use num::Zero;
 use ops::{Div, Rem, Sub};
 use str;
 use slice;
@@ -23,8 +22,9 @@ use ptr;
 use mem;
 
 #[doc(hidden)]
-trait Int: Zero + PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
+trait Int: PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
            Sub<Output=Self> + Copy {
+    fn zero() -> Self;
     fn from_u8(u: u8) -> Self;
     fn to_u8(&self) -> u8;
     fn to_u16(&self) -> u16;
@@ -35,6 +35,7 @@ trait Int: Zero + PartialEq + PartialOrd + Div<Output=Self> + Rem<Output=Self> +
 
 macro_rules! doit {
     ($($t:ident)*) => ($(impl Int for $t {
+        fn zero() -> $t { 0 }
         fn from_u8(u: u8) -> $t { u as $t }
         fn to_u8(&self) -> u8 { *self as u8 }
         fn to_u16(&self) -> u16 { *self as u16 }
diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs
index 1485c79ead2..2a60292d023 100644
--- a/src/libcore/num/dec2flt/rawfp.rs
+++ b/src/libcore/num/dec2flt/rawfp.rs
@@ -63,11 +63,8 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp
     const NAN: Self;
     const ZERO: Self;
 
-    // suffix of "2" because Float::integer_decode is deprecated
-    #[allow(deprecated)]
-    fn integer_decode2(self) -> (u64, i16, i8) {
-        Float::integer_decode(self)
-    }
+    /// Returns the mantissa, exponent and sign as integers.
+    fn integer_decode(self) -> (u64, i16, i8);
 
     /// Get the raw binary representation of the float.
     fn transmute(self) -> u64;
@@ -160,6 +157,21 @@ impl RawFloat for f32 {
     const ZERO_CUTOFF: i64 = -48;
     other_constants!(f32);
 
+    /// Returns the mantissa, exponent and sign as integers.
+    fn integer_decode(self) -> (u64, i16, i8) {
+        let bits: u32 = unsafe { transmute(self) };
+        let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
+        let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
+        let mantissa = if exponent == 0 {
+            (bits & 0x7fffff) << 1
+        } else {
+            (bits & 0x7fffff) | 0x800000
+        };
+        // Exponent bias + mantissa shift
+        exponent -= 127 + 23;
+        (mantissa as u64, exponent, sign)
+    }
+
     fn transmute(self) -> u64 {
         let bits: u32 = unsafe { transmute(self) };
         bits as u64
@@ -171,7 +183,7 @@ impl RawFloat for f32 {
     }
 
     fn unpack(self) -> Unpacked {
-        let (sig, exp, _sig) = self.integer_decode2();
+        let (sig, exp, _sig) = self.integer_decode();
         Unpacked::new(sig, exp)
     }
 
@@ -196,6 +208,21 @@ impl RawFloat for f64 {
     const ZERO_CUTOFF: i64 = -326;
     other_constants!(f64);
 
+    /// Returns the mantissa, exponent and sign as integers.
+    fn integer_decode(self) -> (u64, i16, i8) {
+        let bits: u64 = unsafe { transmute(self) };
+        let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
+        let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
+        let mantissa = if exponent == 0 {
+            (bits & 0xfffffffffffff) << 1
+        } else {
+            (bits & 0xfffffffffffff) | 0x10000000000000
+        };
+        // Exponent bias + mantissa shift
+        exponent -= 1023 + 52;
+        (mantissa, exponent, sign)
+    }
+
     fn transmute(self) -> u64 {
         let bits: u64 = unsafe { transmute(self) };
         bits
@@ -206,7 +233,7 @@ impl RawFloat for f64 {
     }
 
     fn unpack(self) -> Unpacked {
-        let (sig, exp, _sig) = self.integer_decode2();
+        let (sig, exp, _sig) = self.integer_decode();
         Unpacked::new(sig, exp)
     }
 
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index 4527d46a27d..91ca213e96e 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -143,36 +143,6 @@ pub mod consts {
            reason = "stable interface is via `impl f{32,64}` in later crates",
            issue = "32110")]
 impl Float for f32 {
-    #[inline]
-    fn nan() -> f32 {
-        NAN
-    }
-
-    #[inline]
-    fn infinity() -> f32 {
-        INFINITY
-    }
-
-    #[inline]
-    fn neg_infinity() -> f32 {
-        NEG_INFINITY
-    }
-
-    #[inline]
-    fn zero() -> f32 {
-        0.0
-    }
-
-    #[inline]
-    fn neg_zero() -> f32 {
-        -0.0
-    }
-
-    #[inline]
-    fn one() -> f32 {
-        1.0
-    }
-
     /// Returns `true` if the number is NaN.
     #[inline]
     fn is_nan(self) -> bool {
@@ -214,21 +184,6 @@ impl Float for f32 {
         }
     }
 
-    /// Returns the mantissa, exponent and sign as integers.
-    fn integer_decode(self) -> (u64, i16, i8) {
-        let bits: u32 = unsafe { mem::transmute(self) };
-        let sign: i8 = if bits >> 31 == 0 { 1 } else { -1 };
-        let mut exponent: i16 = ((bits >> 23) & 0xff) as i16;
-        let mantissa = if exponent == 0 {
-            (bits & 0x7fffff) << 1
-        } else {
-            (bits & 0x7fffff) | 0x800000
-        };
-        // Exponent bias + mantissa shift
-        exponent -= 127 + 23;
-        (mantissa as u64, exponent, sign)
-    }
-
     /// Computes the absolute value of `self`. Returns `Float::nan()` if the
     /// number is `Float::nan()`.
     #[inline]
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 991a8568349..7d6d6cef049 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -143,36 +143,6 @@ pub mod consts {
            reason = "stable interface is via `impl f{32,64}` in later crates",
            issue = "32110")]
 impl Float for f64 {
-    #[inline]
-    fn nan() -> f64 {
-        NAN
-    }
-
-    #[inline]
-    fn infinity() -> f64 {
-        INFINITY
-    }
-
-    #[inline]
-    fn neg_infinity() -> f64 {
-        NEG_INFINITY
-    }
-
-    #[inline]
-    fn zero() -> f64 {
-        0.0
-    }
-
-    #[inline]
-    fn neg_zero() -> f64 {
-        -0.0
-    }
-
-    #[inline]
-    fn one() -> f64 {
-        1.0
-    }
-
     /// Returns `true` if the number is NaN.
     #[inline]
     fn is_nan(self) -> bool {
@@ -214,21 +184,6 @@ impl Float for f64 {
         }
     }
 
-    /// Returns the mantissa, exponent and sign as integers.
-    fn integer_decode(self) -> (u64, i16, i8) {
-        let bits: u64 = unsafe { mem::transmute(self) };
-        let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
-        let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
-        let mantissa = if exponent == 0 {
-            (bits & 0xfffffffffffff) << 1
-        } else {
-            (bits & 0xfffffffffffff) | 0x10000000000000
-        };
-        // Exponent bias + mantissa shift
-        exponent -= 1023 + 52;
-        (mantissa, exponent, sign)
-    }
-
     /// Computes the absolute value of `self`. Returns `Float::nan()` if the
     /// number is `Float::nan()`.
     #[inline]
diff --git a/src/libcore/num/flt2dec/decoder.rs b/src/libcore/num/flt2dec/decoder.rs
index 72529d3da01..b779eefce57 100644
--- a/src/libcore/num/flt2dec/decoder.rs
+++ b/src/libcore/num/flt2dec/decoder.rs
@@ -67,7 +67,7 @@ impl DecodableFloat for f64 {
 /// Returns a sign (true when negative) and `FullDecoded` value
 /// from given floating point number.
 pub fn decode<T: DecodableFloat>(v: T) -> (/*negative?*/ bool, FullDecoded) {
-    let (mant, exp, sign) = v.integer_decode2();
+    let (mant, exp, sign) = v.integer_decode();
     let even = (mant & 1) == 0;
     let decoded = match v.classify() {
         FpCategory::Nan => FullDecoded::Nan,
@@ -81,7 +81,7 @@ pub fn decode<T: DecodableFloat>(v: T) -> (/*negative?*/ bool, FullDecoded) {
                                           exp: exp, inclusive: even })
         }
         FpCategory::Normal => {
-            let minnorm = <T as DecodableFloat>::min_pos_norm_value().integer_decode2();
+            let minnorm = <T as DecodableFloat>::min_pos_norm_value().integer_decode();
             if mant == minnorm.0 {
                 // neighbors: (maxmant, exp - 1) -- (minnormmant, exp) -- (minnormmant + 1, exp)
                 // where maxmant = minnormmant * 2 - 1
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index f665cfdee77..5c4a43fbd11 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -96,78 +96,6 @@ pub mod dec2flt;
 pub mod bignum;
 pub mod diy_float;
 
-/// Types that have a "zero" value.
-///
-/// This trait is intended for use in conjunction with `Add`, as an identity:
-/// `x + T::zero() == x`.
-#[unstable(feature = "zero_one",
-           reason = "unsure of placement, wants to use associated constants",
-           issue = "27739")]
-#[rustc_deprecated(since = "1.11.0", reason = "no longer used for \
-                                               Iterator::sum")]
-pub trait Zero: Sized {
-    /// The "zero" (usually, additive identity) for this type.
-    fn zero() -> Self;
-}
-
-/// Types that have a "one" value.
-///
-/// This trait is intended for use in conjunction with `Mul`, as an identity:
-/// `x * T::one() == x`.
-#[unstable(feature = "zero_one",
-           reason = "unsure of placement, wants to use associated constants",
-           issue = "27739")]
-#[rustc_deprecated(since = "1.11.0", reason = "no longer used for \
-                                               Iterator::product")]
-pub trait One: Sized {
-    /// The "one" (usually, multiplicative identity) for this type.
-    fn one() -> Self;
-}
-
-macro_rules! zero_one_impl {
-    ($($t:ty)*) => ($(
-        #[unstable(feature = "zero_one",
-                   reason = "unsure of placement, wants to use associated constants",
-                   issue = "27739")]
-        #[allow(deprecated)]
-        impl Zero for $t {
-            #[inline]
-            fn zero() -> Self { 0 }
-        }
-        #[unstable(feature = "zero_one",
-                   reason = "unsure of placement, wants to use associated constants",
-                   issue = "27739")]
-        #[allow(deprecated)]
-        impl One for $t {
-            #[inline]
-            fn one() -> Self { 1 }
-        }
-    )*)
-}
-zero_one_impl! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
-
-macro_rules! zero_one_impl_float {
-    ($($t:ty)*) => ($(
-        #[unstable(feature = "zero_one",
-                   reason = "unsure of placement, wants to use associated constants",
-                   issue = "27739")]
-        #[allow(deprecated)]
-        impl Zero for $t {
-            #[inline]
-            fn zero() -> Self { 0.0 }
-        }
-        #[unstable(feature = "zero_one",
-                   reason = "unsure of placement, wants to use associated constants",
-                   issue = "27739")]
-        #[allow(deprecated)]
-        impl One for $t {
-            #[inline]
-            fn one() -> Self { 1.0 }
-        }
-    )*)
-}
-zero_one_impl_float! { f32 f64 }
-
 macro_rules! checked_op {
     ($U:ty, $op:path, $x:expr, $y:expr) => {{
         let (result, overflowed) = unsafe { $op($x as $U, $y as $U) };
@@ -2525,49 +2453,6 @@ pub enum FpCategory {
            reason = "stable interface is via `impl f{32,64}` in later crates",
            issue = "32110")]
 pub trait Float: Sized {
-    /// Returns the NaN value.
-    #[unstable(feature = "float_extras", reason = "needs removal",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn nan() -> Self;
-    /// Returns the infinite value.
-    #[unstable(feature = "float_extras", reason = "needs removal",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn infinity() -> Self;
-    /// Returns the negative infinite value.
-    #[unstable(feature = "float_extras", reason = "needs removal",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn neg_infinity() -> Self;
-    /// Returns -0.0.
-    #[unstable(feature = "float_extras", reason = "needs removal",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn neg_zero() -> Self;
-    /// Returns 0.0.
-    #[unstable(feature = "float_extras", reason = "needs removal",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn zero() -> Self;
-    /// Returns 1.0.
-    #[unstable(feature = "float_extras", reason = "needs removal",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn one() -> Self;
-
     /// Returns `true` if this value is NaN and false otherwise.
     #[stable(feature = "core", since = "1.6.0")]
     fn is_nan(self) -> bool;
@@ -2585,14 +2470,6 @@ pub trait Float: Sized {
     #[stable(feature = "core", since = "1.6.0")]
     fn classify(self) -> FpCategory;
 
-    /// Returns the mantissa, exponent and sign as integers, respectively.
-    #[unstable(feature = "float_extras", reason = "signature is undecided",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    fn integer_decode(self) -> (u64, i16, i8);
-
     /// Computes the absolute value of `self`. Returns `Float::nan()` if the
     /// number is `Float::nan()`.
     #[stable(feature = "core", since = "1.6.0")]
diff --git a/src/libcore/tests/num/dec2flt/rawfp.rs b/src/libcore/tests/num/dec2flt/rawfp.rs
index 1a3533317da..2b0afc40202 100644
--- a/src/libcore/tests/num/dec2flt/rawfp.rs
+++ b/src/libcore/tests/num/dec2flt/rawfp.rs
@@ -8,23 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::f32;
 use std::f64;
-use std::mem;
 use core::num::diy_float::Fp;
 use core::num::dec2flt::rawfp::{fp_to_float, prev_float, next_float, round_normal};
+use core::num::dec2flt::rawfp::RawFloat;
 
 fn integer_decode(f: f64) -> (u64, i16, i8) {
-    let bits: u64 = unsafe { mem::transmute(f) };
-    let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
-    let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
-    let mantissa = if exponent == 0 {
-        (bits & 0xfffffffffffff) << 1
-    } else {
-        (bits & 0xfffffffffffff) | 0x10000000000000
-    };
-    // Exponent bias + mantissa shift
-    exponent -= 1023 + 52;
-    (mantissa, exponent, sign)
+    RawFloat::integer_decode(f)
 }
 
 #[test]
@@ -152,3 +143,35 @@ fn next_float_monotonic() {
     }
     assert!(x > 0.5);
 }
+
+#[test]
+fn test_f32_integer_decode() {
+    assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1));
+    assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1));
+    assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1));
+    assert_eq!(0f32.integer_decode(), (0, -150, 1));
+    assert_eq!((-0f32).integer_decode(), (0, -150, -1));
+    assert_eq!(f32::INFINITY.integer_decode(), (8388608, 105, 1));
+    assert_eq!(f32::NEG_INFINITY.integer_decode(), (8388608, 105, -1));
+
+    // Ignore the "sign" (quiet / signalling flag) of NAN.
+    // It can vary between runtime operations and LLVM folding.
+    let (nan_m, nan_e, _nan_s) = f32::NAN.integer_decode();
+    assert_eq!((nan_m, nan_e), (12582912, 105));
+}
+
+#[test]
+fn test_f64_integer_decode() {
+    assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1));
+    assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1));
+    assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1));
+    assert_eq!(0f64.integer_decode(), (0, -1075, 1));
+    assert_eq!((-0f64).integer_decode(), (0, -1075, -1));
+    assert_eq!(f64::INFINITY.integer_decode(), (4503599627370496, 972, 1));
+    assert_eq!(f64::NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1));
+
+    // Ignore the "sign" (quiet / signalling flag) of NAN.
+    // It can vary between runtime operations and LLVM folding.
+    let (nan_m, nan_e, _nan_s) = f64::NAN.integer_decode();
+    assert_eq!((nan_m, nan_e), (6755399441055744, 972));
+}
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index fd9750dbfe3..33133f6834b 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -88,15 +88,17 @@ pub enum DepNode<D: Clone + Debug> {
     // predicates for an item wind up in `ItemSignature`).
     AssociatedItems(D),
     ItemSignature(D),
+    IsForeignItem(D),
     TypeParamPredicates((D, D)),
     SizedConstraint(D),
+    DtorckConstraint(D),
     AdtDestructor(D),
     AssociatedItemDefIds(D),
     InherentImpls(D),
     TypeckBodiesKrate,
     TypeckTables(D),
     UsedTraitImports(D),
-    MonomorphicConstEval(D),
+    ConstEval(D),
 
     // The set of impls for a given trait. Ultimately, it would be
     // nice to get more fine-grained here (e.g., to include a
@@ -171,6 +173,7 @@ impl<D: Clone + Debug> DepNode<D> {
             TransCrateItem,
             AssociatedItems,
             ItemSignature,
+            IsForeignItem,
             AssociatedItemDefIds,
             InherentImpls,
             TypeckTables,
@@ -221,16 +224,18 @@ impl<D: Clone + Debug> DepNode<D> {
             TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
             AssociatedItems(ref d) => op(d).map(AssociatedItems),
             ItemSignature(ref d) => op(d).map(ItemSignature),
+            IsForeignItem(ref d) => op(d).map(IsForeignItem),
             TypeParamPredicates((ref item, ref param)) => {
                 Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
             }
             SizedConstraint(ref d) => op(d).map(SizedConstraint),
+            DtorckConstraint(ref d) => op(d).map(DtorckConstraint),
             AdtDestructor(ref d) => op(d).map(AdtDestructor),
             AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
             InherentImpls(ref d) => op(d).map(InherentImpls),
             TypeckTables(ref d) => op(d).map(TypeckTables),
             UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
-            MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval),
+            ConstEval(ref d) => op(d).map(ConstEval),
             TraitImpls(ref d) => op(d).map(TraitImpls),
             TraitItems(ref d) => op(d).map(TraitItems),
             ReprHints(ref d) => op(d).map(ReprHints),
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index 2851191dc14..30e9f502abc 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -1829,6 +1829,7 @@ register_diagnostics! {
     E0314, // closure outlives stack frame
     E0315, // cannot invoke closure outside of its lifetime
     E0316, // nested quantification of lifetimes
+    E0320, // recursive overflow during dropck
     E0473, // dereference of reference outside its lifetime
     E0474, // captured variable `..` does not outlive the enclosing closure
     E0475, // index of slice outside its lifetime
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index f55462fb5de..16af98c2035 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -273,6 +273,12 @@ for ::middle::const_val::ConstVal<'tcx> {
             ConstVal::Bool(value) => {
                 value.hash_stable(hcx, hasher);
             }
+            ConstVal::Char(value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Variant(def_id) => {
+                def_id.hash_stable(hcx, hasher);
+            }
             ConstVal::Function(def_id, substs) => {
                 def_id.hash_stable(hcx, hasher);
                 substs.hash_stable(hcx, hasher);
@@ -296,9 +302,6 @@ for ::middle::const_val::ConstVal<'tcx> {
                 value.hash_stable(hcx, hasher);
                 times.hash_stable(hcx, hasher);
             }
-            ConstVal::Char(value) => {
-                value.hash_stable(hcx, hasher);
-            }
         }
     }
 }
diff --git a/src/librustc/infer/freshen.rs b/src/librustc/infer/freshen.rs
index 697a1ecadc4..922842136dc 100644
--- a/src/librustc/infer/freshen.rs
+++ b/src/librustc/infer/freshen.rs
@@ -99,7 +99,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for TypeFreshener<'a, 'gcx, 'tcx> {
             ty::ReEmpty |
             ty::ReErased => {
                 // replace all free regions with 'erased
-                self.tcx().mk_region(ty::ReErased)
+                self.tcx().types.re_erased
             }
         }
     }
diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs
index 0bb9e2c7fa1..fa6775737b5 100644
--- a/src/librustc/infer/region_inference/mod.rs
+++ b/src/librustc/infer/region_inference/mod.rs
@@ -948,7 +948,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                 } else {
                     // otherwise, we don't know what the free region is,
                     // so we must conservatively say the LUB is static:
-                    self.tcx.mk_region(ReStatic)
+                    self.tcx.types.re_static
                 }
             }
 
@@ -971,7 +971,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
                 if a == b {
                     a
                 } else {
-                    self.tcx.mk_region(ReStatic)
+                    self.tcx.types.re_static
                 }
             }
         }
@@ -1018,7 +1018,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
 
     fn construct_var_data(&self) -> Vec<VarValue<'tcx>> {
         (0..self.num_vars() as usize)
-            .map(|_| Value(self.tcx.mk_region(ty::ReEmpty)))
+            .map(|_| Value(self.tcx.types.re_empty))
             .collect()
     }
 
@@ -1493,7 +1493,7 @@ fn lookup<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                           -> &'tcx ty::Region {
     match values[rid.index as usize] {
         Value(r) => r,
-        ErrorValue => tcx.mk_region(ReStatic), // Previously reported error.
+        ErrorValue => tcx.types.re_static, // Previously reported error.
     }
 }
 
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index b4c5af94019..ec7b3c4dd8d 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -38,12 +38,13 @@ pub enum ConstVal<'tcx> {
     Str(InternedString),
     ByteStr(Rc<Vec<u8>>),
     Bool(bool),
+    Char(char),
+    Variant(DefId),
     Function(DefId, &'tcx Substs<'tcx>),
     Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
     Tuple(Vec<ConstVal<'tcx>>),
     Array(Vec<ConstVal<'tcx>>),
     Repeat(Box<ConstVal<'tcx>>, u64),
-    Char(char),
 }
 
 impl<'tcx> ConstVal<'tcx> {
@@ -54,12 +55,13 @@ impl<'tcx> ConstVal<'tcx> {
             Str(_) => "string literal",
             ByteStr(_) => "byte string literal",
             Bool(_) => "boolean",
+            Char(..) => "char",
+            Variant(_) => "enum variant",
             Struct(_) => "struct",
             Tuple(_) => "tuple",
             Function(..) => "function definition",
             Array(..) => "array",
             Repeat(..) => "repeat",
-            Char(..) => "char",
         }
     }
 
@@ -85,7 +87,6 @@ pub enum ErrKind<'tcx> {
     MissingStructField,
     NegateOn(ConstVal<'tcx>),
     NotOn(ConstVal<'tcx>),
-    CallOn(ConstVal<'tcx>),
 
     NonConstPath,
     UnimplementedConstVal(&'static str),
@@ -145,7 +146,6 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
             CannotCast => simple!("can't cast this type"),
             NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
             NotOn(ref const_val) => simple!("not on {}", const_val.description()),
-            CallOn(ref const_val) => simple!("call on {}", const_val.description()),
 
             MissingStructField  => simple!("nonexistent struct field"),
             NonConstPath        => simple!("non-constant path in constant expression"),
@@ -227,7 +227,8 @@ pub fn eval_length(tcx: TyCtxt,
 {
     let count_expr = &tcx.hir.body(count).value;
     let count_def_id = tcx.hir.body_owner_def_id(count);
-    match ty::queries::monomorphic_const_eval::get(tcx, count_expr.span, count_def_id) {
+    let substs = Substs::empty();
+    match ty::queries::const_eval::get(tcx, count_expr.span, (count_def_id, substs)) {
         Ok(Integral(Usize(count))) => {
             let val = count.as_u64(tcx.sess.target.uint_type);
             assert_eq!(val as usize as u64, val);
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index cbbfeacadb4..3251addcb32 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -188,14 +188,13 @@ pub trait CrateStore {
     fn visibility(&self, def: DefId) -> ty::Visibility;
     fn visible_parent_map<'a>(&'a self) -> ::std::cell::Ref<'a, DefIdMap<DefId>>;
     fn item_generics_cloned(&self, def: DefId) -> ty::Generics;
-    fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
+    fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]>;
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>;
 
     // trait info
     fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
 
     // impl info
-    fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity;
     fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
 
     // trait/impl-item info
@@ -250,8 +249,8 @@ pub trait CrateStore {
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
 
     // misc. metadata
-    fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                     -> Option<&'tcx hir::Body>;
+    fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                           -> &'tcx hir::Body;
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body>;
     fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool;
 
@@ -323,14 +322,13 @@ impl CrateStore for DummyCrateStore {
     }
     fn item_generics_cloned(&self, def: DefId) -> ty::Generics
         { bug!("item_generics_cloned") }
-    fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
+    fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]> { bug!("item_attrs") }
     fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name> { bug!("fn_arg_names") }
 
     // trait info
     fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }
 
     // impl info
-    fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") }
     fn impl_parent(&self, def: DefId) -> Option<DefId> { bug!("impl_parent") }
 
     // trait/impl-item info
@@ -401,9 +399,9 @@ impl CrateStore for DummyCrateStore {
     fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
 
     // misc. metadata
-    fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
-                                     -> Option<&'tcx hir::Body> {
-        bug!("maybe_get_item_body")
+    fn item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+                           -> &'tcx hir::Body {
+        bug!("item_body")
     }
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
         bug!("item_body_nested_bodies")
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index a10f52e2d4c..8b263159158 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -426,7 +426,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
 
             hir::ExprMatch(ref discr, ref arms, _) => {
                 let discr_cmt = return_if_err!(self.mc.cat_expr(&discr));
-                let r = self.tcx().mk_region(ty::ReEmpty);
+                let r = self.tcx().types.re_empty;
                 self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant);
 
                 // treatment of the discriminant is handled while walking the arms.
diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs
index 32dfb63d615..3b506d748ef 100644
--- a/src/librustc/middle/lang_items.rs
+++ b/src/librustc/middle/lang_items.rs
@@ -223,9 +223,10 @@ impl<'a, 'tcx> LanguageItemCollector<'a, 'tcx> {
 
 pub fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
     for attribute in attrs {
-        match attribute.value_str() {
-            Some(value) if attribute.check_name("lang") => return Some(value),
-            _ => {}
+        if attribute.check_name("lang") {
+            if let Some(value) = attribute.value_str() {
+                return Some(value)
+            }
         }
     }
 
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 7d3c17a0489..188fcc91414 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -871,8 +871,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
         // we can promote to a constant, otherwise equal to enclosing temp
         // lifetime.
         let (re, old_re) = if promotable {
-            (self.tcx().mk_region(ty::ReStatic),
-             self.tcx().mk_region(ty::ReStatic))
+            (self.tcx().types.re_static,
+             self.tcx().types.re_static)
         } else {
             self.temporary_scope(id)
         };
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 63455f94ced..be4ec16cd63 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -18,6 +18,7 @@
 use hir::map as hir_map;
 use hir::def::Def;
 use hir::def_id::{DefId, CrateNum};
+use std::rc::Rc;
 use ty::{self, TyCtxt};
 use ty::maps::Providers;
 use middle::privacy;
@@ -362,11 +363,11 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a,
     }
 }
 
-pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet {
+pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc<NodeSet> {
     ty::queries::reachable_set::get(tcx, DUMMY_SP, LOCAL_CRATE)
 }
 
-fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> NodeSet {
+fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> Rc<NodeSet> {
     debug_assert!(crate_num == LOCAL_CRATE);
 
     let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE);
@@ -411,7 +412,7 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) ->
     reachable_context.propagate();
 
     // Return the set of reachable symbols.
-    reachable_context.reachable_symbols
+    Rc::new(reachable_context.reachable_symbols)
 }
 
 pub fn provide(providers: &mut Providers) {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 9ff64b295b7..bfb72b5df7b 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -1307,10 +1307,11 @@ fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ConstVal) -> fmt::Result {
             write!(fmt, "b\"{}\"", escaped)
         }
         Bool(b) => write!(fmt, "{:?}", b),
+        Char(c) => write!(fmt, "{:?}", c),
+        Variant(def_id) |
         Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
         Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
             bug!("ConstVal `{:?}` should not be in MIR", const_val),
-        Char(c) => write!(fmt, "{:?}", c),
     }
 }
 
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index d49affa3e87..908bb337fa1 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -443,7 +443,7 @@ fn process_predicate<'a, 'gcx, 'tcx>(
                         // Otherwise, we have something of the form
                         // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`.
                         Some(t_a) => {
-                            let r_static = selcx.tcx().mk_region(ty::ReStatic);
+                            let r_static = selcx.tcx().types.re_static;
                             register_region_obligation(t_a, r_static,
                                                        obligation.cause.clone(),
                                                        region_obligations);
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 0ff379b30ff..281c1e25379 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -55,6 +55,7 @@ mod object_safety;
 mod select;
 mod specialize;
 mod structural_impls;
+pub mod trans;
 mod util;
 
 /// An `Obligation` represents some trait reference (e.g. `int:Eq`) for
@@ -628,7 +629,7 @@ pub fn get_vtable_methods<'a, 'tcx>(
             // the method may have some early-bound lifetimes, add
             // regions for those
             let substs = Substs::for_item(tcx, def_id,
-                                          |_, _| tcx.mk_region(ty::ReErased),
+                                          |_, _| tcx.types.re_erased,
                                           |def, _| trait_ref.substs().type_for_def(def));
 
             // the trait type may have higher-ranked lifetimes in it;
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 70ddcff5181..207016170fa 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -943,17 +943,17 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                     debug!("Retaining candidate #{}/{}: {:?}",
                            i, candidates.len(), candidates[i]);
                     i += 1;
+
+                    // If there are *STILL* multiple candidates, give up
+                    // and report ambiguity.
+                    if i > 1 {
+                        debug!("multiple matches, ambig");
+                        return Ok(None);
+                    }
                 }
             }
         }
 
-        // If there are *STILL* multiple candidates, give up and
-        // report ambiguity.
-        if candidates.len() > 1 {
-            debug!("multiple matches, ambig");
-            return Ok(None);
-        }
-
         // If there are *NO* candidates, then there are no impls --
         // that we know of, anyway. Note that in the case where there
         // are unbound type variables within the obligation, it might
@@ -1300,8 +1300,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
                             .iter()
                             .filter_map(|o| o.to_opt_poly_trait_ref());
 
+        // micro-optimization: filter out predicates relating to different
+        // traits.
+        let matching_bounds =
+            all_bounds.filter(|p| p.def_id() == stack.obligation.predicate.def_id());
+
         let matching_bounds =
-            all_bounds.filter(
+            matching_bounds.filter(
                 |bound| self.evaluate_where_clause(stack, bound.clone()).may_apply());
 
         let param_candidates =
@@ -1790,11 +1795,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
             ty::TyAdt(def, substs) => {
                 let sized_crit = def.sized_constraint(self.tcx());
                 // (*) binder moved here
-                Where(ty::Binder(match sized_crit.sty {
-                    ty::TyTuple(tys, _) => tys.to_vec().subst(self.tcx(), substs),
-                    ty::TyBool => vec![],
-                    _ => vec![sized_crit.subst(self.tcx(), substs)]
-                }))
+                Where(ty::Binder(
+                    sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect()
+                ))
             }
 
             ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None,
diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs
new file mode 100644
index 00000000000..e38306aed2a
--- /dev/null
+++ b/src/librustc/traits/trans/mod.rs
@@ -0,0 +1,212 @@
+// 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 file contains various trait resolution methods used by trans.
+// They all assume regions can be erased and monomorphic types.  It
+// seems likely that they should eventually be merged into more
+// general routines.
+
+use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig};
+use hir::def_id::DefId;
+use infer::TransNormalize;
+use std::cell::RefCell;
+use std::marker::PhantomData;
+use syntax::ast;
+use syntax_pos::Span;
+use traits::{FulfillmentContext, Obligation, ObligationCause, Reveal, SelectionContext, Vtable};
+use ty::{self, Ty, TyCtxt};
+use ty::subst::{Subst, Substs};
+use ty::fold::{TypeFoldable, TypeFolder};
+use util::common::MemoizationMap;
+
+impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
+    /// Attempts to resolve an obligation to a vtable.. The result is
+    /// a shallow vtable resolution -- meaning that we do not
+    /// (necessarily) resolve all nested obligations on the impl. Note
+    /// that type check should guarantee to us that all nested
+    /// obligations *could be* resolved if we wanted to.
+    pub fn trans_fulfill_obligation(self,
+                                    span: Span,
+                                    trait_ref: ty::PolyTraitRef<'tcx>)
+                                    -> Vtable<'tcx, ()>
+    {
+        // Remove any references to regions; this helps improve caching.
+        let trait_ref = self.erase_regions(&trait_ref);
+
+        self.trans_trait_caches.trait_cache.memoize(trait_ref, || {
+            debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
+                   trait_ref, trait_ref.def_id());
+
+            // Do the initial selection for the obligation. This yields the
+            // shallow result we are looking for -- that is, what specific impl.
+            self.infer_ctxt((), Reveal::All).enter(|infcx| {
+                let mut selcx = SelectionContext::new(&infcx);
+
+                let obligation_cause = ObligationCause::misc(span,
+                                                             ast::DUMMY_NODE_ID);
+                let obligation = Obligation::new(obligation_cause,
+                                                 trait_ref.to_poly_trait_predicate());
+
+                let selection = match selcx.select(&obligation) {
+                    Ok(Some(selection)) => selection,
+                    Ok(None) => {
+                        // Ambiguity can happen when monomorphizing during trans
+                        // expands to some humongo type that never occurred
+                        // statically -- this humongo type can then overflow,
+                        // leading to an ambiguous result. So report this as an
+                        // overflow bug, since I believe this is the only case
+                        // where ambiguity can result.
+                        debug!("Encountered ambiguity selecting `{:?}` during trans, \
+                                presuming due to overflow",
+                               trait_ref);
+                        self.sess.span_fatal(span,
+                                            "reached the recursion limit during monomorphization \
+                                             (selection ambiguity)");
+                    }
+                    Err(e) => {
+                        span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans",
+                                  e, trait_ref)
+                    }
+                };
+
+                debug!("fulfill_obligation: selection={:?}", selection);
+
+                // Currently, we use a fulfillment context to completely resolve
+                // all nested obligations. This is because they can inform the
+                // inference of the impl's type parameters.
+                let mut fulfill_cx = FulfillmentContext::new();
+                let vtable = selection.map(|predicate| {
+                    debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
+                    fulfill_cx.register_predicate_obligation(&infcx, predicate);
+                });
+                let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable);
+
+                info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
+                vtable
+            })
+        })
+    }
+
+    /// Monomorphizes a type from the AST by first applying the in-scope
+    /// substitutions and then normalizing any associated types.
+    pub fn trans_apply_param_substs<T>(self,
+                                       param_substs: &Substs<'tcx>,
+                                       value: &T)
+                                       -> T
+        where T: TransNormalize<'tcx>
+    {
+        debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value);
+        let substituted = value.subst(self, param_substs);
+        let substituted = self.erase_regions(&substituted);
+        AssociatedTypeNormalizer::new(self).fold(&substituted)
+    }
+}
+
+struct AssociatedTypeNormalizer<'a, 'gcx: 'a> {
+    tcx: TyCtxt<'a, 'gcx, 'gcx>,
+}
+
+impl<'a, 'gcx> AssociatedTypeNormalizer<'a, 'gcx> {
+    fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>) -> Self {
+        AssociatedTypeNormalizer { tcx }
+    }
+
+    fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
+        if !value.has_projection_types() {
+            value.clone()
+        } else {
+            value.fold_with(self)
+        }
+    }
+}
+
+impl<'a, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'gcx> {
+    fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> {
+        self.tcx
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
+        if !ty.has_projection_types() {
+            ty
+        } else {
+            self.tcx.trans_trait_caches.project_cache.memoize(ty, || {
+                debug!("AssociatedTypeNormalizer: ty={:?}", ty);
+                self.tcx.normalize_associated_type(&ty)
+            })
+        }
+    }
+}
+
+/// Specializes caches used in trans -- in particular, they assume all
+/// types are fully monomorphized and that free regions can be erased.
+pub struct TransTraitCaches<'tcx> {
+    trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
+    project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
+}
+
+impl<'tcx> TransTraitCaches<'tcx> {
+    pub fn new(graph: DepGraph) -> Self {
+        TransTraitCaches {
+            trait_cache: RefCell::new(DepTrackingMap::new(graph.clone())),
+            project_cache: RefCell::new(DepTrackingMap::new(graph)),
+        }
+    }
+}
+
+// Implement DepTrackingMapConfig for `trait_cache`
+pub struct TraitSelectionCache<'tcx> {
+    data: PhantomData<&'tcx ()>
+}
+
+impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
+    type Key = ty::PolyTraitRef<'tcx>;
+    type Value = Vtable<'tcx, ()>;
+    fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode<DefId> {
+        key.to_poly_trait_predicate().dep_node()
+    }
+}
+
+// # Global Cache
+
+pub struct ProjectionCache<'gcx> {
+    data: PhantomData<&'gcx ()>
+}
+
+impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
+    type Key = Ty<'gcx>;
+    type Value = Ty<'gcx>;
+    fn to_dep_node(key: &Self::Key) -> DepNode<DefId> {
+        // Ideally, we'd just put `key` into the dep-node, but we
+        // can't put full types in there. So just collect up all the
+        // def-ids of structs/enums as well as any traits that we
+        // project out of. It doesn't matter so much what we do here,
+        // except that if we are too coarse, we'll create overly
+        // coarse edges between impls and the trans. For example, if
+        // we just used the def-id of things we are projecting out of,
+        // then the key for `<Foo as SomeTrait>::T` and `<Bar as
+        // SomeTrait>::T` would both share a dep-node
+        // (`TraitSelect(SomeTrait)`), and hence the impls for both
+        // `Foo` and `Bar` would be considered inputs. So a change to
+        // `Bar` would affect things that just normalized `Foo`.
+        // Anyway, this heuristic is not ideal, but better than
+        // nothing.
+        let def_ids: Vec<DefId> =
+            key.walk()
+               .filter_map(|t| match t.sty {
+                   ty::TyAdt(adt_def, _) => Some(adt_def.did),
+                   ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id),
+                   _ => None,
+               })
+               .collect();
+
+        DepNode::ProjectionCache { def_ids: def_ids }
+    }
+}
+
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index a4162925871..b20ac8ddbfc 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -190,6 +190,10 @@ pub struct CommonTypes<'tcx> {
     pub f64: Ty<'tcx>,
     pub never: Ty<'tcx>,
     pub err: Ty<'tcx>,
+
+    pub re_empty: &'tcx Region,
+    pub re_static: &'tcx Region,
+    pub re_erased: &'tcx Region,
 }
 
 #[derive(RustcEncodable, RustcDecodable)]
@@ -360,6 +364,14 @@ impl<'tcx> TypeckTables<'tcx> {
 impl<'tcx> CommonTypes<'tcx> {
     fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> {
         let mk = |sty| interners.intern_ty(sty, None);
+        let mk_region = |r| {
+            if let Some(r) = interners.region.borrow().get(&r) {
+                return r.0;
+            }
+            let r = interners.arena.alloc(r);
+            interners.region.borrow_mut().insert(Interned(r));
+            &*r
+        };
         CommonTypes {
             bool: mk(TyBool),
             char: mk(TyChar),
@@ -379,6 +391,10 @@ impl<'tcx> CommonTypes<'tcx> {
             u128: mk(TyUint(ast::UintTy::U128)),
             f32: mk(TyFloat(ast::FloatTy::F32)),
             f64: mk(TyFloat(ast::FloatTy::F64)),
+
+            re_empty: mk_region(Region::ReEmpty),
+            re_static: mk_region(Region::ReStatic),
+            re_erased: mk_region(Region::ReErased),
         }
     }
 }
@@ -407,6 +423,8 @@ pub struct GlobalCtxt<'tcx> {
 
     pub specializes_cache: RefCell<traits::SpecializesCache>,
 
+    pub trans_trait_caches: traits::trans::TransTraitCaches<'tcx>,
+
     pub dep_graph: DepGraph,
 
     /// Common types, pre-interned for your convenience.
@@ -689,6 +707,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         providers[LOCAL_CRATE] = local_providers;
         tls::enter_global(GlobalCtxt {
             sess: s,
+            trans_trait_caches: traits::trans::TransTraitCaches::new(dep_graph.clone()),
             specializes_cache: RefCell::new(traits::SpecializesCache::new()),
             global_arenas: arenas,
             global_interners: interners,
@@ -1229,7 +1248,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn mk_static_str(self) -> Ty<'tcx> {
-        self.mk_imm_ref(self.mk_region(ty::ReStatic), self.mk_str())
+        self.mk_imm_ref(self.types.re_static, self.mk_str())
     }
 
     pub fn mk_adt(self, def: &'tcx AdtDef, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> {
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index e29653c9e88..969d040e7a6 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -410,7 +410,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T
         where T : TypeFoldable<'tcx>
     {
-        self.replace_late_bound_regions(value, |_| self.mk_region(ty::ReErased)).0
+        self.replace_late_bound_regions(value, |_| self.types.re_erased).0
     }
 
     /// Rewrite any late-bound regions so that they are anonymous.  Region numbers are
@@ -538,7 +538,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 // whenever a substitution occurs.
                 match *r {
                     ty::ReLateBound(..) => r,
-                    _ => self.tcx().mk_region(ty::ReErased)
+                    _ => self.tcx().types.re_erased
                 }
             }
         }
@@ -565,6 +565,22 @@ pub fn shift_region(region: ty::Region, amount: u32) -> ty::Region {
     }
 }
 
+pub fn shift_region_ref<'a, 'gcx, 'tcx>(
+    tcx: TyCtxt<'a, 'gcx, 'tcx>,
+    region: &'tcx ty::Region,
+    amount: u32)
+    -> &'tcx ty::Region
+{
+    match region {
+        &ty::ReLateBound(debruijn, br) if amount > 0 => {
+            tcx.mk_region(ty::ReLateBound(debruijn.shifted(amount), br))
+        }
+        _ => {
+            region
+        }
+    }
+}
+
 pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
                                         amount: u32, value: &T) -> T
     where T: TypeFoldable<'tcx>
@@ -573,7 +589,7 @@ pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
            value, amount);
 
     value.fold_with(&mut RegionFolder::new(tcx, &mut false, &mut |region, _current_depth| {
-        tcx.mk_region(shift_region(*region, amount))
+        shift_region_ref(tcx, region, amount)
     }))
 }
 
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index 67287f1b4ff..cfff3d0e573 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -13,10 +13,7 @@ use hir::def_id::DefId;
 use ty::{self, Ty, TypeFoldable, Substs};
 use util::ppaux;
 
-use std::borrow::Cow;
 use std::fmt;
-use syntax::ast;
-
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub struct Instance<'tcx> {
@@ -59,7 +56,7 @@ impl<'tcx> InstanceDef<'tcx> {
     }
 
     #[inline]
-    pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Cow<'tcx, [ast::Attribute]> {
+    pub fn attrs<'a>(&self, tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> ty::Attributes<'tcx> {
         tcx.get_attrs(self.def_id())
     }
 
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 6a206640b3b..49cc4e7c993 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -822,7 +822,7 @@ impl<'a, 'gcx, 'tcx> Struct {
             }
 
             (_, &ty::TyProjection(_)) | (_, &ty::TyAnon(..)) => {
-                let normalized = normalize_associated_type(infcx, ty);
+                let normalized = infcx.normalize_projections(ty);
                 if ty == normalized {
                     return Ok(None);
                 }
@@ -1067,28 +1067,6 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
     }
 }
 
-/// Helper function for normalizing associated types in an inference context.
-fn normalize_associated_type<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
-                                             ty: Ty<'gcx>)
-                                             -> Ty<'gcx> {
-    if !ty.has_projection_types() {
-        return ty;
-    }
-
-    let mut selcx = traits::SelectionContext::new(infcx);
-    let cause = traits::ObligationCause::dummy();
-    let traits::Normalized { value: result, obligations } =
-        traits::normalize(&mut selcx, cause, &ty);
-
-    let mut fulfill_cx = traits::FulfillmentContext::new();
-
-    for obligation in obligations {
-        fulfill_cx.register_predicate_obligation(infcx, obligation);
-    }
-
-    infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
-}
-
 impl<'a, 'gcx, 'tcx> Layout {
     pub fn compute_uncached(ty: Ty<'gcx>,
                             infcx: &InferCtxt<'a, 'gcx, 'tcx>)
@@ -1100,7 +1078,7 @@ impl<'a, 'gcx, 'tcx> Layout {
 
         let ptr_layout = |pointee: Ty<'gcx>| {
             let non_zero = !ty.is_unsafe_ptr();
-            let pointee = normalize_associated_type(infcx, pointee);
+            let pointee = infcx.normalize_projections(pointee);
             if pointee.is_sized(tcx, &infcx.parameter_environment, DUMMY_SP) {
                 Ok(Scalar { value: Pointer, non_zero: non_zero })
             } else {
@@ -1494,7 +1472,7 @@ impl<'a, 'gcx, 'tcx> Layout {
 
             // Types with no meaningful known layout.
             ty::TyProjection(_) | ty::TyAnon(..) => {
-                let normalized = normalize_associated_type(infcx, ty);
+                let normalized = infcx.normalize_projections(ty);
                 if ty == normalized {
                     return Err(LayoutError::Unknown(ty));
                 }
@@ -1812,7 +1790,7 @@ impl<'a, 'gcx, 'tcx> SizeSkeleton<'gcx> {
             }
 
             ty::TyProjection(_) | ty::TyAnon(..) => {
-                let normalized = normalize_associated_type(infcx, ty);
+                let normalized = infcx.normalize_projections(ty);
                 if ty == normalized {
                     Err(err)
                 } else {
@@ -1882,13 +1860,14 @@ pub trait LayoutTyper<'tcx>: HasTyCtxt<'tcx> {
     type TyLayout;
 
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout;
+    fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx>;
 }
 
 impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
     type TyLayout = Result<TyLayout<'gcx>, LayoutError<'gcx>>;
 
     fn layout_of(self, ty: Ty<'gcx>) -> Self::TyLayout {
-        let ty = normalize_associated_type(self, ty);
+        let ty = self.normalize_projections(ty);
 
         Ok(TyLayout {
             ty: ty,
@@ -1896,6 +1875,25 @@ impl<'a, 'gcx, 'tcx> LayoutTyper<'gcx> for &'a InferCtxt<'a, 'gcx, 'tcx> {
             variant_index: None
         })
     }
+
+    fn normalize_projections(self, ty: Ty<'gcx>) -> Ty<'gcx> {
+        if !ty.has_projection_types() {
+            return ty;
+        }
+
+        let mut selcx = traits::SelectionContext::new(self);
+        let cause = traits::ObligationCause::dummy();
+        let traits::Normalized { value: result, obligations } =
+            traits::normalize(&mut selcx, cause, &ty);
+
+        let mut fulfill_cx = traits::FulfillmentContext::new();
+
+        for obligation in obligations {
+            fulfill_cx.register_predicate_obligation(self, obligation);
+        }
+
+        self.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &result)
+    }
 }
 
 impl<'a, 'tcx> TyLayout<'tcx> {
@@ -2019,6 +2017,6 @@ impl<'a, 'tcx> TyLayout<'tcx> {
     }
 
     pub fn field<C: LayoutTyper<'tcx>>(&self, cx: C, i: usize) -> C::TyLayout {
-        cx.layout_of(self.field_type(cx, i))
+        cx.layout_of(cx.normalize_projections(self.field_type(cx, i)))
     }
 }
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index e9eb5e97582..4595a8c4f77 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -10,11 +10,13 @@
 
 use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig};
 use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use hir;
 use middle::const_val;
 use middle::privacy::AccessLevels;
 use mir;
 use session::CompileResult;
 use ty::{self, CrateInherentImpls, Ty, TyCtxt};
+use ty::subst::Substs;
 use util::nodemap::NodeSet;
 
 use rustc_data_structures::indexed_vec::IndexVec;
@@ -73,6 +75,15 @@ impl Key for (CrateNum, DefId) {
     }
 }
 
+impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) {
+    fn map_crate(&self) -> CrateNum {
+        self.0.krate
+    }
+    fn default_span(&self, tcx: TyCtxt) -> Span {
+        self.0.default_span(tcx)
+    }
+}
+
 trait Value<'tcx>: Sized {
     fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
 }
@@ -96,6 +107,13 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> {
     }
 }
 
+
+impl<'tcx> Value<'tcx> for ty::DtorckConstraint<'tcx> {
+    fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+        Self::empty()
+    }
+}
+
 pub struct CycleError<'a, 'tcx: 'a> {
     span: Span,
     cycle: RefMut<'a, [(Span, Query<'tcx>)]>,
@@ -216,6 +234,13 @@ impl<'tcx> QueryDescription for queries::reachable_set<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::const_eval<'tcx> {
+    fn describe(tcx: TyCtxt, (def_id, _): (DefId, &'tcx Substs<'tcx>)) -> String {
+        format!("const-evaluating `{}`",
+                tcx.item_path_str(def_id))
+    }
+}
+
 macro_rules! define_maps {
     (<$tcx:tt>
      $($(#[$attr:meta])*
@@ -378,7 +403,11 @@ define_maps! { <'tcx>
     pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
     pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
     pub adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
-    pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>,
+    pub adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
+    pub adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>,
+
+    /// True if this is a foreign item (i.e., linked via `extern { ... }`).
+    pub is_foreign_item: IsForeignItem(DefId) -> bool,
 
     /// Maps from def-id of a type or region parameter to its
     /// (inferred) variance.
@@ -391,6 +420,7 @@ define_maps! { <'tcx>
     pub associated_item: AssociatedItems(DefId) -> ty::AssociatedItem,
 
     pub impl_trait_ref: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>>,
+    pub impl_polarity: ItemSignature(DefId) -> hir::ImplPolarity,
 
     /// Maps a DefId of a type to a list of its inherent impls.
     /// Contains implementations of methods that are inherent to a type.
@@ -441,16 +471,17 @@ define_maps! { <'tcx>
     /// (Defined only for LOCAL_CRATE)
     pub crate_inherent_impls_overlap_check: crate_inherent_impls_dep_node(CrateNum) -> (),
 
-    /// Results of evaluating monomorphic constants embedded in
-    /// other items, such as enum variant explicit discriminants.
-    pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> const_val::EvalResult<'tcx>,
+    /// Results of evaluating const items or constants embedded in
+    /// other items (such as enum variant explicit discriminants).
+    pub const_eval: const_eval_dep_node((DefId, &'tcx Substs<'tcx>))
+        -> const_val::EvalResult<'tcx>,
 
     /// Performs the privacy check and computes "access levels".
     pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc<AccessLevels>,
 
-    pub reachable_set: reachability_dep_node(CrateNum) -> NodeSet,
+    pub reachable_set: reachability_dep_node(CrateNum) -> Rc<NodeSet>,
 
-    pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>
+    pub mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>
 }
 
 fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
@@ -465,10 +496,14 @@ fn reachability_dep_node(_: CrateNum) -> DepNode<DefId> {
     DepNode::Reachability
 }
 
-fn mir_shim(instance: ty::InstanceDef) -> DepNode<DefId> {
+fn mir_shim_dep_node(instance: ty::InstanceDef) -> DepNode<DefId> {
     instance.dep_node()
 }
 
 fn typeck_item_bodies_dep_node(_: CrateNum) -> DepNode<DefId> {
     DepNode::TypeckBodiesKrate
 }
+
+fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode<DefId> {
+    DepNode::ConstEval(def_id)
+}
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 5be73542b93..352b6ab1d35 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -31,14 +31,15 @@ use ty;
 use ty::subst::{Subst, Substs};
 use ty::util::IntTypeExt;
 use ty::walk::TypeWalker;
-use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
+use util::common::ErrorReported;
+use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
 
 use serialize::{self, Encodable, Encoder};
-use std::borrow::Cow;
 use std::cell::{Cell, RefCell, Ref};
 use std::collections::BTreeMap;
 use std::cmp;
 use std::hash::{Hash, Hasher};
+use std::iter::FromIterator;
 use std::ops::Deref;
 use std::rc::Rc;
 use std::slice;
@@ -115,7 +116,7 @@ mod sty;
 #[derive(Clone)]
 pub struct CrateAnalysis {
     pub access_levels: Rc<AccessLevels>,
-    pub reachable: NodeSet,
+    pub reachable: Rc<NodeSet>,
     pub name: String,
     pub glob_map: Option<hir::GlobMap>,
 }
@@ -1333,17 +1334,6 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
 pub struct Destructor {
     /// The def-id of the destructor method
     pub did: DefId,
-    /// Invoking the destructor of a dtorck type during usual cleanup
-    /// (e.g. the glue emitted for stack unwinding) requires all
-    /// lifetimes in the type-structure of `adt` to strictly outlive
-    /// the adt value itself.
-    ///
-    /// If `adt` is not dtorck, then the adt's destructor can be
-    /// invoked even when there are lifetimes in the type-structure of
-    /// `adt` that do not strictly outlive the adt value itself.
-    /// (This allows programs to make cyclic structures without
-    /// resorting to unsafe means; see RFCs 769 and 1238).
-    pub is_dtorck: bool,
 }
 
 bitflags! {
@@ -1610,14 +1600,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         }
     }
 
-    /// Returns whether this is a dtorck type. If this returns
-    /// true, this type being safe for destruction requires it to be
-    /// alive; Otherwise, only the contents are required to be.
-    #[inline]
-    pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool {
-        self.destructor(tcx).map_or(false, |d| d.is_dtorck)
-    }
-
     /// Returns whether this type is #[fundamental] for the purposes
     /// of coherence checking.
     #[inline]
@@ -1694,6 +1676,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         }
     }
 
+    #[inline]
     pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
                          -> impl Iterator<Item=ConstInt> + 'a {
         let repr_type = self.repr.discr_type();
@@ -1702,11 +1685,18 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         self.variants.iter().map(move |v| {
             let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
             if let VariantDiscr::Explicit(expr_did) = v.discr {
-                match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) {
+                let substs = Substs::empty();
+                match queries::const_eval::get(tcx, DUMMY_SP, (expr_did, substs)) {
                     Ok(ConstVal::Integral(v)) => {
                         discr = v;
                     }
-                    _ => {}
+                    err => {
+                        if !expr_did.is_local() {
+                            span_bug!(tcx.def_span(expr_did),
+                                "variant discriminant evaluation succeeded \
+                                 in its crate but failed locally: {:?}", err);
+                        }
+                    }
                 }
             }
             prev_discr = Some(discr);
@@ -1734,12 +1724,21 @@ impl<'a, 'gcx, 'tcx> AdtDef {
                     explicit_index -= distance;
                 }
                 ty::VariantDiscr::Explicit(expr_did) => {
-                    match queries::monomorphic_const_eval::get(tcx, DUMMY_SP, expr_did) {
+                    let substs = Substs::empty();
+                    match queries::const_eval::get(tcx, DUMMY_SP, (expr_did, substs)) {
                         Ok(ConstVal::Integral(v)) => {
                             explicit_value = v;
                             break;
                         }
-                        _ => {
+                        err => {
+                            if !expr_did.is_local() {
+                                span_bug!(tcx.def_span(expr_did),
+                                    "variant discriminant evaluation succeeded \
+                                     in its crate but failed locally: {:?}", err);
+                            }
+                            if explicit_index == 0 {
+                                break;
+                            }
                             explicit_index -= 1;
                         }
                     }
@@ -1764,16 +1763,9 @@ impl<'a, 'gcx, 'tcx> AdtDef {
         queries::adt_destructor::get(tcx, DUMMY_SP, self.did)
     }
 
-    /// Returns a simpler type such that `Self: Sized` if and only
+    /// Returns a list of types such that `Self: Sized` if and only
     /// if that type is Sized, or `TyErr` if this type is recursive.
     ///
-    /// HACK: instead of returning a list of types, this function can
-    /// return a tuple. In that case, the result is Sized only if
-    /// all elements of the tuple are Sized.
-    ///
-    /// This is generally the `struct_tail` if this is a struct, or a
-    /// tuple of them if this is an enum.
-    ///
     /// Oddly enough, checking that the sized-constraint is Sized is
     /// actually more expressive than checking all members:
     /// the Sized trait is inductive, so an associated type that references
@@ -1781,16 +1773,16 @@ impl<'a, 'gcx, 'tcx> AdtDef {
     ///
     /// Due to normalization being eager, this applies even if
     /// the associated type is behind a pointer, e.g. issue #31299.
-    pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
+    pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] {
         match queries::adt_sized_constraint::try_get(tcx, DUMMY_SP, self.did) {
-            Ok(ty) => ty,
+            Ok(tys) => tys,
             Err(_) => {
                 debug!("adt_sized_constraint: {:?} is recursive", self);
                 // This should be reported as an error by `check_representable`.
                 //
                 // Consider the type as Sized in the meanwhile to avoid
                 // further errors.
-                tcx.types.err
+                tcx.intern_type_list(&[tcx.types.err])
             }
         }
     }
@@ -1820,18 +1812,13 @@ impl<'a, 'gcx, 'tcx> AdtDef {
 
             TyAdt(adt, substs) => {
                 // recursive case
-                let adt_ty =
-                    adt.sized_constraint(tcx)
-                       .subst(tcx, substs);
+                let adt_tys = adt.sized_constraint(tcx);
                 debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
-                       ty, adt_ty);
-                if let ty::TyTuple(ref tys, _) = adt_ty.sty {
-                    tys.iter().flat_map(|ty| {
-                        self.sized_constraint_for_ty(tcx, ty)
-                    }).collect()
-                } else {
-                    self.sized_constraint_for_ty(tcx, adt_ty)
-                }
+                       ty, adt_tys);
+                adt_tys.iter()
+                    .map(|ty| ty.subst(tcx, substs))
+                    .flat_map(|ty| self.sized_constraint_for_ty(tcx, ty))
+                    .collect()
             }
 
             TyProjection(..) | TyAnon(..) => {
@@ -2036,6 +2023,23 @@ impl BorrowKind {
     }
 }
 
+#[derive(Debug, Clone)]
+pub enum Attributes<'gcx> {
+    Owned(Rc<[ast::Attribute]>),
+    Borrowed(&'gcx [ast::Attribute])
+}
+
+impl<'gcx> ::std::ops::Deref for Attributes<'gcx> {
+    type Target = [ast::Attribute];
+
+    fn deref(&self) -> &[ast::Attribute] {
+        match self {
+            &Attributes::Owned(ref data) => &data,
+            &Attributes::Borrowed(data) => data
+        }
+    }
+}
+
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     pub fn body_tables(self, body: hir::BodyId) -> &'gcx TypeckTables<'gcx> {
         self.item_tables(self.hir.body_owner_def_id(body))
@@ -2133,14 +2137,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn trait_impl_polarity(self, id: DefId) -> hir::ImplPolarity {
-        if let Some(id) = self.hir.as_local_node_id(id) {
-            match self.hir.expect_item(id).node {
-                hir::ItemImpl(_, polarity, ..) => polarity,
-                ref item => bug!("trait_impl_polarity: {:?} not an impl", item)
-            }
-        } else {
-            self.sess.cstore.impl_polarity(id)
-        }
+        queries::impl_polarity::get(self, DUMMY_SP, id)
     }
 
     pub fn trait_relevant_for_never(self, did: DefId) -> bool {
@@ -2389,11 +2386,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     /// Get the attributes of a definition.
-    pub fn get_attrs(self, did: DefId) -> Cow<'gcx, [ast::Attribute]> {
+    pub fn get_attrs(self, did: DefId) -> Attributes<'gcx> {
         if let Some(id) = self.hir.as_local_node_id(did) {
-            Cow::Borrowed(self.hir.attrs(id))
+            Attributes::Borrowed(self.hir.attrs(id))
         } else {
-            Cow::Owned(self.sess.cstore.item_attrs(did))
+            Attributes::Owned(self.sess.cstore.item_attrs(did))
         }
     }
 
@@ -2499,15 +2496,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Construct a parameter environment suitable for static contexts or other contexts where there
     /// are no free type/lifetime parameters in scope.
     pub fn empty_parameter_environment(self) -> ParameterEnvironment<'tcx> {
-
-        // for an empty parameter environment, there ARE no free
-        // regions, so it shouldn't matter what we use for the free id
-        let free_id_outlive = self.region_maps.node_extent(ast::DUMMY_NODE_ID);
         ty::ParameterEnvironment {
             free_substs: self.intern_substs(&[]),
             caller_bounds: Vec::new(),
-            implicit_region_bound: self.mk_region(ty::ReEmpty),
-            free_id_outlive: free_id_outlive,
+            implicit_region_bound: self.types.re_empty,
+            // for an empty parameter environment, there ARE no free
+            // regions, so it shouldn't matter what we use for the free id
+            free_id_outlive: ROOT_CODE_EXTENT,
             is_copy_cache: RefCell::new(FxHashMap()),
             is_sized_cache: RefCell::new(FxHashMap()),
             is_freeze_cache: RefCell::new(FxHashMap()),
@@ -2673,13 +2668,7 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
 
 /// Calculates the Sized-constraint.
 ///
-/// As the Sized-constraint of enums can be a *set* of types,
-/// the Sized-constraint may need to be a set also. Because introducing
-/// a new type of IVar is currently a complex affair, the Sized-constraint
-/// may be a tuple.
-///
-/// In fact, there are only a few options for the constraint:
-///     - `bool`, if the type is always Sized
+/// In fact, there are only a few options for the types in the constraint:
 ///     - an obviously-unsized type
 ///     - a type parameter or projection whose Sizedness can't be known
 ///     - a tuple of type parameters or projections, if there are multiple
@@ -2688,26 +2677,50 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
 ///       check should catch this case.
 fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   def_id: DefId)
-                                  -> Ty<'tcx> {
+                                  -> &'tcx [Ty<'tcx>] {
     let def = tcx.lookup_adt_def(def_id);
 
-    let tys: Vec<_> = def.variants.iter().flat_map(|v| {
+    let result = tcx.intern_type_list(&def.variants.iter().flat_map(|v| {
         v.fields.last()
     }).flat_map(|f| {
-        let ty = tcx.item_type(f.did);
-        def.sized_constraint_for_ty(tcx, ty)
-    }).collect();
-
-    let ty = match tys.len() {
-        _ if tys.references_error() => tcx.types.err,
-        0 => tcx.types.bool,
-        1 => tys[0],
-        _ => tcx.intern_tup(&tys[..], false)
-    };
+        def.sized_constraint_for_ty(tcx, tcx.item_type(f.did))
+    }).collect::<Vec<_>>());
 
-    debug!("adt_sized_constraint: {:?} => {:?}", def, ty);
+    debug!("adt_sized_constraint: {:?} => {:?}", def, result);
 
-    ty
+    result
+}
+
+/// Calculates the dtorck constraint for a type.
+fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                   def_id: DefId)
+                                   -> DtorckConstraint<'tcx> {
+    let def = tcx.lookup_adt_def(def_id);
+    let span = tcx.def_span(def_id);
+    debug!("dtorck_constraint: {:?}", def);
+
+    if def.is_phantom_data() {
+        let result = DtorckConstraint {
+            outlives: vec![],
+            dtorck_types: vec![
+                tcx.mk_param_from_def(&tcx.item_generics(def_id).types[0])
+           ]
+        };
+        debug!("dtorck_constraint: {:?} => {:?}", def, result);
+        return result;
+    }
+
+    let mut result = def.all_fields()
+        .map(|field| tcx.item_type(field.did))
+        .map(|fty| tcx.dtorck_constraint_for_ty(span, fty, 0, fty))
+        .collect::<Result<DtorckConstraint, ErrorReported>>()
+        .unwrap_or(DtorckConstraint::empty());
+    result.outlives.extend(tcx.destructor_constraints(def));
+    result.dedup();
+
+    debug!("dtorck_constraint: {:?} => {:?}", def, result);
+
+    result
 }
 
 fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -2738,6 +2751,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
         associated_item,
         associated_item_def_ids,
         adt_sized_constraint,
+        adt_dtorck_constraint,
         ..*providers
     };
 }
@@ -2745,6 +2759,7 @@ pub fn provide(providers: &mut ty::maps::Providers) {
 pub fn provide_extern(providers: &mut ty::maps::Providers) {
     *providers = ty::maps::Providers {
         adt_sized_constraint,
+        adt_dtorck_constraint,
         ..*providers
     };
 }
@@ -2761,3 +2776,45 @@ pub struct CrateInherentImpls {
     pub inherent_impls: DefIdMap<Rc<Vec<DefId>>>,
 }
 
+/// A set of constraints that need to be satisfied in order for
+/// a type to be valid for destruction.
+#[derive(Clone, Debug)]
+pub struct DtorckConstraint<'tcx> {
+    /// Types that are required to be alive in order for this
+    /// type to be valid for destruction.
+    pub outlives: Vec<ty::subst::Kind<'tcx>>,
+    /// Types that could not be resolved: projections and params.
+    pub dtorck_types: Vec<Ty<'tcx>>,
+}
+
+impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx>
+{
+    fn from_iter<I: IntoIterator<Item=DtorckConstraint<'tcx>>>(iter: I) -> Self {
+        let mut result = Self::empty();
+
+        for constraint in iter {
+            result.outlives.extend(constraint.outlives);
+            result.dtorck_types.extend(constraint.dtorck_types);
+        }
+
+        result
+    }
+}
+
+
+impl<'tcx> DtorckConstraint<'tcx> {
+    fn empty() -> DtorckConstraint<'tcx> {
+        DtorckConstraint {
+            outlives: vec![],
+            dtorck_types: vec![]
+        }
+    }
+
+    fn dedup<'a>(&mut self) {
+        let mut outlives = FxHashSet();
+        let mut dtorck_types = FxHashSet();
+
+        self.outlives.retain(|&val| outlives.replace(val).is_none());
+        self.dtorck_types.retain(|&val| dtorck_types.replace(val).is_none());
+    }
+}
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 0a2cc1c30f4..14aebdf8418 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -539,6 +539,9 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
     }
 
     fn shift_region_through_binders(&self, region: &'tcx ty::Region) -> &'tcx ty::Region {
+        if self.region_binders_passed == 0 || !region.has_escaping_regions() {
+            return region;
+        }
         self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed))
     }
 }
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 49d79f6545e..f68cf6f97f8 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -19,6 +19,7 @@ use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
 use ty::ParameterEnvironment;
 use ty::fold::TypeVisitor;
 use ty::layout::{Layout, LayoutError};
+use ty::subst::{Subst, Kind};
 use ty::TypeVariants::*;
 use util::common::ErrorReported;
 use util::nodemap::{FxHashMap, FxHashSet};
@@ -385,6 +386,27 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             None => return None,
         };
 
+        Some(ty::Destructor { did: dtor_did })
+    }
+
+    /// Return the set of types that are required to be alive in
+    /// order to run the destructor of `def` (see RFCs 769 and
+    /// 1238).
+    ///
+    /// Note that this returns only the constraints for the
+    /// destructor of `def` itself. For the destructors of the
+    /// contents, you need `adt_dtorck_constraint`.
+    pub fn destructor_constraints(self, def: &'tcx ty::AdtDef)
+                                  -> Vec<ty::subst::Kind<'tcx>>
+    {
+        let dtor = match def.destructor(self) {
+            None => {
+                debug!("destructor_constraints({:?}) - no dtor", def.did);
+                return vec![]
+            }
+            Some(dtor) => dtor.did
+        };
+
         // RFC 1238: if the destructor method is tagged with the
         // attribute `unsafe_destructor_blind_to_params`, then the
         // compiler is being instructed to *assume* that the
@@ -394,11 +416,147 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         // Such access can be in plain sight (e.g. dereferencing
         // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden
         // (e.g. calling `foo.0.clone()` of `Foo<T:Clone>`).
-        let is_dtorck = !self.has_attr(dtor_did, "unsafe_destructor_blind_to_params");
-        Some(ty::Destructor { did: dtor_did, is_dtorck: is_dtorck })
+        if self.has_attr(dtor, "unsafe_destructor_blind_to_params") {
+            debug!("destructor_constraint({:?}) - blind", def.did);
+            return vec![];
+        }
+
+        let impl_def_id = self.associated_item(dtor).container.id();
+        let impl_generics = self.item_generics(impl_def_id);
+
+        // We have a destructor - all the parameters that are not
+        // pure_wrt_drop (i.e, don't have a #[may_dangle] attribute)
+        // must be live.
+
+        // We need to return the list of parameters from the ADTs
+        // generics/substs that correspond to impure parameters on the
+        // impl's generics. This is a bit ugly, but conceptually simple:
+        //
+        // Suppose our ADT looks like the following
+        //
+        //     struct S<X, Y, Z>(X, Y, Z);
+        //
+        // and the impl is
+        //
+        //     impl<#[may_dangle] P0, P1, P2> Drop for S<P1, P2, P0>
+        //
+        // We want to return the parameters (X, Y). For that, we match
+        // up the item-substs <X, Y, Z> with the substs on the impl ADT,
+        // <P1, P2, P0>, and then look up which of the impl substs refer to
+        // parameters marked as pure.
+
+        let impl_substs = match self.item_type(impl_def_id).sty {
+            ty::TyAdt(def_, substs) if def_ == def => substs,
+            _ => bug!()
+        };
+
+        let item_substs = match self.item_type(def.did).sty {
+            ty::TyAdt(def_, substs) if def_ == def => substs,
+            _ => bug!()
+        };
+
+        let result = item_substs.iter().zip(impl_substs.iter())
+            .filter(|&(_, &k)| {
+                if let Some(&ty::Region::ReEarlyBound(ref ebr)) = k.as_region() {
+                    !impl_generics.region_param(ebr).pure_wrt_drop
+                } else if let Some(&ty::TyS {
+                    sty: ty::TypeVariants::TyParam(ref pt), ..
+                }) = k.as_type() {
+                    !impl_generics.type_param(pt).pure_wrt_drop
+                } else {
+                    // not a type or region param - this should be reported
+                    // as an error.
+                    false
+                }
+            }).map(|(&item_param, _)| item_param).collect();
+        debug!("destructor_constraint({:?}) = {:?}", def.did, result);
+        result
+    }
+
+    /// Return a set of constraints that needs to be satisfied in
+    /// order for `ty` to be valid for destruction.
+    pub fn dtorck_constraint_for_ty(self,
+                                    span: Span,
+                                    for_ty: Ty<'tcx>,
+                                    depth: usize,
+                                    ty: Ty<'tcx>)
+                                    -> Result<ty::DtorckConstraint<'tcx>, ErrorReported>
+    {
+        debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})",
+               span, for_ty, depth, ty);
+
+        if depth >= self.sess.recursion_limit.get() {
+            let mut err = struct_span_err!(
+                self.sess, span, E0320,
+                "overflow while adding drop-check rules for {}", for_ty);
+            err.note(&format!("overflowed on {}", ty));
+            err.emit();
+            return Err(ErrorReported);
+        }
+
+        let result = match ty.sty {
+            ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
+            ty::TyFloat(_) | ty::TyStr | ty::TyNever |
+            ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) => {
+                // these types never have a destructor
+                Ok(ty::DtorckConstraint::empty())
+            }
+
+            ty::TyArray(ety, _) | ty::TySlice(ety) => {
+                // single-element containers, behave like their element
+                self.dtorck_constraint_for_ty(span, for_ty, depth+1, ety)
+            }
+
+            ty::TyTuple(tys, _) => {
+                tys.iter().map(|ty| {
+                    self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty)
+                }).collect()
+            }
+
+            ty::TyClosure(def_id, substs) => {
+                substs.upvar_tys(def_id, self).map(|ty| {
+                    self.dtorck_constraint_for_ty(span, for_ty, depth+1, ty)
+                }).collect()
+            }
+
+            ty::TyAdt(def, substs) => {
+                let ty::DtorckConstraint {
+                    dtorck_types, outlives
+                } = ty::queries::adt_dtorck_constraint::get(self, span, def.did);
+                Ok(ty::DtorckConstraint {
+                    // FIXME: we can try to recursively `dtorck_constraint_on_ty`
+                    // there, but that needs some way to handle cycles.
+                    dtorck_types: dtorck_types.subst(self, substs),
+                    outlives: outlives.subst(self, substs)
+                })
+            }
+
+            // Objects must be alive in order for their destructor
+            // to be called.
+            ty::TyDynamic(..) => Ok(ty::DtorckConstraint {
+                outlives: vec![Kind::from(ty)],
+                dtorck_types: vec![],
+            }),
+
+            // Types that can't be resolved. Pass them forward.
+            ty::TyProjection(..) | ty::TyAnon(..) | ty::TyParam(..) => {
+                Ok(ty::DtorckConstraint {
+                    outlives: vec![],
+                    dtorck_types: vec![ty],
+                })
+            }
+
+            ty::TyInfer(..) | ty::TyError => {
+                self.sess.delay_span_bug(span, "unresolved type in dtorck");
+                Err(ErrorReported)
+            }
+        };
+
+        debug!("dtorck_constraint_for_ty({:?}) = {:?}", ty, result);
+        result
     }
 
-    pub fn closure_base_def_id(&self, def_id: DefId) -> DefId {
+    pub fn closure_base_def_id(self, def_id: DefId) -> DefId {
         let mut def_id = def_id;
         while self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr {
             def_id = self.parent_def_id(def_id).unwrap_or_else(|| {
@@ -412,7 +570,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// a suitable "empty substs" for it.
     pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tcx> {
         ty::Substs::for_item(self, item_def_id,
-                             |_, _| self.mk_region(ty::ReErased),
+                             |_, _| self.types.re_erased,
                              |_, _| {
             bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id)
         })
diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
index bbfb7e5874e..b921678b495 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs
@@ -120,7 +120,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> {
             }
             Categorization::StaticItem |
             Categorization::Deref(.., mc::UnsafePtr(..)) => {
-                self.bccx.tcx.mk_region(ty::ReStatic)
+                self.bccx.tcx.types.re_static
             }
             Categorization::Deref(.., mc::BorrowedPtr(_, r)) |
             Categorization::Deref(.., mc::Implicit(_, r)) => {
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 9c5a669bef0..e9352f53c92 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -15,7 +15,7 @@ use rustc::middle::const_val::{ConstVal, ConstEvalErr, EvalResult, ErrKind};
 use rustc::hir::map as hir_map;
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::traits;
-use rustc::hir::def::Def;
+use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::maps::Providers;
@@ -48,110 +48,39 @@ macro_rules! math {
     }
 }
 
-fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                  variant_def: DefId)
-                                  -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> {
-    if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) {
-        let enum_node_id = tcx.hir.get_parent(variant_node_id);
-        if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) {
-            if let hir::ItemEnum(ref edef, _) = it.node {
-                for variant in &edef.variants {
-                    if variant.node.data.id() == variant_node_id {
-                        return variant.node.disr_expr.map(|e| {
-                            let def_id = tcx.hir.body_owner_def_id(e);
-                            (&tcx.hir.body(e).value,
-                             tcx.item_tables(def_id))
-                        });
-                    }
-                }
-            }
-        }
-    }
-    None
-}
-
 /// * `def_id` is the id of the constant.
 /// * `substs` is the monomorphized substitutions for the expression.
 ///
 /// `substs` is optional and is used for associated constants.
 /// This generally happens in late/trans const evaluation.
-pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                        def_id: DefId,
-                                        substs: &'tcx Substs<'tcx>)
-                                        -> Option<(&'tcx Expr,
-                                                   &'a ty::TypeckTables<'tcx>)> {
+pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                    def_id: DefId,
+                                    substs: &'tcx Substs<'tcx>)
+                                    -> Option<(DefId, &'tcx Substs<'tcx>)> {
     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
         match tcx.hir.find(node_id) {
-            None => None,
-            Some(hir_map::NodeItem(&hir::Item {
-                node: hir::ItemConst(_, body), ..
-            })) |
-            Some(hir_map::NodeImplItem(&hir::ImplItem {
-                node: hir::ImplItemKind::Const(_, body), ..
-            })) => {
-                Some((&tcx.hir.body(body).value,
-                      tcx.item_tables(def_id)))
+            Some(hir_map::NodeTraitItem(_)) => {
+                // If we have a trait item and the substitutions for it,
+                // `resolve_trait_associated_const` will select an impl
+                // or the default.
+                resolve_trait_associated_const(tcx, def_id, substs)
             }
-            Some(hir_map::NodeTraitItem(ti)) => match ti.node {
-                hir::TraitItemKind::Const(_, default) => {
-                    // If we have a trait item and the substitutions for it,
-                    // `resolve_trait_associated_const` will select an impl
-                    // or the default.
-                    let trait_id = tcx.hir.get_parent(node_id);
-                    let trait_id = tcx.hir.local_def_id(trait_id);
-                    let default_value = default.map(|body| {
-                        (&tcx.hir.body(body).value,
-                            tcx.item_tables(def_id))
-                    });
-                    resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
-                }
-                _ => None
-            },
-            Some(_) => None
+            _ => Some((def_id, substs))
         }
     } else {
-        let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-            (&body.value, tcx.item_tables(def_id))
-        });
         match tcx.sess.cstore.describe_def(def_id) {
             Some(Def::AssociatedConst(_)) => {
-                let trait_id = tcx.sess.cstore.trait_of_item(def_id);
                 // As mentioned in the comments above for in-crate
                 // constants, we only try to find the expression for a
                 // trait-associated const if the caller gives us the
                 // substitutions for the reference to it.
-                if let Some(trait_id) = trait_id {
-                    resolve_trait_associated_const(tcx, def_id, expr_and_tables,
-                                                   trait_id, substs)
+                if tcx.sess.cstore.trait_of_item(def_id).is_some() {
+                    resolve_trait_associated_const(tcx, def_id, substs)
                 } else {
-                    expr_and_tables
+                    Some((def_id, substs))
                 }
-            },
-            Some(Def::Const(..)) => expr_and_tables,
-            _ => None
-        }
-    }
-}
-
-fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
-                                   -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)>
-{
-    if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
-        FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| {
-            if fn_like.constness() == hir::Constness::Const {
-                Some((tcx.hir.body(fn_like.body()),
-                      tcx.item_tables(def_id)))
-            } else {
-                None
             }
-        })
-    } else {
-        if tcx.sess.cstore.is_const_fn(def_id) {
-            tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
-                (body, tcx.item_tables(def_id))
-            })
-        } else {
-            None
+            _ => Some((def_id, substs))
         }
     }
 }
@@ -338,9 +267,22 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         }
       }
       hir::ExprCast(ref base, _) => {
-        match cast_const(tcx, cx.eval(base)?, ety) {
-            Ok(val) => val,
-            Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
+        let base_val = cx.eval(base)?;
+        let base_ty = cx.tables.expr_ty(base);
+
+        // Avoid applying substitutions if they're empty, that'd ICE.
+        let base_ty = if cx.substs.is_empty() {
+            base_ty
+        } else {
+            base_ty.subst(tcx, cx.substs)
+        };
+        if ety == base_ty {
+            base_val
+        } else {
+            match cast_const(tcx, base_val, ety) {
+                Ok(val) => val,
+                Err(kind) => signal!(e, kind),
+            }
         }
       }
       hir::ExprPath(ref qpath) => {
@@ -357,42 +299,29 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           match cx.tables.qpath_def(qpath, e.id) {
               Def::Const(def_id) |
               Def::AssociatedConst(def_id) => {
-                  if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) {
-                      let cx = ConstContext::with_tables(tcx, tables);
-                      match cx.eval(expr) {
-                          Ok(val) => val,
-                          Err(ConstEvalErr { kind: TypeckError, .. }) => {
-                              signal!(e, TypeckError);
-                          }
-                          Err(err) => {
-                              debug!("bad reference: {:?}, {:?}", err.description(), err.span);
-                              signal!(e, ErroneousReferencedConstant(box err))
-                          },
-                      }
-                  } else {
-                      signal!(e, TypeckError);
-                  }
+                    match ty::queries::const_eval::get(tcx, e.span, (def_id, substs)) {
+                        Ok(val) => val,
+                        Err(ConstEvalErr { kind: TypeckError, .. }) => {
+                            signal!(e, TypeckError);
+                        }
+                        Err(err) => {
+                            debug!("bad reference: {:?}, {:?}", err.description(), err.span);
+                            signal!(e, ErroneousReferencedConstant(box err))
+                        },
+                    }
               },
-              Def::VariantCtor(variant_def, ..) => {
-                  if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
-                      let cx = ConstContext::with_tables(tcx, tables);
-                      match cx.eval(expr) {
-                          Ok(val) => val,
-                          Err(ConstEvalErr { kind: TypeckError, .. }) => {
-                              signal!(e, TypeckError);
-                          }
-                          Err(err) => {
-                              debug!("bad reference: {:?}, {:?}", err.description(), err.span);
-                              signal!(e, ErroneousReferencedConstant(box err))
-                          },
-                      }
-                  } else {
-                      signal!(e, UnimplementedConstVal("enum variants"));
-                  }
+              Def::VariantCtor(variant_def, CtorKind::Const) => {
+                Variant(variant_def)
+              }
+              Def::VariantCtor(_, CtorKind::Fn) => {
+                  signal!(e, UnimplementedConstVal("enum variants"));
               }
-              Def::StructCtor(..) => {
+              Def::StructCtor(_, CtorKind::Const) => {
                   ConstVal::Struct(Default::default())
               }
+              Def::StructCtor(_, CtorKind::Fn) => {
+                  signal!(e, UnimplementedConstVal("tuple struct constructors"))
+              }
               Def::Local(def_id) => {
                   debug!("Def::Local({:?}): {:?}", def_id, cx.fn_args);
                   if let Some(val) = cx.fn_args.as_ref().and_then(|args| args.get(&def_id)) {
@@ -407,14 +336,27 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           }
       }
       hir::ExprCall(ref callee, ref args) => {
-          let (did, substs) = match cx.eval(callee)? {
-              Function(did, substs) => (did, substs),
-              Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
-              callee => signal!(e, CallOn(callee)),
+          let (def_id, substs) = match cx.eval(callee)? {
+              Function(def_id, substs) => (def_id, substs),
+              _ => signal!(e, TypeckError),
           };
-          let (body, tables) = match lookup_const_fn_by_id(tcx, did) {
-              Some(x) => x,
-              None => signal!(e, NonConstPath),
+
+          let body = if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
+            if let Some(fn_like) = FnLikeNode::from_node(tcx.hir.get(node_id)) {
+                if fn_like.constness() == hir::Constness::Const {
+                    tcx.hir.body(fn_like.body())
+                } else {
+                    signal!(e, TypeckError)
+                }
+            } else {
+                signal!(e, TypeckError)
+            }
+          } else {
+            if tcx.sess.cstore.is_const_fn(def_id) {
+                tcx.sess.cstore.item_body(tcx, def_id)
+            } else {
+                signal!(e, TypeckError)
+            }
           };
 
           let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
@@ -434,7 +376,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
           debug!("const call({:?})", call_args);
           let callee_cx = ConstContext {
             tcx: tcx,
-            tables: tables,
+            tables: tcx.item_tables(def_id),
             substs: substs,
             fn_args: Some(call_args)
           };
@@ -532,19 +474,16 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
     Ok(result)
 }
 
-fn resolve_trait_associated_const<'a, 'tcx: 'a>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    trait_item_id: DefId,
-    default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>,
-    trait_id: DefId,
-    rcvr_substs: &'tcx Substs<'tcx>
-) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>
-{
-    let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
+fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                            def_id: DefId,
+                                            substs: &'tcx Substs<'tcx>)
+                                            -> Option<(DefId, &'tcx Substs<'tcx>)> {
+    let trait_item = tcx.associated_item(def_id);
+    let trait_id = trait_item.container.id();
+    let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs));
     debug!("resolve_trait_associated_const: trait_ref={:?}",
            trait_ref);
 
-    tcx.populate_implementations_for_trait_if_necessary(trait_id);
     tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
         let mut selcx = traits::SelectionContext::new(&infcx);
         let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
@@ -569,12 +508,20 @@ fn resolve_trait_associated_const<'a, 'tcx: 'a>(
         // when constructing the inference context above.
         match selection {
             traits::VtableImpl(ref impl_data) => {
-                let name = tcx.associated_item(trait_item_id).name;
+                let name = trait_item.name;
                 let ac = tcx.associated_items(impl_data.impl_def_id)
                     .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
                 match ac {
-                    Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()),
-                    None => default_value,
+                    // FIXME(eddyb) Use proper Instance resolution to
+                    // get the correct Substs returned from here.
+                    Some(ic) => Some((ic.def_id, Substs::empty())),
+                    None => {
+                        if trait_item.defaultness.has_value() {
+                            Some((def_id, substs))
+                        } else {
+                            None
+                        }
+                    }
                 }
             }
             _ => {
@@ -615,7 +562,7 @@ fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             U8(u) => Ok(Char(u as char)),
             _ => bug!(),
         },
-        _ => bug!(),
+        _ => Err(CannotCast),
     }
 }
 
@@ -659,6 +606,11 @@ fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
         Float(f) => cast_const_float(tcx, f, ty),
         Char(c) => cast_const_int(tcx, U32(c as u32), ty),
+        Variant(v) => {
+            let adt = tcx.lookup_adt_def(tcx.parent_def_id(v).unwrap());
+            let idx = adt.variant_index_with_id(v);
+            cast_const_int(tcx, adt.discriminant_for_variant(tcx, idx), ty)
+        }
         Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
         ByteStr(b) => match ty.sty {
             ty::TyRawPtr(_) => {
@@ -796,21 +748,35 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
-        monomorphic_const_eval,
+        const_eval,
         ..*providers
     };
 }
 
-fn monomorphic_const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                    def_id: DefId)
-                                    -> EvalResult<'tcx> {
-    let cx = ConstContext::with_tables(tcx, tcx.item_tables(def_id));
+fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        (def_id, substs): (DefId, &'tcx Substs<'tcx>))
+                        -> EvalResult<'tcx> {
+    let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, def_id, substs) {
+        resolved
+    } else {
+        return Err(ConstEvalErr {
+            span: tcx.def_span(def_id),
+            kind: TypeckError
+        });
+    };
+
+    let cx = ConstContext {
+        tcx,
+        tables: tcx.item_tables(def_id),
+        substs: substs,
+        fn_args: None
+    };
 
     let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
         ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
         tcx.hir.body(tcx.hir.body_owned_by(id))
     } else {
-        tcx.sess.cstore.maybe_get_item_body(tcx, def_id).unwrap()
+        tcx.sess.cstore.item_body(tcx, def_id)
     };
     cx.eval(&body.value)
 }
diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs
index f20fa27dc22..0dfafeb6fb8 100644
--- a/src/librustc_const_eval/pattern.rs
+++ b/src/librustc_const_eval/pattern.rs
@@ -116,6 +116,7 @@ fn print_const_val(value: &ConstVal, f: &mut fmt::Formatter) -> fmt::Result {
         ConstVal::ByteStr(ref b) => write!(f, "{:?}", &b[..]),
         ConstVal::Bool(b) => write!(f, "{:?}", b),
         ConstVal::Char(c) => write!(f, "{:?}", c),
+        ConstVal::Variant(_) |
         ConstVal::Struct(_) |
         ConstVal::Tuple(_) |
         ConstVal::Function(..) |
@@ -587,11 +588,16 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
                 let substs = self.tables.node_id_item_substs(id)
                     .unwrap_or_else(|| tcx.intern_substs(&[]));
                 match eval::lookup_const_by_id(tcx, def_id, substs) {
-                    Some((const_expr, const_tables)) => {
+                    Some((def_id, _substs)) => {
                         // Enter the inlined constant's tables temporarily.
                         let old_tables = self.tables;
-                        self.tables = const_tables;
-                        let pat = self.lower_const_expr(const_expr, pat_id, span);
+                        self.tables = tcx.item_tables(def_id);
+                        let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
+                            tcx.hir.body(tcx.hir.body_owned_by(id))
+                        } else {
+                            tcx.sess.cstore.item_body(tcx, def_id)
+                        };
+                        let pat = self.lower_const_expr(&body.value, pat_id, span);
                         self.tables = old_tables;
                         return pat;
                     }
@@ -615,7 +621,12 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
         let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
         match const_cx.eval(expr) {
             Ok(value) => {
-                PatternKind::Constant { value: value }
+                if let ConstVal::Variant(def_id) = value {
+                    let ty = self.tables.expr_ty(expr);
+                    self.lower_variant_or_leaf(Def::Variant(def_id), ty, vec![])
+                } else {
+                    PatternKind::Constant { value: value }
+                }
             }
             Err(e) => {
                 self.errors.push(PatternError::ConstEval(e));
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 7632b40ab4f..438f482fa55 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -225,6 +225,8 @@ pub fn compile_input(sess: &Session,
         sess.code_stats.borrow().print_type_sizes();
     }
 
+    if ::std::env::var("SKIP_LLVM").is_ok() { ::std::process::exit(0); }
+
     let phase5_result = phase_5_run_llvm_passes(sess, &trans, &outputs);
 
     controller_entry_point!(after_llvm,
@@ -810,7 +812,7 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
         defs: resolver.definitions,
         analysis: ty::CrateAnalysis {
             access_levels: Rc::new(AccessLevels::default()),
-            reachable: NodeSet(),
+            reachable: Rc::new(NodeSet()),
             name: crate_name.to_string(),
             glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None },
         },
@@ -889,9 +891,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
     let index = stability::Index::new(&hir_map);
 
     let mut local_providers = ty::maps::Providers::default();
+    borrowck::provide(&mut local_providers);
     mir::provide(&mut local_providers);
+    reachable::provide(&mut local_providers);
     rustc_privacy::provide(&mut local_providers);
-    borrowck::provide(&mut local_providers);
     typeck::provide(&mut local_providers);
     ty::provide(&mut local_providers);
     reachable::provide(&mut local_providers);
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index 7447fba3038..147d6558e19 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -343,12 +343,12 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> {
     }
 
     pub fn t_rptr_static(&self) -> Ty<'tcx> {
-        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReStatic),
+        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_static,
                                   self.tcx().types.isize)
     }
 
     pub fn t_rptr_empty(&self) -> Ty<'tcx> {
-        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.mk_region(ty::ReEmpty),
+        self.infcx.tcx.mk_imm_ref(self.infcx.tcx.types.re_empty,
                                   self.tcx().types.isize)
     }
 
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index a8ee999505e..7bc0e8a512b 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -326,6 +326,7 @@ impl<'a> CrateLoader<'a> {
             cnum_map: RefCell::new(cnum_map),
             cnum: cnum,
             codemap_import_info: RefCell::new(vec![]),
+            attribute_cache: RefCell::new([Vec::new(), Vec::new()]),
             dep_kind: Cell::new(dep_kind),
             source: cstore::CrateSource {
                 dylib: dylib,
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 17a6a706e0a..72ad1d75a56 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -72,6 +72,7 @@ pub struct CrateMetadata {
     pub cnum_map: RefCell<CrateNumMap>,
     pub cnum: CrateNum,
     pub codemap_import_info: RefCell<Vec<ImportedFileMap>>,
+    pub attribute_cache: RefCell<[Vec<Option<Rc<[ast::Attribute]>>>; 2]>,
 
     pub root: schema::CrateRoot,
 
@@ -269,7 +270,7 @@ impl CrateMetadata {
     }
 
     pub fn is_staged_api(&self) -> bool {
-        for attr in self.get_item_attrs(CRATE_DEF_INDEX) {
+        for attr in self.get_item_attrs(CRATE_DEF_INDEX).iter() {
             if attr.path == "stable" || attr.path == "unstable" {
                 return true;
             }
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 3239dfb937b..9e6a45e7f8b 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -89,6 +89,7 @@ provide! { <'tcx> tcx, def_id, cdata
     }
     associated_item => { cdata.get_associated_item(def_id.index) }
     impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
+    impl_polarity => { cdata.get_impl_polarity(def_id.index) }
     coerce_unsized_info => {
         cdata.get_coerce_unsized_info(def_id.index).unwrap_or_else(|| {
             bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
@@ -111,6 +112,7 @@ provide! { <'tcx> tcx, def_id, cdata
     closure_kind => { cdata.closure_kind(def_id.index) }
     closure_type => { cdata.closure_ty(def_id.index, tcx) }
     inherent_impls => { Rc::new(cdata.get_inherent_implementations_for_type(def_id.index)) }
+    is_foreign_item => { cdata.is_foreign_item(def_id.index) }
 }
 
 impl CrateStore for cstore::CStore {
@@ -148,7 +150,7 @@ impl CrateStore for cstore::CStore {
         self.get_crate_data(def.krate).get_generics(def.index)
     }
 
-    fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
+    fn item_attrs(&self, def_id: DefId) -> Rc<[ast::Attribute]>
     {
         self.dep_graph.read(DepNode::MetaData(def_id));
         self.get_crate_data(def_id.krate).get_item_attrs(def_id.index)
@@ -176,12 +178,6 @@ impl CrateStore for cstore::CStore {
         result
     }
 
-    fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity
-    {
-        self.dep_graph.read(DepNode::MetaData(def));
-        self.get_crate_data(def.krate).get_impl_polarity(def.index)
-    }
-
     fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
         self.dep_graph.read(DepNode::MetaData(impl_def));
         self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index)
@@ -405,7 +401,7 @@ impl CrateStore for cstore::CStore {
 
         // Mark the attrs as used
         let attrs = data.get_item_attrs(id.index);
-        for attr in &attrs {
+        for attr in attrs.iter() {
             attr::mark_used(attr);
         }
 
@@ -418,25 +414,24 @@ impl CrateStore for cstore::CStore {
             ident: ast::Ident::with_empty_ctxt(name),
             id: ast::DUMMY_NODE_ID,
             span: local_span,
-            attrs: attrs,
+            attrs: attrs.iter().cloned().collect(),
             node: ast::ItemKind::MacroDef(body.into()),
             vis: ast::Visibility::Inherited,
         })
     }
 
-    fn maybe_get_item_body<'a, 'tcx>(&self,
-                                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     def_id: DefId)
-                                     -> Option<&'tcx hir::Body>
-    {
+    fn item_body<'a, 'tcx>(&self,
+                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                           def_id: DefId)
+                           -> &'tcx hir::Body {
         if let Some(cached) = tcx.hir.get_inlined_body(def_id) {
-            return Some(cached);
+            return cached;
         }
 
         self.dep_graph.read(DepNode::MetaData(def_id));
-        debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id));
+        debug!("item_body({}): inlining item", tcx.item_path_str(def_id));
 
-        self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index)
+        self.get_crate_data(def_id.krate).item_body(tcx, def_id.index)
     }
 
     fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index fac6079529e..a9eae5281b2 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -31,6 +31,7 @@ use std::cell::Ref;
 use std::collections::BTreeMap;
 use std::io;
 use std::mem;
+use std::rc::Rc;
 use std::str;
 use std::u32;
 
@@ -749,16 +750,15 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn maybe_get_item_body(&self,
-                               tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                               id: DefIndex)
-                               -> Option<&'tcx hir::Body> {
-        if self.is_proc_macro(id) { return None; }
-        self.entry(id).ast.map(|ast| {
-            let def_id = self.local_def_id(id);
-            let body = ast.decode(self).body.decode(self);
-            tcx.hir.intern_inlined_body(def_id, body)
-        })
+    pub fn item_body(&self,
+                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                     id: DefIndex)
+                     -> &'tcx hir::Body {
+        assert!(!self.is_proc_macro(id));
+        let ast = self.entry(id).ast.unwrap();
+        let def_id = self.local_def_id(id);
+        let body = ast.decode(self).body.decode(self);
+        tcx.hir.intern_inlined_body(def_id, body)
     }
 
     pub fn item_body_tables(&self,
@@ -859,10 +859,18 @@ impl<'a, 'tcx> CrateMetadata {
         }
     }
 
-    pub fn get_item_attrs(&self, node_id: DefIndex) -> Vec<ast::Attribute> {
+    pub fn get_item_attrs(&self, node_id: DefIndex) -> Rc<[ast::Attribute]> {
+        let (node_as, node_index) =
+            (node_id.address_space().index(), node_id.as_array_index());
         if self.is_proc_macro(node_id) {
-            return Vec::new();
+            return Rc::new([]);
+        }
+
+        if let Some(&Some(ref val)) =
+            self.attribute_cache.borrow()[node_as].get(node_index) {
+            return val.clone();
         }
+
         // The attributes for a tuple struct are attached to the definition, not the ctor;
         // we assume that someone passing in a tuple struct ctor is actually wanting to
         // look at the definition
@@ -871,7 +879,13 @@ impl<'a, 'tcx> CrateMetadata {
         if def_key.disambiguated_data.data == DefPathData::StructCtor {
             item = self.entry(def_key.parent.unwrap());
         }
-        self.get_attributes(&item)
+        let result = Rc::__from_array(self.get_attributes(&item).into_boxed_slice());
+        let vec_ = &mut self.attribute_cache.borrow_mut()[node_as];
+        if vec_.len() < node_index + 1 {
+            vec_.resize(node_index + 1, None);
+        }
+        vec_[node_index] = Some(result.clone());
+        result
     }
 
     pub fn get_struct_field_names(&self, id: DefIndex) -> Vec<ast::Name> {
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 5fece4d6a5d..0833342927f 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -280,7 +280,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
                     assert!(ty.is_slice());
 
                     let array_ty = tcx.mk_array(tcx.types.u8, bytes.len());
-                    let array_ref = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic), array_ty);
+                    let array_ref = tcx.mk_imm_ref(tcx.types.re_static, array_ty);
                     let array = self.literal_operand(test.span, array_ref, Literal::Value {
                         value: value.clone()
                     });
diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs
index b7de50efe34..736c076ea15 100644
--- a/src/librustc_mir/hair/cx/expr.rs
+++ b/src/librustc_mir/hair/cx/expr.rs
@@ -593,7 +593,8 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
         hir::ExprRepeat(ref v, count) => {
             let c = &cx.tcx.hir.body(count).value;
             let def_id = cx.tcx.hir.body_owner_def_id(count);
-            let count = match ty::queries::monomorphic_const_eval::get(cx.tcx, c.span, def_id) {
+            let substs = Substs::empty();
+            let count = match ty::queries::const_eval::get(cx.tcx, c.span, (def_id, substs)) {
                 Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
                 Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
                 Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression")
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 4d70540a7c6..7f7377e5ffe 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -308,10 +308,9 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
         Adjustment::Deref => Operand::Consume(rcvr_l.deref()),
         Adjustment::RefMut => {
             // let rcvr = &mut rcvr;
-            let re_erased = tcx.mk_region(ty::ReErased);
             let ref_rcvr = local_decls.push(temp_decl(
                 Mutability::Not,
-                tcx.mk_ref(re_erased, ty::TypeAndMut {
+                tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut {
                     ty: sig.inputs()[0],
                     mutbl: hir::Mutability::MutMutable
                 }),
@@ -321,7 +320,7 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
                 source_info: source_info,
                 kind: StatementKind::Assign(
                     Lvalue::Local(ref_rcvr),
-                    Rvalue::Ref(re_erased, BorrowKind::Mut, rcvr_l)
+                    Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, rcvr_l)
                 )
             });
             Operand::Consume(Lvalue::Local(ref_rcvr))
diff --git a/src/librustc_mir/transform/erase_regions.rs b/src/librustc_mir/transform/erase_regions.rs
index 0f869e7ed02..5cc5cf29793 100644
--- a/src/librustc_mir/transform/erase_regions.rs
+++ b/src/librustc_mir/transform/erase_regions.rs
@@ -13,7 +13,7 @@
 //! care erasing regions all over the place.
 
 use rustc::ty::subst::Substs;
-use rustc::ty::{Ty, TyCtxt, ReErased, ClosureSubsts};
+use rustc::ty::{Ty, TyCtxt, ClosureSubsts};
 use rustc::mir::*;
 use rustc::mir::visit::MutVisitor;
 use rustc::mir::transform::{MirPass, MirSource, Pass};
@@ -43,7 +43,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
     fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
         match *rvalue {
             Rvalue::Ref(ref mut r, _, _) => {
-                *r = self.tcx.mk_region(ReErased);
+                *r = self.tcx.types.re_erased;
             }
             Rvalue::Use(..) |
             Rvalue::Repeat(..) |
diff --git a/src/librustc_mir/transform/inline.rs b/src/librustc_mir/transform/inline.rs
index 892d67ac237..45bdff9195c 100644
--- a/src/librustc_mir/transform/inline.rs
+++ b/src/librustc_mir/transform/inline.rs
@@ -497,7 +497,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
                 let dest = if dest_needs_borrow(&destination.0) {
                     debug!("Creating temp for return destination");
                     let dest = Rvalue::Ref(
-                        self.tcx.mk_region(ty::ReErased),
+                        self.tcx.types.re_erased,
                         BorrowKind::Mut,
                         destination.0);
 
@@ -582,7 +582,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
     fn cast_box_free_arg(&self, arg: Lvalue<'tcx>, ptr_ty: Ty<'tcx>,
                          callsite: &CallSite<'tcx>, caller_mir: &mut Mir<'tcx>) -> Operand<'tcx> {
         let arg = Rvalue::Ref(
-            self.tcx.mk_region(ty::ReErased),
+            self.tcx.types.re_erased,
             BorrowKind::Mut,
             arg.deref());
 
diff --git a/src/librustc_mir/transform/simplify.rs b/src/librustc_mir/transform/simplify.rs
index 0a8f147b214..ef7990653ba 100644
--- a/src/librustc_mir/transform/simplify.rs
+++ b/src/librustc_mir/transform/simplify.rs
@@ -124,6 +124,8 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
                     self.collapse_goto_chain(successor, &mut changed);
                 }
 
+                changed |= self.simplify_unwind(&mut terminator);
+
                 let mut new_stmts = vec![];
                 let mut inner_changed = true;
                 while inner_changed {
@@ -238,6 +240,38 @@ impl<'a, 'tcx: 'a> CfgSimplifier<'a, 'tcx> {
         true
     }
 
+    // turn an unwind branch to a resume block into a None
+    fn simplify_unwind(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
+        let unwind = match terminator.kind {
+            TerminatorKind::Drop { ref mut unwind, .. } |
+            TerminatorKind::DropAndReplace { ref mut unwind, .. } |
+            TerminatorKind::Call { cleanup: ref mut unwind, .. } |
+            TerminatorKind::Assert { cleanup: ref mut unwind, .. } =>
+                unwind,
+            _ => return false
+        };
+
+        if let &mut Some(unwind_block) = unwind {
+            let is_resume_block = match self.basic_blocks[unwind_block] {
+                BasicBlockData {
+                    ref statements,
+                    terminator: Some(Terminator {
+                        kind: TerminatorKind::Resume, ..
+                    }), ..
+                } if statements.is_empty() => true,
+                _ => false
+            };
+            if is_resume_block {
+                debug!("simplifying unwind to {:?} from {:?}",
+                       unwind_block, terminator.source_info);
+                *unwind = None;
+            }
+            return is_resume_block;
+        }
+
+        false
+    }
+
     fn strip_nops(&mut self) {
         for blk in self.basic_blocks.iter_mut() {
             blk.statements.retain(|stmt| if let StatementKind::Nop = stmt.kind {
diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs
index 07025fcfdb9..9d7c7ec63cf 100644
--- a/src/librustc_mir/util/elaborate_drops.rs
+++ b/src/librustc_mir/util/elaborate_drops.rs
@@ -506,8 +506,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
         let ty = self.lvalue_ty(self.lvalue);
         let substs = tcx.mk_substs(iter::once(Kind::from(ty)));
 
-        let re_erased = tcx.mk_region(ty::ReErased);
-        let ref_ty = tcx.mk_ref(re_erased, ty::TypeAndMut {
+        let ref_ty = tcx.mk_ref(tcx.types.re_erased, ty::TypeAndMut {
             ty: ty,
             mutbl: hir::Mutability::MutMutable
         });
@@ -519,7 +518,7 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D>
                 source_info: self.source_info,
                 kind: StatementKind::Assign(
                     Lvalue::Local(ref_lvalue),
-                    Rvalue::Ref(re_erased, BorrowKind::Mut, self.lvalue.clone())
+                    Rvalue::Ref(tcx.types.re_erased, BorrowKind::Mut, self.lvalue.clone())
                 )
             }],
             terminator: Some(Terminator {
diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs
index 5d6717272fd..221c52141a8 100644
--- a/src/librustc_trans/back/symbol_export.rs
+++ b/src/librustc_trans/back/symbol_export.rs
@@ -53,7 +53,7 @@ impl ExportedSymbols {
                 scx.tcx().hir.local_def_id(node_id)
             })
             .map(|def_id| {
-                let name = symbol_for_def_id(scx, def_id, symbol_map);
+                let name = symbol_for_def_id(scx.tcx(), def_id, symbol_map);
                 let export_level = export_level(scx, def_id);
                 debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
                 (name, export_level)
@@ -108,7 +108,7 @@ impl ExportedSymbols {
                 .exported_symbols(cnum)
                 .iter()
                 .map(|&def_id| {
-                    let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx);
+                    let name = symbol_name(Instance::mono(scx.tcx(), def_id), scx.tcx());
                     let export_level = if special_runtime_crate {
                         // We can probably do better here by just ensuring that
                         // it has hidden visibility rather than public
@@ -214,21 +214,21 @@ pub fn is_below_threshold(level: SymbolExportLevel,
     }
 }
 
-fn symbol_for_def_id<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+fn symbol_for_def_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                def_id: DefId,
                                symbol_map: &SymbolMap<'tcx>)
                                -> String {
     // Just try to look things up in the symbol map. If nothing's there, we
     // recompute.
-    if let Some(node_id) = scx.tcx().hir.as_local_node_id(def_id) {
+    if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
         if let Some(sym) = symbol_map.get(TransItem::Static(node_id)) {
             return sym.to_owned();
         }
     }
 
-    let instance = Instance::mono(scx.tcx(), def_id);
+    let instance = Instance::mono(tcx, def_id);
 
     symbol_map.get(TransItem::Fn(instance))
               .map(str::to_owned)
-              .unwrap_or_else(|| symbol_name(instance, scx))
+              .unwrap_or_else(|| symbol_name(instance, tcx))
 }
diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs
index 8facbd6cc27..f21864764dd 100644
--- a/src/librustc_trans/back/symbol_names.rs
+++ b/src/librustc_trans/back/symbol_names.rs
@@ -97,13 +97,12 @@
 //! virtually impossible. Thus, symbol hash generation exclusively relies on
 //! DefPaths which are much more robust in the face of changes to the code base.
 
-use common::SharedCrateContext;
 use monomorphize::Instance;
 
 use rustc::middle::weak_lang_items;
 use rustc::hir::def_id::DefId;
 use rustc::hir::map as hir_map;
-use rustc::ty::{self, Ty, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::fold::TypeVisitor;
 use rustc::ty::item_path::{self, ItemPathBuffer, RootMode};
 use rustc::ty::subst::Substs;
@@ -111,9 +110,10 @@ use rustc::hir::map::definitions::DefPathData;
 use rustc::util::common::record_time;
 
 use syntax::attr;
-use syntax::symbol::{Symbol, InternedString};
 
-fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+use std::fmt::Write;
+
+fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
                              // the DefId of the item this name is for
                              def_id: Option<DefId>,
@@ -130,8 +130,6 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                              -> String {
     debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
 
-    let tcx = scx.tcx();
-
     let mut hasher = ty::util::TypeIdHasher::<u64>::new(tcx);
 
     record_time(&tcx.sess.perf_stats.symbol_hash_time, || {
@@ -157,8 +155,8 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             // in case the same instances is emitted in two crates of the same
             // project.
             if substs.types().next().is_some() {
-                hasher.hash(scx.tcx().crate_name.as_str());
-                hasher.hash(scx.sess().local_crate_disambiguator().as_str());
+                hasher.hash(tcx.crate_name.as_str());
+                hasher.hash(tcx.sess.local_crate_disambiguator().as_str());
             }
         }
     });
@@ -168,37 +166,37 @@ fn get_symbol_hash<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 }
 
 pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
-                             scx: &SharedCrateContext<'a, 'tcx>) -> String {
+                             tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
     let def_id = instance.def_id();
     let substs = instance.substs;
 
     debug!("symbol_name(def_id={:?}, substs={:?})",
            def_id, substs);
 
-    let node_id = scx.tcx().hir.as_local_node_id(def_id);
+    let node_id = tcx.hir.as_local_node_id(def_id);
 
     if let Some(id) = node_id {
-        if scx.sess().plugin_registrar_fn.get() == Some(id) {
+        if tcx.sess.plugin_registrar_fn.get() == Some(id) {
             let idx = def_id.index;
-            let disambiguator = scx.sess().local_crate_disambiguator();
-            return scx.sess().generate_plugin_registrar_symbol(disambiguator, idx);
+            let disambiguator = tcx.sess.local_crate_disambiguator();
+            return tcx.sess.generate_plugin_registrar_symbol(disambiguator, idx);
         }
-        if scx.sess().derive_registrar_fn.get() == Some(id) {
+        if tcx.sess.derive_registrar_fn.get() == Some(id) {
             let idx = def_id.index;
-            let disambiguator = scx.sess().local_crate_disambiguator();
-            return scx.sess().generate_derive_registrar_symbol(disambiguator, idx);
+            let disambiguator = tcx.sess.local_crate_disambiguator();
+            return tcx.sess.generate_derive_registrar_symbol(disambiguator, idx);
         }
     }
 
     // FIXME(eddyb) Precompute a custom symbol name based on attributes.
-    let attrs = scx.tcx().get_attrs(def_id);
+    let attrs = tcx.get_attrs(def_id);
     let is_foreign = if let Some(id) = node_id {
-        match scx.tcx().hir.get(id) {
+        match tcx.hir.get(id) {
             hir_map::NodeForeignItem(_) => true,
             _ => false
         }
     } else {
-        scx.sess().cstore.is_foreign_item(def_id)
+        tcx.sess.cstore.is_foreign_item(def_id)
     };
 
     if let Some(name) = weak_lang_items::link_name(&attrs) {
@@ -210,17 +208,17 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
             return name.to_string();
         }
         // Don't mangle foreign items.
-        return scx.tcx().item_name(def_id).as_str().to_string();
+        return tcx.item_name(def_id).as_str().to_string();
     }
 
-    if let Some(name) = attr::find_export_name_attr(scx.sess().diagnostic(), &attrs) {
+    if let Some(name) = attr::find_export_name_attr(tcx.sess.diagnostic(), &attrs) {
         // Use provided name
         return name.to_string();
     }
 
     if attr::contains_name(&attrs, "no_mangle") {
         // Don't mangle
-        return scx.tcx().item_name(def_id).as_str().to_string();
+        return tcx.item_name(def_id).as_str().to_string();
     }
 
     // We want to compute the "type" of this item. Unfortunately, some
@@ -230,11 +228,11 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
     let mut ty_def_id = def_id;
     let instance_ty;
     loop {
-        let key = scx.tcx().def_key(ty_def_id);
+        let key = tcx.def_key(ty_def_id);
         match key.disambiguated_data.data {
             DefPathData::TypeNs(_) |
             DefPathData::ValueNs(_) => {
-                instance_ty = scx.tcx().item_type(ty_def_id);
+                instance_ty = tcx.item_type(ty_def_id);
                 break;
             }
             _ => {
@@ -251,23 +249,51 @@ pub fn symbol_name<'a, 'tcx>(instance: Instance<'tcx>,
 
     // Erase regions because they may not be deterministic when hashed
     // and should not matter anyhow.
-    let instance_ty = scx.tcx().erase_regions(&instance_ty);
-
-    let hash = get_symbol_hash(scx, Some(def_id), instance_ty, Some(substs));
+    let instance_ty = tcx.erase_regions(&instance_ty);
 
-    let mut buffer = SymbolPathBuffer {
-        names: Vec::new()
-    };
+    let hash = get_symbol_hash(tcx, Some(def_id), instance_ty, Some(substs));
 
+    let mut buffer = SymbolPathBuffer::new();
     item_path::with_forced_absolute_paths(|| {
-        scx.tcx().push_item_path(&mut buffer, def_id);
+        tcx.push_item_path(&mut buffer, def_id);
     });
-
-    mangle(buffer.names.into_iter(), &hash)
+    buffer.finish(&hash)
 }
 
+// Follow C++ namespace-mangling style, see
+// http://en.wikipedia.org/wiki/Name_mangling for more info.
+//
+// It turns out that on macOS you can actually have arbitrary symbols in
+// function names (at least when given to LLVM), but this is not possible
+// when using unix's linker. Perhaps one day when we just use a linker from LLVM
+// we won't need to do this name mangling. The problem with name mangling is
+// that it seriously limits the available characters. For example we can't
+// have things like &T in symbol names when one would theoretically
+// want them for things like impls of traits on that type.
+//
+// To be able to work on all platforms and get *some* reasonable output, we
+// use C++ name-mangling.
 struct SymbolPathBuffer {
-    names: Vec<InternedString>,
+    result: String,
+    temp_buf: String
+}
+
+impl SymbolPathBuffer {
+    fn new() -> Self {
+        let mut result = SymbolPathBuffer {
+            result: String::with_capacity(64),
+            temp_buf: String::with_capacity(16)
+        };
+        result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested
+        result
+    }
+
+    fn finish(mut self, hash: &str) -> String {
+        // end name-sequence
+        self.push(hash);
+        self.result.push('E');
+        self.result
+    }
 }
 
 impl ItemPathBuffer for SymbolPathBuffer {
@@ -277,24 +303,32 @@ impl ItemPathBuffer for SymbolPathBuffer {
     }
 
     fn push(&mut self, text: &str) {
-        self.names.push(Symbol::intern(text).as_str());
+        self.temp_buf.clear();
+        let need_underscore = sanitize(&mut self.temp_buf, text);
+        let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize));
+        if need_underscore {
+            self.result.push('_');
+        }
+        self.result.push_str(&self.temp_buf);
     }
 }
 
-pub fn exported_name_from_type_and_prefix<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+pub fn exported_name_from_type_and_prefix<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                     t: Ty<'tcx>,
                                                     prefix: &str)
                                                     -> String {
-    let hash = get_symbol_hash(scx, None, t, None);
-    let path = [Symbol::intern(prefix).as_str()];
-    mangle(path.iter().cloned(), &hash)
+    let hash = get_symbol_hash(tcx, None, t, None);
+    let mut buffer = SymbolPathBuffer::new();
+    buffer.push(prefix);
+    buffer.finish(&hash)
 }
 
 // Name sanitation. LLVM will happily accept identifiers with weird names, but
 // gas doesn't!
 // gas accepts the following characters in symbols: a-z, A-Z, 0-9, ., _, $
-pub fn sanitize(s: &str) -> String {
-    let mut result = String::new();
+//
+// returns true if an underscore must be added at the start
+pub fn sanitize(result: &mut String, s: &str) -> bool {
     for c in s.chars() {
         match c {
             // Escape these with $ sequences
@@ -331,44 +365,7 @@ pub fn sanitize(s: &str) -> String {
     }
 
     // Underscore-qualify anything that didn't start as an ident.
-    if !result.is_empty() &&
+    !result.is_empty() &&
         result.as_bytes()[0] != '_' as u8 &&
-        ! (result.as_bytes()[0] as char).is_xid_start() {
-        return format!("_{}", result);
-    }
-
-    return result;
-}
-
-fn mangle<PI: Iterator<Item=InternedString>>(path: PI, hash: &str) -> String {
-    // Follow C++ namespace-mangling style, see
-    // http://en.wikipedia.org/wiki/Name_mangling for more info.
-    //
-    // It turns out that on macOS you can actually have arbitrary symbols in
-    // function names (at least when given to LLVM), but this is not possible
-    // when using unix's linker. Perhaps one day when we just use a linker from LLVM
-    // we won't need to do this name mangling. The problem with name mangling is
-    // that it seriously limits the available characters. For example we can't
-    // have things like &T in symbol names when one would theoretically
-    // want them for things like impls of traits on that type.
-    //
-    // To be able to work on all platforms and get *some* reasonable output, we
-    // use C++ name-mangling.
-
-    let mut n = String::from("_ZN"); // _Z == Begin name-sequence, N == nested
-
-    fn push(n: &mut String, s: &str) {
-        let sani = sanitize(s);
-        n.push_str(&format!("{}{}", sani.len(), sani));
-    }
-
-    // First, connect each component with <len, name> pairs.
-    for data in path {
-        push(&mut n, &data);
-    }
-
-    push(&mut n, hash);
-
-    n.push('E'); // End name-sequence.
-    n
+        ! (result.as_bytes()[0] as char).is_xid_start()
 }
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index cb8022efedb..ba119bd9ef0 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -65,6 +65,7 @@ use meth;
 use mir;
 use monomorphize::{self, Instance};
 use partitioning::{self, PartitioningStrategy, CodegenUnit};
+use symbol_cache::SymbolCache;
 use symbol_map::SymbolMap;
 use symbol_names_test;
 use trans_item::{TransItem, DefPathBasedNames};
@@ -75,7 +76,6 @@ use util::nodemap::{NodeSet, FxHashMap, FxHashSet};
 
 use libc::c_uint;
 use std::ffi::{CStr, CString};
-use std::rc::Rc;
 use std::str;
 use std::i32;
 use syntax_pos::Span;
@@ -802,6 +802,7 @@ fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
 /// in any other compilation unit.  Give these symbols internal linkage.
 fn internalize_symbols<'a, 'tcx>(sess: &Session,
                                  scx: &SharedCrateContext<'a, 'tcx>,
+                                 translation_items: &FxHashSet<TransItem<'tcx>>,
                                  llvm_modules: &[ModuleLlvm],
                                  symbol_map: &SymbolMap<'tcx>,
                                  exported_symbols: &ExportedSymbols) {
@@ -854,7 +855,7 @@ fn internalize_symbols<'a, 'tcx>(sess: &Session,
             let mut locally_defined_symbols = FxHashSet();
             let mut linkage_fixed_explicitly = FxHashSet();
 
-            for trans_item in scx.translation_items().borrow().iter() {
+            for trans_item in translation_items {
                 let symbol_name = symbol_map.get_or_compute(scx, *trans_item);
                 if trans_item.explicit_linkage(tcx).is_some() {
                     linkage_fixed_explicitly.insert(symbol_name.clone());
@@ -1011,8 +1012,8 @@ fn iter_functions(llmod: llvm::ModuleRef) -> ValueIter {
 ///
 /// This list is later used by linkers to determine the set of symbols needed to
 /// be exposed from a dynamic library and it's also encoded into the metadata.
-pub fn find_exported_symbols(tcx: TyCtxt, reachable: NodeSet) -> NodeSet {
-    reachable.into_iter().filter(|&id| {
+pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet {
+    reachable.iter().cloned().filter(|&id| {
         // Next, we want to ignore some FFI functions that are not exposed from
         // this crate. Reachable FFI functions can be lumped into two
         // categories:
@@ -1064,7 +1065,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let krate = tcx.hir.krate();
 
     let ty::CrateAnalysis { reachable, .. } = analysis;
-    let exported_symbols = find_exported_symbols(tcx, reachable);
+    let exported_symbols = find_exported_symbols(tcx, &reachable);
 
     let check_overflow = tcx.sess.overflow_checks();
 
@@ -1109,9 +1110,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // Run the translation item collector and partition the collected items into
     // codegen units.
-    let (codegen_units, symbol_map) = collect_and_partition_translation_items(&shared_ccx);
-
-    let symbol_map = Rc::new(symbol_map);
+    let (translation_items, codegen_units, symbol_map) =
+        collect_and_partition_translation_items(&shared_ccx);
 
     let mut all_stats = Stats::default();
     let modules: Vec<ModuleTranslation> = codegen_units
@@ -1121,7 +1121,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             let (stats, module) =
                 tcx.dep_graph.with_task(dep_node,
                                         AssertDepGraphSafe(&shared_ccx),
-                                        AssertDepGraphSafe((cgu, symbol_map.clone())),
+                                        AssertDepGraphSafe(cgu),
                                         module_translation);
             all_stats.extend(stats);
             module
@@ -1130,16 +1130,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     fn module_translation<'a, 'tcx>(
         scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>,
-        args: AssertDepGraphSafe<(CodegenUnit<'tcx>, Rc<SymbolMap<'tcx>>)>)
+        args: AssertDepGraphSafe<CodegenUnit<'tcx>>)
         -> (Stats, ModuleTranslation)
     {
         // FIXME(#40304): We ought to be using the id as a key and some queries, I think.
         let AssertDepGraphSafe(scx) = scx;
-        let AssertDepGraphSafe((cgu, symbol_map)) = args;
+        let AssertDepGraphSafe(cgu) = args;
 
         let cgu_name = String::from(cgu.name());
         let cgu_id = cgu.work_product_id();
-        let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_map);
+        let symbol_cache = SymbolCache::new(scx.tcx());
+        let symbol_name_hash = cgu.compute_symbol_name_hash(scx, &symbol_cache);
 
         // Check whether there is a previous work-product we can
         // re-use.  Not only must the file exist, and the inputs not
@@ -1174,11 +1175,11 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
 
         // Instantiate translation items without filling out definitions yet...
-        let lcx = LocalCrateContext::new(scx, cgu, symbol_map.clone());
+        let lcx = LocalCrateContext::new(scx, cgu, &symbol_cache);
         let module = {
             let ccx = CrateContext::new(scx, &lcx);
             let trans_items = ccx.codegen_unit()
-                                 .items_in_deterministic_order(ccx.tcx(), &symbol_map);
+                                 .items_in_deterministic_order(ccx.tcx(), &symbol_cache);
             for &(trans_item, linkage) in &trans_items {
                 trans_item.predefine(&ccx, linkage);
             }
@@ -1238,7 +1239,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     assert_module_sources::assert_module_sources(tcx, &modules);
 
-    symbol_names_test::report_symbol_names(&shared_ccx);
+    symbol_names_test::report_symbol_names(tcx);
 
     if shared_ccx.sess().trans_stats() {
         println!("--- trans stats ---");
@@ -1289,6 +1290,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     time(shared_ccx.sess().time_passes(), "internalize symbols", || {
         internalize_symbols(sess,
                             &shared_ccx,
+                            &translation_items,
                             &llvm_modules,
                             &symbol_map,
                             &exported_symbols);
@@ -1517,7 +1519,9 @@ fn gather_type_sizes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
 }
 
 fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>)
-                                                     -> (Vec<CodegenUnit<'tcx>>, SymbolMap<'tcx>) {
+                                                     -> (FxHashSet<TransItem<'tcx>>,
+                                                         Vec<CodegenUnit<'tcx>>,
+                                                         SymbolMap<'tcx>) {
     let time_passes = scx.sess().time_passes();
 
     let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items {
@@ -1563,13 +1567,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
     assert!(scx.tcx().sess.opts.cg.codegen_units == codegen_units.len() ||
             scx.tcx().sess.opts.debugging_opts.incremental.is_some());
 
-    {
-        let mut ccx_map = scx.translation_items().borrow_mut();
-
-        for trans_item in items.iter().cloned() {
-            ccx_map.insert(trans_item);
-        }
-    }
+    let translation_items: FxHashSet<TransItem<'tcx>> = items.iter().cloned().collect();
 
     if scx.sess().opts.debugging_opts.print_trans_items.is_some() {
         let mut item_to_cgus = FxHashMap();
@@ -1624,5 +1622,5 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
         }
     }
 
-    (codegen_units, symbol_map)
+    (translation_items, codegen_units, symbol_map)
 }
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index aefee51191a..264e26e4594 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -14,18 +14,18 @@
 //! and methods are represented as just a fn ptr and not a full
 //! closure.
 
-use llvm::{self, ValueRef};
-use rustc::hir::def_id::DefId;
-use rustc::ty::subst::Substs;
 use attributes;
 use common::{self, CrateContext};
-use monomorphize;
 use consts;
 use declare;
-use monomorphize::Instance;
+use llvm::{self, ValueRef};
+use monomorphize::{self, Instance};
+use rustc::hir::def_id::DefId;
+use rustc::ty::{self, TypeFoldable};
+use rustc::ty::subst::Substs;
+use syntax_pos::DUMMY_SP;
 use trans_item::TransItem;
 use type_of;
-use rustc::ty::TypeFoldable;
 
 /// Translates a reference to a fn/method item, monomorphizing and
 /// inlining as it goes.
@@ -51,8 +51,7 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         return llfn;
     }
 
-    let sym = ccx.symbol_map().get_or_compute(ccx.shared(),
-                                              TransItem::Fn(instance));
+    let sym = ccx.symbol_cache().get(TransItem::Fn(instance));
     debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);
 
     // This is subtle and surprising, but sometimes we have to bitcast
@@ -102,15 +101,17 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let attrs = instance.def.attrs(ccx.tcx());
         attributes::from_fn_attrs(ccx, &attrs, llfn);
 
-        let is_local_def = ccx.shared().translation_items().borrow()
-                              .contains(&TransItem::Fn(instance));
-        if is_local_def {
-            // FIXME(eddyb) Doubt all extern fn should allow unwinding.
+        // Perhaps questionable, but we assume that anything defined
+        // *in Rust code* may unwind. Foreign items like `extern "C" {
+        // fn foo(); }` are assumed not to unwind **unless** they have
+        // a `#[unwind]` attribute.
+        if !ty::queries::is_foreign_item::get(tcx, DUMMY_SP, instance.def_id()) {
             attributes::unwind(llfn, true);
             unsafe {
                 llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
             }
         }
+
         if ccx.use_dll_storage_attrs() &&
             ccx.sess().cstore.is_dllimport_foreign_item(instance.def_id())
         {
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index ba2b807d5a0..13bb0d37125 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -467,13 +467,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
             // have to instantiate all methods of the trait being cast to, so we
             // can build the appropriate vtable.
             mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => {
-                let target_ty = monomorphize::apply_param_substs(self.scx,
-                                                                 self.param_substs,
-                                                                 &target_ty);
+                let target_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
+                                                                        &target_ty);
                 let source_ty = operand.ty(self.mir, self.scx.tcx());
-                let source_ty = monomorphize::apply_param_substs(self.scx,
-                                                                 self.param_substs,
-                                                                 &source_ty);
+                let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
+                                                                        &source_ty);
                 let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx,
                                                                             source_ty,
                                                                             target_ty);
@@ -489,10 +487,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
             }
             mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => {
                 let fn_ty = operand.ty(self.mir, self.scx.tcx());
-                let fn_ty = monomorphize::apply_param_substs(
-                    self.scx,
-                    self.param_substs,
-                    &fn_ty);
+                let fn_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
+                                                                    &fn_ty);
                 visit_fn_use(self.scx, fn_ty, false, &mut self.output);
             }
             mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => {
@@ -534,9 +530,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
         }
 
         if let mir::Literal::Item { def_id, substs } = constant.literal {
-            let substs = monomorphize::apply_param_substs(self.scx,
-                                                          self.param_substs,
-                                                          &substs);
+            let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs,
+                                                                 &substs);
             let instance = monomorphize::resolve(self.scx, def_id, substs);
             collect_neighbours(self.scx, instance, self.output);
         }
@@ -552,17 +547,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
         match *kind {
             mir::TerminatorKind::Call { ref func, .. } => {
                 let callee_ty = func.ty(self.mir, tcx);
-                let callee_ty = monomorphize::apply_param_substs(
-                    self.scx, self.param_substs, &callee_ty);
+                let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty);
                 visit_fn_use(self.scx, callee_ty, true, &mut self.output);
             }
             mir::TerminatorKind::Drop { ref location, .. } |
             mir::TerminatorKind::DropAndReplace { ref location, .. } => {
                 let ty = location.ty(self.mir, self.scx.tcx())
                     .to_ty(self.scx.tcx());
-                let ty = monomorphize::apply_param_substs(self.scx,
-                                                          self.param_substs,
-                                                          &ty);
+                let ty = tcx.trans_apply_param_substs(self.param_substs, &ty);
                 visit_drop_use(self.scx, ty, true, self.output);
             }
             mir::TerminatorKind::Goto { .. } |
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 5d58c935389..648ea92c843 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -564,7 +564,7 @@ pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
                         -> Ty<'tcx>
 {
     let ty = shared.tcx().item_type(def_id);
-    monomorphize::apply_param_substs(shared, substs, &ty)
+    shared.tcx().trans_apply_param_substs(substs, &ty)
 }
 
 /// Return the substituted type of an instance.
@@ -573,5 +573,5 @@ pub fn instance_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
                              -> Ty<'tcx>
 {
     let ty = instance.def.def_ty(shared.tcx());
-    monomorphize::apply_param_substs(shared, instance.substs, &ty)
+    shared.tcx().trans_apply_param_substs(instance.substs, &ty)
 }
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index eb3ac309be1..3d614cfbcbf 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -93,20 +93,19 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
             hir_map::NodeItem(&hir::Item {
                 ref attrs, span, node: hir::ItemStatic(..), ..
             }) => {
-                let sym = ccx.symbol_map()
-                             .get(TransItem::Static(id))
-                             .expect("Local statics should always be in the SymbolMap");
+                let sym = ccx.symbol_cache()
+                             .get(TransItem::Static(id));
 
                 let defined_in_current_codegen_unit = ccx.codegen_unit()
                                                          .items()
                                                          .contains_key(&TransItem::Static(id));
                 assert!(!defined_in_current_codegen_unit);
 
-                if declare::get_declared_value(ccx, sym).is_some() {
+                if declare::get_declared_value(ccx, &sym[..]).is_some() {
                     span_bug!(span, "trans: Conflicting symbol names for static?");
                 }
 
-                let g = declare::define_global(ccx, sym, llty).unwrap();
+                let g = declare::define_global(ccx, &sym[..], llty).unwrap();
 
                 (g, attrs)
             }
@@ -114,7 +113,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
             hir_map::NodeForeignItem(&hir::ForeignItem {
                 ref attrs, span, node: hir::ForeignItemStatic(..), ..
             }) => {
-                let sym = symbol_names::symbol_name(instance, ccx.shared());
+                let sym = symbol_names::symbol_name(instance, ccx.tcx());
                 let g = if let Some(name) =
                         attr::first_attr_value_str_by_name(&attrs, "linkage") {
                     // If this is a static with a linkage specified, then we need to handle
@@ -174,7 +173,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
 
         g
     } else {
-        let sym = symbol_names::symbol_name(instance, ccx.shared());
+        let sym = symbol_names::symbol_name(instance, ccx.tcx());
 
         // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
         // FIXME(nagisa): investigate whether it can be changed into define_global
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 1d1921bf7b9..bef22cf304d 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -10,7 +10,7 @@
 
 use llvm;
 use llvm::{ContextRef, ModuleRef, ValueRef};
-use rustc::dep_graph::{DepGraph, DepGraphSafe, DepNode, DepTrackingMap, DepTrackingMapConfig};
+use rustc::dep_graph::{DepGraph, DepGraphSafe};
 use rustc::hir;
 use rustc::hir::def_id::DefId;
 use rustc::traits;
@@ -21,7 +21,6 @@ use declare;
 use monomorphize::Instance;
 
 use partitioning::CodegenUnit;
-use trans_item::TransItem;
 use type_::Type;
 use rustc_data_structures::base_n;
 use rustc::ty::subst::Substs;
@@ -30,15 +29,13 @@ use rustc::ty::layout::{LayoutTyper, TyLayout};
 use session::config::NoDebugInfo;
 use session::Session;
 use session::config;
-use symbol_map::SymbolMap;
-use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
+use symbol_cache::SymbolCache;
+use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
 
 use std::ffi::{CStr, CString};
 use std::cell::{Cell, RefCell};
-use std::marker::PhantomData;
 use std::ptr;
 use std::iter;
-use std::rc::Rc;
 use std::str;
 use syntax::ast;
 use syntax::symbol::InternedString;
@@ -86,17 +83,13 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
     check_overflow: bool,
 
     use_dll_storage_attrs: bool,
-
-    translation_items: RefCell<FxHashSet<TransItem<'tcx>>>,
-    trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
-    project_cache: RefCell<DepTrackingMap<ProjectionCache<'tcx>>>,
 }
 
 /// The local portion of a `CrateContext`.  There is one `LocalCrateContext`
 /// per compilation unit.  Each one has its own LLVM `ContextRef` so that
 /// several compilation units may be optimized in parallel.  All other LLVM
 /// data structures in the `LocalCrateContext` are tied to that `ContextRef`.
-pub struct LocalCrateContext<'tcx> {
+pub struct LocalCrateContext<'a, 'tcx: 'a> {
     llmod: ModuleRef,
     llcx: ContextRef,
     stats: Stats,
@@ -168,60 +161,10 @@ pub struct LocalCrateContext<'tcx> {
     /// Depth of the current type-of computation - used to bail out
     type_of_depth: Cell<usize>,
 
-    symbol_map: Rc<SymbolMap<'tcx>>,
-
     /// A counter that is used for generating local symbol names
     local_gen_sym_counter: Cell<usize>,
-}
 
-// Implement DepTrackingMapConfig for `trait_cache`
-pub struct TraitSelectionCache<'tcx> {
-    data: PhantomData<&'tcx ()>
-}
-
-impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
-    type Key = ty::PolyTraitRef<'tcx>;
-    type Value = traits::Vtable<'tcx, ()>;
-    fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode<DefId> {
-        key.to_poly_trait_predicate().dep_node()
-    }
-}
-
-// # Global Cache
-
-pub struct ProjectionCache<'gcx> {
-    data: PhantomData<&'gcx ()>
-}
-
-impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
-    type Key = Ty<'gcx>;
-    type Value = Ty<'gcx>;
-    fn to_dep_node(key: &Self::Key) -> DepNode<DefId> {
-        // Ideally, we'd just put `key` into the dep-node, but we
-        // can't put full types in there. So just collect up all the
-        // def-ids of structs/enums as well as any traits that we
-        // project out of. It doesn't matter so much what we do here,
-        // except that if we are too coarse, we'll create overly
-        // coarse edges between impls and the trans. For example, if
-        // we just used the def-id of things we are projecting out of,
-        // then the key for `<Foo as SomeTrait>::T` and `<Bar as
-        // SomeTrait>::T` would both share a dep-node
-        // (`TraitSelect(SomeTrait)`), and hence the impls for both
-        // `Foo` and `Bar` would be considered inputs. So a change to
-        // `Bar` would affect things that just normalized `Foo`.
-        // Anyway, this heuristic is not ideal, but better than
-        // nothing.
-        let def_ids: Vec<DefId> =
-            key.walk()
-               .filter_map(|t| match t.sty {
-                   ty::TyAdt(adt_def, _) => Some(adt_def.did),
-                   ty::TyProjection(ref proj) => Some(proj.trait_ref.def_id),
-                   _ => None,
-               })
-               .collect();
-
-        DepNode::ProjectionCache { def_ids: def_ids }
-    }
+    symbol_cache: &'a SymbolCache<'a, 'tcx>,
 }
 
 /// A CrateContext value binds together one LocalCrateContext with the
@@ -229,12 +172,12 @@ impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> {
 /// pass around (SharedCrateContext, LocalCrateContext) tuples all over trans.
 pub struct CrateContext<'a, 'tcx: 'a> {
     shared: &'a SharedCrateContext<'a, 'tcx>,
-    local_ccx: &'a LocalCrateContext<'tcx>,
+    local_ccx: &'a LocalCrateContext<'a, 'tcx>,
 }
 
 impl<'a, 'tcx> CrateContext<'a, 'tcx> {
     pub fn new(shared: &'a SharedCrateContext<'a, 'tcx>,
-               local_ccx: &'a LocalCrateContext<'tcx>)
+               local_ccx: &'a LocalCrateContext<'a, 'tcx>)
                -> Self {
         CrateContext { shared, local_ccx }
     }
@@ -385,9 +328,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
             tcx: tcx,
             check_overflow: check_overflow,
             use_dll_storage_attrs: use_dll_storage_attrs,
-            translation_items: RefCell::new(FxHashSet()),
-            trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
-            project_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
         }
     }
 
@@ -407,14 +347,6 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
         &self.exported_symbols
     }
 
-    pub fn trait_cache(&self) -> &RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>> {
-        &self.trait_cache
-    }
-
-    pub fn project_cache(&self) -> &RefCell<DepTrackingMap<ProjectionCache<'tcx>>> {
-        &self.project_cache
-    }
-
     pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
         self.tcx
     }
@@ -430,17 +362,13 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
     pub fn use_dll_storage_attrs(&self) -> bool {
         self.use_dll_storage_attrs
     }
-
-    pub fn translation_items(&self) -> &RefCell<FxHashSet<TransItem<'tcx>>> {
-        &self.translation_items
-    }
 }
 
-impl<'tcx> LocalCrateContext<'tcx> {
-    pub fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
-                   codegen_unit: CodegenUnit<'tcx>,
-                   symbol_map: Rc<SymbolMap<'tcx>>)
-                   -> LocalCrateContext<'tcx> {
+impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
+    pub fn new(shared: &SharedCrateContext<'a, 'tcx>,
+               codegen_unit: CodegenUnit<'tcx>,
+               symbol_cache: &'a SymbolCache<'a, 'tcx>)
+               -> LocalCrateContext<'a, 'tcx> {
         unsafe {
             // Append ".rs" to LLVM module identifier.
             //
@@ -494,8 +422,8 @@ impl<'tcx> LocalCrateContext<'tcx> {
                 rust_try_fn: Cell::new(None),
                 intrinsics: RefCell::new(FxHashMap()),
                 type_of_depth: Cell::new(0),
-                symbol_map: symbol_map,
                 local_gen_sym_counter: Cell::new(0),
+                symbol_cache: symbol_cache,
             };
 
             let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = {
@@ -529,9 +457,9 @@ impl<'tcx> LocalCrateContext<'tcx> {
     /// This is used in the `LocalCrateContext` constructor to allow calling
     /// functions that expect a complete `CrateContext`, even before the local
     /// portion is fully initialized and attached to the `SharedCrateContext`.
-    fn dummy_ccx<'a>(shared: &'a SharedCrateContext<'a, 'tcx>,
-                     local_ccxs: &'a [LocalCrateContext<'tcx>])
-                     -> CrateContext<'a, 'tcx> {
+    fn dummy_ccx(shared: &'a SharedCrateContext<'a, 'tcx>,
+                 local_ccxs: &'a [LocalCrateContext<'a, 'tcx>])
+                 -> CrateContext<'a, 'tcx> {
         assert!(local_ccxs.len() == 1);
         CrateContext {
             shared: shared,
@@ -549,7 +477,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         self.shared
     }
 
-    fn local(&self) -> &'b LocalCrateContext<'tcx> {
+    fn local(&self) -> &'b LocalCrateContext<'b, 'tcx> {
         self.local_ccx
     }
 
@@ -716,12 +644,8 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         self.shared.use_dll_storage_attrs()
     }
 
-    pub fn symbol_map(&self) -> &SymbolMap<'tcx> {
-        &*self.local().symbol_map
-    }
-
-    pub fn translation_items(&self) -> &RefCell<FxHashSet<TransItem<'tcx>>> {
-        &self.shared.translation_items
+    pub fn symbol_cache(&self) -> &'b SymbolCache<'b, 'tcx> {
+        self.local().symbol_cache
     }
 
     /// Given the def-id of some item that has no type parameters, make
@@ -847,6 +771,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
     type TyLayout = TyLayout<'tcx>;
 
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
+        if let Some(&layout) = self.tcx().layout_cache.borrow().get(&ty) {
+            return TyLayout { ty: ty, layout: layout, variant_index: None };
+        }
+
         self.tcx().infer_ctxt((), traits::Reveal::All).enter(|infcx| {
             infcx.layout_of(ty).unwrap_or_else(|e| {
                 match e {
@@ -857,6 +785,10 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a SharedCrateContext<'a, 'tcx> {
             })
         })
     }
+
+    fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.tcx().normalize_associated_type(&ty)
+    }
 }
 
 impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> {
@@ -865,9 +797,13 @@ impl<'a, 'tcx> LayoutTyper<'tcx> for &'a CrateContext<'a, 'tcx> {
     fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout {
         self.shared.layout_of(ty)
     }
+
+    fn normalize_projections(self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        self.shared.normalize_projections(ty)
+    }
 }
 
-pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>);
+pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'a, 'tcx>);
 
 impl<'a, 'tcx> Drop for TypeOfDepthLock<'a, 'tcx> {
     fn drop(&mut self) {
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index be214a0f614..117d8568500 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -124,6 +124,7 @@ mod meth;
 mod mir;
 mod monomorphize;
 mod partitioning;
+mod symbol_cache;
 mod symbol_map;
 mod symbol_names_test;
 mod trans_item;
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 8bce0cf85c0..040194e63d0 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -100,15 +100,13 @@ impl<'tcx> Const<'tcx> {
             ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
             ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
             ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
+            ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
+            ConstVal::Function(..) => C_null(type_of::type_of(ccx, ty)),
+            ConstVal::Variant(_) |
             ConstVal::Struct(_) | ConstVal::Tuple(_) |
             ConstVal::Array(..) | ConstVal::Repeat(..) => {
                 bug!("MIR must not use `{:?}` (aggregates are expanded to MIR rvalues)", cv)
             }
-            ConstVal::Function(..) => {
-                let llty = type_of::type_of(ccx, ty);
-                return Const::new(C_null(llty), ty);
-            }
-            ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
         };
 
         assert!(!ty.has_erasable_regions());
@@ -260,9 +258,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
     fn monomorphize<T>(&self, value: &T) -> T
         where T: TransNormalize<'tcx>
     {
-        monomorphize::apply_param_substs(self.ccx.shared(),
-                                         self.substs,
-                                         value)
+        self.ccx.tcx().trans_apply_param_substs(self.substs, value)
     }
 
     fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
@@ -710,7 +706,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                 let tr_lvalue = self.const_lvalue(lvalue, span)?;
 
                 let ty = tr_lvalue.ty;
-                let ref_ty = tcx.mk_ref(tcx.mk_region(ty::ReErased),
+                let ref_ty = tcx.mk_ref(tcx.types.re_erased,
                     ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() });
 
                 let base = match tr_lvalue.base {
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index d39a91405c1..af0e27c8ca3 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -22,7 +22,7 @@ use base;
 use builder::Builder;
 use common::{self, CrateContext, Funclet};
 use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
-use monomorphize::{self, Instance};
+use monomorphize::Instance;
 use abi::FnType;
 use type_of;
 
@@ -102,8 +102,9 @@ pub struct MirContext<'a, 'tcx:'a> {
 
 impl<'a, 'tcx> MirContext<'a, 'tcx> {
     pub fn monomorphize<T>(&self, value: &T) -> T
-        where T: TransNormalize<'tcx> {
-        monomorphize::apply_param_substs(self.ccx.shared(), self.param_substs, value)
+        where T: TransNormalize<'tcx>
+    {
+        self.ccx.tcx().trans_apply_param_substs(self.param_substs, value)
     }
 
     pub fn set_debug_loc(&mut self, bcx: &Builder, source_info: mir::SourceInfo) {
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index de1c1e492f3..b8e9a490b0e 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -329,7 +329,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
 
                 let ty = tr_lvalue.ty.to_ty(bcx.tcx());
                 let ref_ty = bcx.tcx().mk_ref(
-                    bcx.tcx().mk_region(ty::ReErased),
+                    bcx.tcx().types.re_erased,
                     ty::TypeAndMut { ty: ty, mutbl: bk.to_mutbl_lossy() }
                 );
 
diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs
index 382ca8ef010..d27eeb2b646 100644
--- a/src/librustc_trans/monomorphize.rs
+++ b/src/librustc_trans/monomorphize.rs
@@ -13,17 +13,13 @@ use common::*;
 use glue;
 
 use rustc::hir::def_id::DefId;
-use rustc::infer::TransNormalize;
 use rustc::middle::lang_items::DropInPlaceFnLangItem;
-use rustc::traits::{self, SelectionContext, Reveal};
+use rustc::traits;
 use rustc::ty::adjustment::CustomCoerceUnsized;
-use rustc::ty::fold::{TypeFolder, TypeFoldable};
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::util::common::MemoizationMap;
 
-use syntax::ast;
-use syntax::codemap::{Span, DUMMY_SP};
+use syntax::codemap::DUMMY_SP;
 
 pub use rustc::ty::Instance;
 
@@ -104,73 +100,6 @@ pub fn resolve_closure<'a, 'tcx> (
     }
 }
 
-/// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we
-/// do not (necessarily) resolve all nested obligations on the impl. Note that type check should
-/// guarantee to us that all nested obligations *could be* resolved if we wanted to.
-fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
-                                span: Span,
-                                trait_ref: ty::PolyTraitRef<'tcx>)
-                                -> traits::Vtable<'tcx, ()>
-{
-    let tcx = scx.tcx();
-
-    // Remove any references to regions; this helps improve caching.
-    let trait_ref = tcx.erase_regions(&trait_ref);
-
-    scx.trait_cache().memoize(trait_ref, || {
-        debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})",
-               trait_ref, trait_ref.def_id());
-
-        // Do the initial selection for the obligation. This yields the
-        // shallow result we are looking for -- that is, what specific impl.
-        tcx.infer_ctxt((), Reveal::All).enter(|infcx| {
-            let mut selcx = SelectionContext::new(&infcx);
-
-            let obligation_cause = traits::ObligationCause::misc(span,
-                                                             ast::DUMMY_NODE_ID);
-            let obligation = traits::Obligation::new(obligation_cause,
-                                                     trait_ref.to_poly_trait_predicate());
-
-            let selection = match selcx.select(&obligation) {
-                Ok(Some(selection)) => selection,
-                Ok(None) => {
-                    // Ambiguity can happen when monomorphizing during trans
-                    // expands to some humongo type that never occurred
-                    // statically -- this humongo type can then overflow,
-                    // leading to an ambiguous result. So report this as an
-                    // overflow bug, since I believe this is the only case
-                    // where ambiguity can result.
-                    debug!("Encountered ambiguity selecting `{:?}` during trans, \
-                            presuming due to overflow",
-                           trait_ref);
-                    tcx.sess.span_fatal(span,
-                        "reached the recursion limit during monomorphization \
-                         (selection ambiguity)");
-                }
-                Err(e) => {
-                    span_bug!(span, "Encountered error `{:?}` selecting `{:?}` during trans",
-                              e, trait_ref)
-                }
-            };
-
-            debug!("fulfill_obligation: selection={:?}", selection);
-
-            // Currently, we use a fulfillment context to completely resolve
-            // all nested obligations. This is because they can inform the
-            // inference of the impl's type parameters.
-            let mut fulfill_cx = traits::FulfillmentContext::new();
-            let vtable = selection.map(|predicate| {
-                debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate);
-                fulfill_cx.register_predicate_obligation(&infcx, predicate);
-            });
-            let vtable = infcx.drain_fulfillment_cx_or_panic(span, &mut fulfill_cx, &vtable);
-
-            info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
-            vtable
-        })
-    })
-}
-
 fn resolve_associated_item<'a, 'tcx>(
     scx: &SharedCrateContext<'a, 'tcx>,
     trait_item: &ty::AssociatedItem,
@@ -185,7 +114,7 @@ fn resolve_associated_item<'a, 'tcx>(
            def_id, trait_id, rcvr_substs);
 
     let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs);
-    let vtbl = fulfill_obligation(scx, DUMMY_SP, ty::Binder(trait_ref));
+    let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::Binder(trait_ref));
 
     // Now that we know which impl is being used, we can dispatch to
     // the actual function:
@@ -285,7 +214,7 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx
         substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty])
     });
 
-    match fulfill_obligation(scx, DUMMY_SP, trait_ref) {
+    match scx.tcx().trans_fulfill_obligation(DUMMY_SP, trait_ref) {
         traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
             scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap()
         }
@@ -295,21 +224,6 @@ pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx
     }
 }
 
-/// Monomorphizes a type from the AST by first applying the in-scope
-/// substitutions and then normalizing any associated types.
-pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>,
-                                       param_substs: &Substs<'tcx>,
-                                       value: &T)
-                                       -> T
-    where T: TransNormalize<'tcx>
-{
-    let tcx = scx.tcx();
-    debug!("apply_param_substs(param_substs={:?}, value={:?})", param_substs, value);
-    let substituted = value.subst(tcx, param_substs);
-    let substituted = scx.tcx().erase_regions(&substituted);
-    AssociatedTypeNormalizer::new(scx).fold(&substituted)
-}
-
 /// Returns the normalized type of a struct field
 pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           param_substs: &Substs<'tcx>,
@@ -319,39 +233,3 @@ pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     tcx.normalize_associated_type(&f.ty(tcx, param_substs))
 }
 
-struct AssociatedTypeNormalizer<'a, 'b: 'a, 'gcx: 'b> {
-    shared: &'a SharedCrateContext<'b, 'gcx>,
-}
-
-impl<'a, 'b, 'gcx> AssociatedTypeNormalizer<'a, 'b, 'gcx> {
-    fn new(shared: &'a SharedCrateContext<'b, 'gcx>) -> Self {
-        AssociatedTypeNormalizer {
-            shared: shared,
-        }
-    }
-
-    fn fold<T:TypeFoldable<'gcx>>(&mut self, value: &T) -> T {
-        if !value.has_projection_types() {
-            value.clone()
-        } else {
-            value.fold_with(self)
-        }
-    }
-}
-
-impl<'a, 'b, 'gcx> TypeFolder<'gcx, 'gcx> for AssociatedTypeNormalizer<'a, 'b, 'gcx> {
-    fn tcx<'c>(&'c self) -> TyCtxt<'c, 'gcx, 'gcx> {
-        self.shared.tcx()
-    }
-
-    fn fold_ty(&mut self, ty: Ty<'gcx>) -> Ty<'gcx> {
-        if !ty.has_projection_types() {
-            ty
-        } else {
-            self.shared.project_cache().memoize(ty, || {
-                debug!("AssociatedTypeNormalizer: ty={:?}", ty);
-                self.shared.tcx().normalize_associated_type(&ty)
-            })
-        }
-    }
-}
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index 4973181202e..6b89d11cfb6 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -116,7 +116,7 @@ use rustc_incremental::IchHasher;
 use std::cmp::Ordering;
 use std::hash::Hash;
 use std::sync::Arc;
-use symbol_map::SymbolMap;
+use symbol_cache::SymbolCache;
 use syntax::ast::NodeId;
 use syntax::symbol::{Symbol, InternedString};
 use trans_item::{TransItem, InstantiationMode};
@@ -174,14 +174,15 @@ impl<'tcx> CodegenUnit<'tcx> {
         DepNode::WorkProduct(self.work_product_id())
     }
 
-    pub fn compute_symbol_name_hash(&self,
-                                    scx: &SharedCrateContext,
-                                    symbol_map: &SymbolMap) -> u64 {
+    pub fn compute_symbol_name_hash<'a>(&self,
+                                        scx: &SharedCrateContext<'a, 'tcx>,
+                                        symbol_cache: &SymbolCache<'a, 'tcx>)
+                                        -> u64 {
         let mut state = IchHasher::new();
         let exported_symbols = scx.exported_symbols();
-        let all_items = self.items_in_deterministic_order(scx.tcx(), symbol_map);
+        let all_items = self.items_in_deterministic_order(scx.tcx(), symbol_cache);
         for (item, _) in all_items {
-            let symbol_name = symbol_map.get(item).unwrap();
+            let symbol_name = symbol_cache.get(item);
             symbol_name.len().hash(&mut state);
             symbol_name.hash(&mut state);
             let exported = match item {
@@ -201,10 +202,10 @@ impl<'tcx> CodegenUnit<'tcx> {
         state.finish().to_smaller_hash()
     }
 
-    pub fn items_in_deterministic_order(&self,
-                                        tcx: TyCtxt,
-                                        symbol_map: &SymbolMap)
-                                        -> Vec<(TransItem<'tcx>, llvm::Linkage)> {
+    pub fn items_in_deterministic_order<'a>(&self,
+                                            tcx: TyCtxt,
+                                            symbol_cache: &SymbolCache<'a, 'tcx>)
+                                            -> Vec<(TransItem<'tcx>, llvm::Linkage)> {
         let mut items: Vec<(TransItem<'tcx>, llvm::Linkage)> =
             self.items.iter().map(|(item, linkage)| (*item, *linkage)).collect();
 
@@ -216,9 +217,9 @@ impl<'tcx> CodegenUnit<'tcx> {
 
             match (node_id1, node_id2) {
                 (None, None) => {
-                    let symbol_name1 = symbol_map.get(trans_item1).unwrap();
-                    let symbol_name2 = symbol_map.get(trans_item2).unwrap();
-                    symbol_name1.cmp(symbol_name2)
+                    let symbol_name1 = symbol_cache.get(trans_item1);
+                    let symbol_name2 = symbol_cache.get(trans_item2);
+                    symbol_name1.cmp(&symbol_name2)
                 }
                 // In the following two cases we can avoid looking up the symbol
                 (None, Some(_)) => Ordering::Less,
@@ -230,9 +231,9 @@ impl<'tcx> CodegenUnit<'tcx> {
                         return ordering;
                     }
 
-                    let symbol_name1 = symbol_map.get(trans_item1).unwrap();
-                    let symbol_name2 = symbol_map.get(trans_item2).unwrap();
-                    symbol_name1.cmp(symbol_name2)
+                    let symbol_name1 = symbol_cache.get(trans_item1);
+                    let symbol_name2 = symbol_cache.get(trans_item2);
+                    symbol_name1.cmp(&symbol_name2)
                 }
             }
         });
@@ -271,14 +272,14 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
     let mut initial_partitioning = place_root_translation_items(scx,
                                                                 trans_items);
 
-    debug_dump(scx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter());
+    debug_dump(tcx, "INITIAL PARTITONING:", initial_partitioning.codegen_units.iter());
 
     // If the partitioning should produce a fixed count of codegen units, merge
     // until that count is reached.
     if let PartitioningStrategy::FixedUnitCount(count) = strategy {
         merge_codegen_units(&mut initial_partitioning, count, &tcx.crate_name.as_str());
 
-        debug_dump(scx, "POST MERGING:", initial_partitioning.codegen_units.iter());
+        debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
     }
 
     // In the next step, we use the inlining map to determine which addtional
@@ -288,7 +289,7 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
     let post_inlining = place_inlined_translation_items(initial_partitioning,
                                                         inlining_map);
 
-    debug_dump(scx, "POST INLINING:", post_inlining.0.iter());
+    debug_dump(tcx, "POST INLINING:", post_inlining.0.iter());
 
     // Finally, sort by codegen unit name, so that we get deterministic results
     let mut result = post_inlining.0;
@@ -528,7 +529,7 @@ fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString
     Symbol::intern(&format!("{}{}{}", crate_name, NUMBERED_CODEGEN_UNIT_MARKER, index)).as_str()
 }
 
-fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
+fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                label: &str,
                                cgus: I)
     where I: Iterator<Item=&'b CodegenUnit<'tcx>>,
@@ -536,20 +537,18 @@ fn debug_dump<'a, 'b, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
 {
     if cfg!(debug_assertions) {
         debug!("{}", label);
+        let symbol_cache = SymbolCache::new(tcx);
         for cgu in cgus {
-            let symbol_map = SymbolMap::build(scx, cgu.items
-                                                      .iter()
-                                                      .map(|(&trans_item, _)| trans_item));
             debug!("CodegenUnit {}:", cgu.name);
 
             for (trans_item, linkage) in &cgu.items {
-                let symbol_name = symbol_map.get_or_compute(scx, *trans_item);
+                let symbol_name = symbol_cache.get(*trans_item);
                 let symbol_hash_start = symbol_name.rfind('h');
                 let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..])
                                                    .unwrap_or("<no hash>");
 
                 debug!(" - {} [{:?}] [{}]",
-                       trans_item.to_string(scx.tcx()),
+                       trans_item.to_string(tcx),
                        linkage,
                        symbol_hash);
             }
diff --git a/src/librustc_trans/symbol_cache.rs b/src/librustc_trans/symbol_cache.rs
new file mode 100644
index 00000000000..ddc1ef537a5
--- /dev/null
+++ b/src/librustc_trans/symbol_cache.rs
@@ -0,0 +1,42 @@
+// Copyright 2016 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 rustc::ty::TyCtxt;
+use std::cell::RefCell;
+use syntax_pos::symbol::{InternedString, Symbol};
+use trans_item::TransItem;
+use util::nodemap::FxHashMap;
+
+// In the SymbolCache we collect the symbol names of translation items
+// and cache them for later reference. This is just a performance
+// optimization and the cache is populated lazilly; symbol names of
+// translation items are deterministic and fully defined by the item.
+// Thus they can always be recomputed if needed.
+
+pub struct SymbolCache<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    index: RefCell<FxHashMap<TransItem<'tcx>, Symbol>>,
+}
+
+impl<'a, 'tcx> SymbolCache<'a, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+        SymbolCache {
+            tcx: tcx,
+            index: RefCell::new(FxHashMap())
+        }
+    }
+
+    pub fn get(&self, trans_item: TransItem<'tcx>) -> InternedString {
+        let mut index = self.index.borrow_mut();
+        index.entry(trans_item)
+             .or_insert_with(|| Symbol::intern(&trans_item.compute_symbol_name(self.tcx)))
+             .as_str()
+    }
+}
diff --git a/src/librustc_trans/symbol_map.rs b/src/librustc_trans/symbol_map.rs
index 36c3981e3a6..9d3e62888a2 100644
--- a/src/librustc_trans/symbol_map.rs
+++ b/src/librustc_trans/symbol_map.rs
@@ -34,8 +34,9 @@ impl<'tcx> SymbolMap<'tcx> {
         where I: Iterator<Item=TransItem<'tcx>>
     {
         // Check for duplicate symbol names
+        let tcx = scx.tcx();
         let mut symbols: Vec<_> = trans_items.map(|trans_item| {
-            (trans_item, trans_item.compute_symbol_name(scx))
+            (trans_item, trans_item.compute_symbol_name(tcx))
         }).collect();
 
         (&mut symbols[..]).sort_by(|&(_, ref sym1), &(_, ref sym2)|{
@@ -124,7 +125,7 @@ impl<'tcx> SymbolMap<'tcx> {
         if let Some(sym) = self.get(trans_item) {
             Cow::from(sym)
         } else {
-            Cow::from(trans_item.compute_symbol_name(scx))
+            Cow::from(trans_item.compute_symbol_name(scx.tcx()))
         }
     }
 }
diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs
index fe551b06b3d..fd817cb94c1 100644
--- a/src/librustc_trans/symbol_names_test.rs
+++ b/src/librustc_trans/symbol_names_test.rs
@@ -17,43 +17,42 @@
 use back::symbol_names;
 use rustc::hir;
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
+use rustc::ty::TyCtxt;
 use syntax::ast;
 
-use common::SharedCrateContext;
 use monomorphize::Instance;
 
 const SYMBOL_NAME: &'static str = "rustc_symbol_name";
 const ITEM_PATH: &'static str = "rustc_item_path";
 
-pub fn report_symbol_names(scx: &SharedCrateContext) {
+pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     // if the `rustc_attrs` feature is not enabled, then the
     // attributes we are interested in cannot be present anyway, so
     // skip the walk.
-    let tcx = scx.tcx();
     if !tcx.sess.features.borrow().rustc_attrs {
         return;
     }
 
     let _ignore = tcx.dep_graph.in_ignore();
-    let mut visitor = SymbolNamesTest { scx: scx };
+    let mut visitor = SymbolNamesTest { tcx: tcx };
     // FIXME(#37712) could use ItemLikeVisitor if trait items were item-like
     tcx.hir.krate().visit_all_item_likes(&mut visitor.as_deep_visitor());
 }
 
 struct SymbolNamesTest<'a, 'tcx:'a> {
-    scx: &'a SharedCrateContext<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> {
     fn process_attrs(&mut self,
                      node_id: ast::NodeId) {
-        let tcx = self.scx.tcx();
+        let tcx = self.tcx;
         let def_id = tcx.hir.local_def_id(node_id);
         for attr in tcx.get_attrs(def_id).iter() {
             if attr.check_name(SYMBOL_NAME) {
                 // for now, can only use on monomorphic names
                 let instance = Instance::mono(tcx, def_id);
-                let name = symbol_names::symbol_name(instance, self.scx);
+                let name = symbol_names::symbol_name(instance, self.tcx);
                 tcx.sess.span_err(attr.span, &format!("symbol-name({})", name));
             } else if attr.check_name(ITEM_PATH) {
                 let path = tcx.item_path_str(def_id);
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 4d908f3c94f..de35d1b7dd4 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -18,7 +18,7 @@ use asm;
 use attributes;
 use base;
 use consts;
-use context::{CrateContext, SharedCrateContext};
+use context::CrateContext;
 use common;
 use declare;
 use llvm;
@@ -118,8 +118,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
                self.to_raw_string(),
                ccx.codegen_unit().name());
 
-        let symbol_name = ccx.symbol_map()
-                             .get_or_compute(ccx.shared(), *self);
+        let symbol_name = ccx.symbol_cache().get(*self);
 
         debug!("symbol {}", &symbol_name);
 
@@ -185,16 +184,15 @@ impl<'a, 'tcx> TransItem<'tcx> {
         ccx.instances().borrow_mut().insert(instance, lldecl);
     }
 
-    pub fn compute_symbol_name(&self,
-                               scx: &SharedCrateContext<'a, 'tcx>) -> String {
+    pub fn compute_symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
         match *self {
-            TransItem::Fn(instance) => symbol_names::symbol_name(instance, scx),
+            TransItem::Fn(instance) => symbol_names::symbol_name(instance, tcx),
             TransItem::Static(node_id) => {
-                let def_id = scx.tcx().hir.local_def_id(node_id);
-                symbol_names::symbol_name(Instance::mono(scx.tcx(), def_id), scx)
+                let def_id = tcx.hir.local_def_id(node_id);
+                symbol_names::symbol_name(Instance::mono(tcx, def_id), tcx)
             }
             TransItem::GlobalAsm(node_id) => {
-                let def_id = scx.tcx().hir.local_def_id(node_id);
+                let def_id = tcx.hir.local_def_id(node_id);
                 format!("global_asm_{:?}", def_id)
             }
         }
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 9426d601dfc..5137ae6ff42 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -109,7 +109,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         let tcx = self.tcx();
         let r = match tcx.named_region_map.defs.get(&lifetime.id) {
             Some(&rl::Region::Static) => {
-                tcx.mk_region(ty::ReStatic)
+                tcx.types.re_static
             }
 
             Some(&rl::Region::LateBound(debruijn, id)) => {
@@ -171,7 +171,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                     .emit();
 
                 return Substs::for_item(tcx, def_id, |_, _| {
-                    tcx.mk_region(ty::ReStatic)
+                    tcx.types.re_static
                 }, |_, _| {
                     tcx.types.err
                 });
@@ -254,7 +254,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             if let Some(lifetime) = lifetimes.get(i) {
                 self.ast_region_to_region(lifetime, Some(def))
             } else {
-                tcx.mk_region(ty::ReStatic)
+                tcx.types.re_static
             }
         }, |def, substs| {
             let i = def.index as usize;
@@ -715,7 +715,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                         span_err!(tcx.sess, span, E0228,
                                   "the lifetime bound for this object type cannot be deduced \
                                    from context; please supply an explicit bound");
-                        tcx.mk_region(ty::ReStatic)
+                        tcx.types.re_static
                     })
                 }
             })
@@ -1357,7 +1357,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         // If any of the derived region bounds are 'static, that is always
         // the best choice.
         if derived_region_bounds.iter().any(|&r| ty::ReStatic == *r) {
-            return Some(tcx.mk_region(ty::ReStatic));
+            return Some(tcx.types.re_static);
         }
 
         // Determine whether there is exactly one unique region in the set
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index 4a044642444..1086773041c 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -55,7 +55,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         let expected_ty = self.structurally_resolved_type(pat.span, expected);
                         if let ty::TyRef(_, mt) = expected_ty.sty {
                             if let ty::TySlice(_) = mt.ty.sty {
-                                pat_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic),
+                                pat_ty = tcx.mk_imm_ref(tcx.types.re_static,
                                                          tcx.mk_slice(tcx.types.u8))
                             }
                         }
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index b71ff58ccec..c125d7c0255 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -15,12 +15,11 @@ use middle::free_region::FreeRegionMap;
 use rustc::infer::{self, InferOk};
 use middle::region;
 use rustc::ty::subst::{Subst, Substs};
-use rustc::ty::{self, AdtKind, Ty, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt};
 use rustc::traits::{self, ObligationCause, Reveal};
 use util::common::ErrorReported;
 use util::nodemap::FxHashSet;
 
-use syntax::ast;
 use syntax_pos::Span;
 
 /// check_drop_impl confirms that the Drop implementation identfied by
@@ -270,389 +269,64 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
 ///
 pub fn check_safety_of_destructor_if_necessary<'a, 'gcx, 'tcx>(
     rcx: &mut RegionCtxt<'a, 'gcx, 'tcx>,
-    typ: ty::Ty<'tcx>,
+    ty: ty::Ty<'tcx>,
     span: Span,
     scope: region::CodeExtent)
+    -> Result<(), ErrorReported>
 {
     debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
-           typ, scope);
+           ty, scope);
 
 
     let parent_scope = match rcx.tcx.region_maps.opt_encl_scope(scope) {
-      Some(parent_scope) => parent_scope,
-      // If no enclosing scope, then it must be the root scope which cannot be outlived.
-      None => return
+        Some(parent_scope) => parent_scope,
+        // If no enclosing scope, then it must be the root scope
+        // which cannot be outlived.
+        None => return Ok(())
     };
-
-    let result = iterate_over_potentially_unsafe_regions_in_type(
-        &mut DropckContext {
-            rcx: rcx,
-            span: span,
-            parent_scope: parent_scope,
-            breadcrumbs: FxHashSet()
-        },
-        TypeContext::Root,
-        typ,
-        0);
-    match result {
-        Ok(()) => {}
-        Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => {
-            let tcx = rcx.tcx;
-            let mut err = struct_span_err!(tcx.sess, span, E0320,
-                                           "overflow while adding drop-check rules for {}", typ);
-            match *ctxt {
-                TypeContext::Root => {
-                    // no need for an additional note if the overflow
-                    // was somehow on the root.
-                }
-                TypeContext::ADT { def_id, variant, field } => {
-                    let adt = tcx.lookup_adt_def(def_id);
-                    let variant_name = match adt.adt_kind() {
-                        AdtKind::Enum => format!("enum {} variant {}",
-                                                 tcx.item_path_str(def_id),
-                                                 variant),
-                        AdtKind::Struct => format!("struct {}",
-                                                   tcx.item_path_str(def_id)),
-                        AdtKind::Union => format!("union {}",
-                                                  tcx.item_path_str(def_id)),
-                    };
-                    span_note!(
-                        &mut err,
-                        span,
-                        "overflowed on {} field {} type: {}",
-                        variant_name,
-                        field,
-                        detected_on_typ);
+    let parent_scope = rcx.tcx.mk_region(ty::ReScope(parent_scope));
+    let origin = || infer::SubregionOrigin::SafeDestructor(span);
+
+    let ty = rcx.fcx.resolve_type_vars_if_possible(&ty);
+    let for_ty = ty;
+    let mut types = vec![(ty, 0)];
+    let mut known = FxHashSet();
+    while let Some((ty, depth)) = types.pop() {
+        let ty::DtorckConstraint {
+            dtorck_types, outlives
+        } = rcx.tcx.dtorck_constraint_for_ty(span, for_ty, depth, ty)?;
+
+        for ty in dtorck_types {
+            let ty = rcx.fcx.normalize_associated_types_in(span, &ty);
+            let ty = rcx.fcx.resolve_type_vars_with_obligations(ty);
+            let ty = rcx.fcx.resolve_type_and_region_vars_if_possible(&ty);
+            match ty.sty {
+                // All parameters live for the duration of the
+                // function.
+                ty::TyParam(..) => {}
+
+                // A projection that we couldn't resolve - it
+                // might have a destructor.
+                ty::TyProjection(..) | ty::TyAnon(..) => {
+                    rcx.type_must_outlive(origin(), ty, parent_scope);
                 }
-            }
-            err.emit();
-        }
-    }
-}
-
-enum Error<'tcx> {
-    Overflow(TypeContext, ty::Ty<'tcx>),
-}
-
-#[derive(Copy, Clone)]
-enum TypeContext {
-    Root,
-    ADT {
-        def_id: DefId,
-        variant: ast::Name,
-        field: ast::Name,
-    }
-}
-
-struct DropckContext<'a, 'b: 'a, 'gcx: 'b+'tcx, 'tcx: 'b> {
-    rcx: &'a mut RegionCtxt<'b, 'gcx, 'tcx>,
-    /// types that have already been traversed
-    breadcrumbs: FxHashSet<Ty<'tcx>>,
-    /// span for error reporting
-    span: Span,
-    /// the scope reachable dtorck types must outlive
-    parent_scope: region::CodeExtent
-}
-
-// `context` is used for reporting overflow errors
-fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'gcx, 'tcx>(
-    cx: &mut DropckContext<'a, 'b, 'gcx, 'tcx>,
-    context: TypeContext,
-    ty: Ty<'tcx>,
-    depth: usize)
-    -> Result<(), Error<'tcx>>
-{
-    let tcx = cx.rcx.tcx;
-    // Issue #22443: Watch out for overflow. While we are careful to
-    // handle regular types properly, non-regular ones cause problems.
-    let recursion_limit = tcx.sess.recursion_limit.get();
-    if depth / 4 >= recursion_limit {
-        // This can get into rather deep recursion, especially in the
-        // presence of things like Vec<T> -> Unique<T> -> PhantomData<T> -> T.
-        // use a higher recursion limit to avoid errors.
-        return Err(Error::Overflow(context, ty))
-    }
 
-    // canoncialize the regions in `ty` before inserting - infinitely many
-    // region variables can refer to the same region.
-    let ty = cx.rcx.resolve_type_and_region_vars_if_possible(&ty);
-
-    if !cx.breadcrumbs.insert(ty) {
-        debug!("iterate_over_potentially_unsafe_regions_in_type \
-               {}ty: {} scope: {:?} - cached",
-               (0..depth).map(|_| ' ').collect::<String>(),
-               ty, cx.parent_scope);
-        return Ok(()); // we already visited this type
-    }
-    debug!("iterate_over_potentially_unsafe_regions_in_type \
-           {}ty: {} scope: {:?}",
-           (0..depth).map(|_| ' ').collect::<String>(),
-           ty, cx.parent_scope);
-
-    // 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: for any Drop
-    // impl that is tagged as "blind" to their parameters,
-    // we assume that data borrowed via such type parameters
-    // remains unreachable via that Drop impl.
-    //
-    // For example, consider:
-    //
-    // ```rust
-    // #[unsafe_destructor_blind_to_params]
-    // 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).
-    let dropck_kind = has_dtor_of_interest(tcx, ty);
-    debug!("iterate_over_potentially_unsafe_regions_in_type \
-            ty: {:?} dropck_kind: {:?}", ty, dropck_kind);
-    match dropck_kind {
-        DropckKind::NoBorrowedDataAccessedInMyDtor => {
-            // The maximally blind attribute.
-        }
-        DropckKind::BorrowedDataMustStrictlyOutliveSelf => {
-            cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
-                                     ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
-            return Ok(());
-        }
-        DropckKind::RevisedSelf(revised_ty) => {
-            cx.rcx.type_must_outlive(infer::SubregionOrigin::SafeDestructor(cx.span),
-                                     revised_ty, tcx.mk_region(ty::ReScope(cx.parent_scope)));
-            // Do not return early from this case; we want
-            // to recursively process the internal structure of Self
-            // (because even though the Drop for Self has been asserted
-            //  safe, the types instantiated for the generics of Self
-            //  may themselves carry dropck constraints.)
-        }
-    }
-
-    debug!("iterate_over_potentially_unsafe_regions_in_type \
-           {}ty: {} scope: {:?} - checking interior",
-           (0..depth).map(|_| ' ').collect::<String>(),
-           ty, cx.parent_scope);
-
-    // We still need to ensure all referenced data is safe.
-    match ty.sty {
-        ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
-        ty::TyFloat(_) | ty::TyStr | ty::TyNever => {
-            // primitive - definitely safe
-            Ok(())
-        }
-
-        ty::TyArray(ity, _) | ty::TySlice(ity) => {
-            // single-element containers, behave like their element
-            iterate_over_potentially_unsafe_regions_in_type(
-                cx, context, ity, depth+1)
-        }
-
-        ty::TyAdt(def, substs) if def.is_phantom_data() => {
-            // PhantomData<T> - behaves identically to T
-            let ity = substs.type_at(0);
-            iterate_over_potentially_unsafe_regions_in_type(
-                cx, context, ity, depth+1)
-        }
-
-        ty::TyAdt(def, substs) => {
-            let did = def.did;
-            for variant in &def.variants {
-                for field in variant.fields.iter() {
-                    let fty = field.ty(tcx, substs);
-                    let fty = cx.rcx.fcx.resolve_type_vars_with_obligations(
-                        cx.rcx.fcx.normalize_associated_types_in(cx.span, &fty));
-                    iterate_over_potentially_unsafe_regions_in_type(
-                        cx,
-                        TypeContext::ADT {
-                            def_id: did,
-                            field: field.name,
-                            variant: variant.name,
-                        },
-                        fty,
-                        depth+1)?
+                _ => {
+                    if let None = known.replace(ty) {
+                        types.push((ty, depth+1));
+                    }
                 }
             }
-            Ok(())
-        }
-
-        ty::TyClosure(def_id, substs) => {
-            for ty in substs.upvar_tys(def_id, tcx) {
-                iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)?
-            }
-            Ok(())
-        }
-
-        ty::TyTuple(tys, _) => {
-            for ty in tys {
-                iterate_over_potentially_unsafe_regions_in_type(cx, context, ty, depth+1)?
-            }
-            Ok(())
-        }
-
-        ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyParam(..) => {
-            // these always come with a witness of liveness (references
-            // explicitly, pointers implicitly, parameters by the
-            // caller).
-            Ok(())
         }
 
-        ty::TyFnDef(..) | ty::TyFnPtr(_) => {
-            // FIXME(#26656): this type is always destruction-safe, but
-            // it implicitly witnesses Self: Fn, which can be false.
-            Ok(())
-        }
-
-        ty::TyInfer(..) | ty::TyError => {
-            tcx.sess.delay_span_bug(cx.span, "unresolved type in regionck");
-            Ok(())
-        }
-
-        // these are always dtorck
-        ty::TyDynamic(..) | ty::TyProjection(_) | ty::TyAnon(..) => bug!(),
-    }
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-enum DropckKind<'tcx> {
-    /// The "safe" kind; i.e. conservatively assume any borrow
-    /// accessed by dtor, and therefore such data must strictly
-    /// outlive self.
-    ///
-    /// Equivalent to RevisedTy with no change to the self type.
-    BorrowedDataMustStrictlyOutliveSelf,
-
-    /// The nearly completely-unsafe kind.
-    ///
-    /// Equivalent to RevisedSelf with *all* parameters remapped to ()
-    /// (maybe...?)
-    NoBorrowedDataAccessedInMyDtor,
-
-    /// Assume all borrowed data access by dtor occurs as if Self has the
-    /// type carried by this variant. In practice this means that some
-    /// of the type parameters are remapped to `()` (and some lifetime
-    /// parameters remapped to `'static`), because the developer has asserted
-    /// that the destructor will not access their contents.
-    RevisedSelf(Ty<'tcx>),
-}
-
-/// Returns the classification of what kind of check should be applied
-/// to `ty`, which may include a revised type where some of the type
-/// parameters are re-mapped to `()` to reflect the destructor's
-/// "purity" with respect to their actual contents.
-fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                        ty: Ty<'tcx>)
-                                        -> DropckKind<'tcx> {
-    match ty.sty {
-        ty::TyAdt(adt_def, substs) => {
-            if !adt_def.is_dtorck(tcx) {
-                return DropckKind::NoBorrowedDataAccessedInMyDtor;
+        for outlive in outlives {
+            if let Some(r) = outlive.as_region() {
+                rcx.sub_regions(origin(), parent_scope, r);
+            } else if let Some(ty) = outlive.as_type() {
+                rcx.type_must_outlive(origin(), ty, parent_scope);
             }
-
-            // Find the `impl<..> Drop for _` to inspect any
-            // attributes attached to the impl's generics.
-            let dtor_method = adt_def.destructor(tcx)
-                .expect("dtorck type without destructor impossible");
-            let method = tcx.associated_item(dtor_method.did);
-            let impl_def_id = method.container.id();
-            let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs);
-            return DropckKind::RevisedSelf(revised_ty);
-        }
-        ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyAnon(..) => {
-            debug!("ty: {:?} isn't known, and therefore is a dropck type", ty);
-            return DropckKind::BorrowedDataMustStrictlyOutliveSelf;
-        },
-        _ => {
-            return DropckKind::NoBorrowedDataAccessedInMyDtor;
         }
     }
-}
 
-// Constructs new Ty just like the type defined by `adt_def` coupled
-// with `substs`, except each type and lifetime parameter marked as
-// `#[may_dangle]` in the Drop impl (identified by `impl_def_id`) is
-// respectively mapped to `()` or `'static`.
-//
-// For example: If the `adt_def` maps to:
-//
-//   enum Foo<'a, X, Y> { ... }
-//
-// and the `impl_def_id` maps to:
-//
-//   impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... }
-//
-// then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>`
-fn revise_self_ty<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                  adt_def: &'tcx ty::AdtDef,
-                                  impl_def_id: DefId,
-                                  substs: &Substs<'tcx>)
-                                  -> Ty<'tcx> {
-    // Get generics for `impl Drop` to query for `#[may_dangle]` attr.
-    let impl_bindings = tcx.item_generics(impl_def_id);
-
-    // Get Substs attached to Self on `impl Drop`; process in parallel
-    // with `substs`, replacing dangling entries as appropriate.
-    let self_substs = {
-        let impl_self_ty: Ty<'tcx> = tcx.item_type(impl_def_id);
-        if let ty::TyAdt(self_adt_def, self_substs) = impl_self_ty.sty {
-            assert_eq!(adt_def, self_adt_def);
-            self_substs
-        } else {
-            bug!("Self in `impl Drop for _` must be an Adt.");
-        }
-    };
-
-    // Walk `substs` + `self_substs`, build new substs appropriate for
-    // `adt_def`; each non-dangling param reuses entry from `substs`.
-    //
-    // Note: The manner we map from a right-hand side (i.e. Region or
-    // Ty) for a given `def` to generic parameter associated with that
-    // right-hand side is tightly coupled to `Drop` impl constraints.
-    //
-    // E.g. we know such a Ty must be `TyParam`, because a destructor
-    // for `struct Foo<X>` is defined via `impl<Y> Drop for Foo<Y>`,
-    // and never by (for example) `impl<Z> Drop for Foo<Vec<Z>>`.
-    let substs = Substs::for_item(
-        tcx,
-        adt_def.did,
-        |def, _| {
-            let r_orig = substs.region_for_def(def);
-            let impl_self_orig = self_substs.region_for_def(def);
-            let r = if let ty::Region::ReEarlyBound(ref ebr) = *impl_self_orig {
-                if impl_bindings.region_param(ebr).pure_wrt_drop {
-                    tcx.mk_region(ty::ReStatic)
-                } else {
-                    r_orig
-                }
-            } else {
-                bug!("substs for an impl must map regions to ReEarlyBound");
-            };
-            debug!("has_dtor_of_interest mapping def {:?} orig {:?} to {:?}",
-                   def, r_orig, r);
-            r
-        },
-        |def, _| {
-            let t_orig = substs.type_for_def(def);
-            let impl_self_orig = self_substs.type_for_def(def);
-            let t = if let ty::TypeVariants::TyParam(ref pt) = impl_self_orig.sty {
-                if impl_bindings.type_param(pt).pure_wrt_drop {
-                    tcx.mk_nil()
-                } else {
-                    t_orig
-                }
-            } else {
-                bug!("substs for an impl must map types to TyParam");
-            };
-            debug!("has_dtor_of_interest mapping def {:?} orig {:?} {:?} to {:?} {:?}",
-                   def, t_orig, t_orig.sty, t, t.sty);
-            t
-        });
-
-    tcx.mk_adt(adt_def, &substs)
+    Ok(())
 }
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index cd58fcd4806..bf7649242fa 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -36,7 +36,7 @@ fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let def_id = tcx.hir.local_def_id(it.id);
 
     let substs = Substs::for_item(tcx, def_id,
-                                  |_, _| tcx.mk_region(ty::ReErased),
+                                  |_, _| tcx.types.re_erased,
                                   |def, _| tcx.mk_param_from_def(def));
 
     let fty = tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 59dbbfe49f0..80f9372eb54 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -1063,7 +1063,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         // In general, during probing we erase regions. See
         // `impl_self_ty()` for an explanation.
-        let region = tcx.mk_region(ty::ReErased);
+        let region = tcx.types.re_erased;
 
         // Search through mutabilities in order to find one where pick works:
         [hir::MutImmutable, hir::MutMutable]
@@ -1325,7 +1325,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
                 } else {
                     // In general, during probe we erase regions. See
                     // `impl_self_ty()` for an explanation.
-                    self.tcx.mk_region(ty::ReErased)
+                    self.tcx.types.re_erased
                 }
             }, |def, cur_substs| {
                 let i = def.index as usize;
@@ -1345,7 +1345,7 @@ impl<'a, 'gcx, 'tcx> ProbeContext<'a, 'gcx, 'tcx> {
 
         let substs = Substs::for_item(self.tcx,
                                       impl_def_id,
-                                      |_, _| self.tcx.mk_region(ty::ReErased),
+                                      |_, _| self.tcx.types.re_erased,
                                       |_, _| self.next_ty_var(
                                         TypeVariableOrigin::SubstitutionPlaceholder(
                                             self.tcx.def_span(impl_def_id))));
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 839af0fa670..098e8c53a52 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1954,7 +1954,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         //
         // FIXME(#27579) all uses of this should be migrated to register_wf_obligation eventually
         let cause = traits::ObligationCause::new(span, self.body_id, code);
-        self.register_region_obligation(ty, self.tcx.mk_region(ty::ReEmpty), cause);
+        self.register_region_obligation(ty, self.tcx.types.re_empty, cause);
     }
 
     /// Registers obligations that all types appearing in `substs` are well-formed.
@@ -2513,7 +2513,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         match lit.node {
             ast::LitKind::Str(..) => tcx.mk_static_str(),
             ast::LitKind::ByteStr(ref v) => {
-                tcx.mk_imm_ref(tcx.mk_region(ty::ReStatic),
+                tcx.mk_imm_ref(tcx.types.re_static,
                                 tcx.mk_array(tcx.types.u8, v.len()))
             }
             ast::LitKind::Byte(_) => tcx.types.u8,
diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs
index 8bfb390bd2a..dcef22da879 100644
--- a/src/librustc_typeck/check/regionck.rs
+++ b/src/librustc_typeck/check/regionck.rs
@@ -457,7 +457,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
             self.type_of_node_must_outlive(origin, id, var_region);
 
             let typ = self.resolve_node_type(id);
-            dropck::check_safety_of_destructor_if_necessary(self, typ, span, var_scope);
+            let _ = dropck::check_safety_of_destructor_if_necessary(
+                self, typ, span, var_scope);
         })
     }
 }
@@ -995,10 +996,8 @@ impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
                 match *region {
                     ty::ReScope(rvalue_scope) => {
                         let typ = self.resolve_type(cmt.ty);
-                        dropck::check_safety_of_destructor_if_necessary(self,
-                                                                        typ,
-                                                                        span,
-                                                                        rvalue_scope);
+                        let _ = dropck::check_safety_of_destructor_if_necessary(
+                            self, typ, span, rvalue_scope);
                     }
                     ty::ReStatic => {}
                     _ => {
diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs
index f196aa82b1e..35b2e8f8afc 100644
--- a/src/librustc_typeck/check/writeback.rs
+++ b/src/librustc_typeck/check/writeback.rs
@@ -288,8 +288,8 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
             let outside_ty = gcx.fold_regions(&inside_ty, &mut false, |r, _| {
                 match *r {
                     // 'static is valid everywhere.
-                    ty::ReStatic |
-                    ty::ReEmpty => gcx.mk_region(*r),
+                    ty::ReStatic => gcx.types.re_static,
+                    ty::ReEmpty => gcx.types.re_empty,
 
                     // Free regions that come from early-bound regions are valid.
                     ty::ReFree(ty::FreeRegion {
@@ -307,7 +307,7 @@ impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
                         span_err!(self.tcx().sess, span, E0564,
                                   "only named lifetimes are allowed in `impl Trait`, \
                                    but `{}` was found in the type `{}`", r, inside_ty);
-                        gcx.mk_region(ty::ReStatic)
+                        gcx.types.re_static
                     }
 
                     ty::ReVar(_) |
@@ -526,7 +526,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Resolver<'cx, 'gcx, 'tcx> {
         match self.infcx.fully_resolve(&r) {
             Ok(r) => r,
             Err(_) => {
-                self.tcx.mk_region(ty::ReStatic)
+                self.tcx.types.re_static
             }
         }
     }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index af0ef279e4f..660ce837043 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -99,6 +99,8 @@ pub fn provide(providers: &mut Providers) {
         trait_def,
         adt_def,
         impl_trait_ref,
+        impl_polarity,
+        is_foreign_item,
         ..*providers
     };
 }
@@ -553,7 +555,8 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr());
         prev_discr = Some(if let Some(e) = variant.node.disr_expr {
             let expr_did = tcx.hir.local_def_id(e.node_id);
-            let result = ty::queries::monomorphic_const_eval::get(tcx, variant.span, expr_did);
+            let substs = Substs::empty();
+            let result = ty::queries::const_eval::get(tcx, variant.span, (expr_did, substs));
 
             // enum variant evaluation happens before the global constant check
             // so we need to report the real error
@@ -1132,6 +1135,16 @@ fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     }
 }
 
+fn impl_polarity<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                           def_id: DefId)
+                           -> hir::ImplPolarity {
+    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+    match tcx.hir.expect_item(node_id).node {
+        hir::ItemImpl(_, polarity, ..) => polarity,
+        ref item => bug!("trait_impl_polarity: {:?} not an impl", item)
+    }
+}
+
 // Is it marked with ?Sized
 fn is_unsized<'gcx: 'tcx, 'tcx>(astconv: &AstConv<'gcx, 'tcx>,
                                 ast_bounds: &[hir::TyParamBound],
@@ -1530,3 +1543,13 @@ fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
     let substs = Substs::identity_for_item(tcx, def_id);
     tcx.mk_fn_def(def_id, substs, fty)
 }
+
+fn is_foreign_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                             def_id: DefId)
+                             -> bool {
+    match tcx.hir.get_if_local(def_id) {
+        Some(hir_map::NodeForeignItem(..)) => true,
+        Some(_) => false,
+        _ => bug!("is_foreign_item applied to non-local def-id {:?}", def_id)
+    }
+}
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index c50156fa5f2..2bae6a0d9e1 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -4154,7 +4154,6 @@ register_diagnostics! {
 //  E0248, // value used as a type, now reported earlier during resolution as E0412
 //  E0249,
 //  E0319, // trait impls for defaulted traits allowed just for structs/enums
-    E0320, // recursive overflow during dropck
 //  E0372, // coherence not object safe
     E0377, // the trait `CoerceUnsized` may only be implemented for a coercion
            // between structures with the same definition
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index cc30fdf56fc..6016fd488f5 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -487,7 +487,7 @@ impl hir::print::PpAnn for InlinedConst {
 }
 
 fn print_inlined_const(cx: &DocContext, did: DefId) -> String {
-    let body = cx.tcx.sess.cstore.maybe_get_item_body(cx.tcx, did).unwrap();
+    let body = cx.tcx.sess.cstore.item_body(cx.tcx, did);
     let inlined = InlinedConst {
         nested_bodies: cx.tcx.sess.cstore.item_body_nested_bodies(did)
     };
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 4bf856240f6..85a28bbfbc6 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -32,6 +32,7 @@ use std::ascii::AsciiExt;
 use std::cell::RefCell;
 use std::collections::{HashMap, VecDeque};
 use std::default::Default;
+use std::ffi::CString;
 use std::fmt::{self, Write};
 use std::str;
 use syntax::feature_gate::UnstableFeatures;
@@ -40,21 +41,28 @@ use syntax::codemap::Span;
 use html::render::derive_id;
 use html::toc::TocBuilder;
 use html::highlight;
+use html::escape::Escape;
 use test;
 
 use pulldown_cmark::{html, Event, Tag, Parser};
 use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES};
 
+#[derive(PartialEq, Debug, Clone, Copy)]
+pub enum RenderType {
+    Hoedown,
+    Pulldown,
+}
+
 /// A unit struct which has the `fmt::Display` trait implemented. When
 /// formatted, this struct will emit the HTML corresponding to the rendered
 /// version of the contained markdown string.
 // The second parameter is whether we need a shorter version or not.
-pub struct Markdown<'a>(pub &'a str);
+pub struct Markdown<'a>(pub &'a str, pub RenderType);
 /// A unit struct like `Markdown`, that renders the markdown with a
 /// table of contents.
-pub struct MarkdownWithToc<'a>(pub &'a str);
+pub struct MarkdownWithToc<'a>(pub &'a str, pub RenderType);
 /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
-pub struct MarkdownHtml<'a>(pub &'a str);
+pub struct MarkdownHtml<'a>(pub &'a str, pub RenderType);
 /// A unit struct like `Markdown`, that renders only the first paragraph.
 pub struct MarkdownSummaryLine<'a>(pub &'a str);
 
@@ -73,6 +81,14 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
     }
 }
 
+/// Returns a new string with all consecutive whitespace collapsed into
+/// single spaces.
+///
+/// Any leading or trailing whitespace will be trimmed.
+fn collapse_whitespace(s: &str) -> String {
+    s.split_whitespace().collect::<Vec<_>>().join(" ")
+}
+
 /// Convert chars from a title for an id.
 ///
 /// "Hello, world!" -> "hello-world"
@@ -368,6 +384,7 @@ const HOEDOWN_EXT_AUTOLINK: libc::c_uint = 1 << 3;
 const HOEDOWN_EXT_STRIKETHROUGH: libc::c_uint = 1 << 4;
 const HOEDOWN_EXT_SUPERSCRIPT: libc::c_uint = 1 << 8;
 const HOEDOWN_EXT_FOOTNOTES: libc::c_uint = 1 << 2;
+const HOEDOWN_HTML_ESCAPE: libc::c_uint = 1 << 1;
 
 const HOEDOWN_EXTENSIONS: libc::c_uint =
     HOEDOWN_EXT_NO_INTRA_EMPHASIS | HOEDOWN_EXT_TABLES |
@@ -462,6 +479,13 @@ struct hoedown_buffer {
     unit: libc::size_t,
 }
 
+struct MyOpaque {
+    dfltblk: extern "C" fn(*mut hoedown_buffer, *const hoedown_buffer,
+                           *const hoedown_buffer, *const hoedown_renderer_data,
+                           libc::size_t),
+    toc_builder: Option<TocBuilder>,
+}
+
 extern {
     fn hoedown_html_renderer_new(render_flags: libc::c_uint,
                                  nesting_level: libc::c_int)
@@ -478,6 +502,7 @@ extern {
     fn hoedown_document_free(md: *mut hoedown_document);
 
     fn hoedown_buffer_new(unit: libc::size_t) -> *mut hoedown_buffer;
+    fn hoedown_buffer_puts(b: *mut hoedown_buffer, c: *const libc::c_char);
     fn hoedown_buffer_free(b: *mut hoedown_buffer);
 }
 
@@ -487,12 +512,214 @@ impl hoedown_buffer {
     }
 }
 
+pub fn render(w: &mut fmt::Formatter,
+              s: &str,
+              print_toc: bool,
+              html_flags: libc::c_uint) -> fmt::Result {
+    extern fn block(ob: *mut hoedown_buffer, orig_text: *const hoedown_buffer,
+                    lang: *const hoedown_buffer, data: *const hoedown_renderer_data,
+                    line: libc::size_t) {
+        unsafe {
+            if orig_text.is_null() { return }
+
+            let opaque = (*data).opaque as *mut hoedown_html_renderer_state;
+            let my_opaque: &MyOpaque = &*((*opaque).opaque as *const MyOpaque);
+            let text = (*orig_text).as_bytes();
+            let origtext = str::from_utf8(text).unwrap();
+            let origtext = origtext.trim_left();
+            debug!("docblock: ==============\n{:?}\n=======", text);
+            let rendered = if lang.is_null() || origtext.is_empty() {
+                false
+            } else {
+                let rlang = (*lang).as_bytes();
+                let rlang = str::from_utf8(rlang).unwrap();
+                if !LangString::parse(rlang).rust {
+                    (my_opaque.dfltblk)(ob, orig_text, lang,
+                                        opaque as *const hoedown_renderer_data,
+                                        line);
+                    true
+                } else {
+                    false
+                }
+            };
+
+            let lines = origtext.lines().filter(|l| {
+                stripped_filtered_line(*l).is_none()
+            });
+            let text = lines.collect::<Vec<&str>>().join("\n");
+            if rendered { return }
+            PLAYGROUND.with(|play| {
+                // insert newline to clearly separate it from the
+                // previous block so we can shorten the html output
+                let mut s = String::from("\n");
+                let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| {
+                    if url.is_empty() {
+                        return None;
+                    }
+                    let test = origtext.lines().map(|l| {
+                        stripped_filtered_line(l).unwrap_or(l)
+                    }).collect::<Vec<&str>>().join("\n");
+                    let krate = krate.as_ref().map(|s| &**s);
+                    let test = test::maketest(&test, krate, false,
+                                              &Default::default());
+                    let channel = if test.contains("#![feature(") {
+                        "&amp;version=nightly"
+                    } else {
+                        ""
+                    };
+                    // These characters don't need to be escaped in a URI.
+                    // FIXME: use a library function for percent encoding.
+                    fn dont_escape(c: u8) -> bool {
+                        (b'a' <= c && c <= b'z') ||
+                        (b'A' <= c && c <= b'Z') ||
+                        (b'0' <= c && c <= b'9') ||
+                        c == b'-' || c == b'_' || c == b'.' ||
+                        c == b'~' || c == b'!' || c == b'\'' ||
+                        c == b'(' || c == b')' || c == b'*'
+                    }
+                    let mut test_escaped = String::new();
+                    for b in test.bytes() {
+                        if dont_escape(b) {
+                            test_escaped.push(char::from(b));
+                        } else {
+                            write!(test_escaped, "%{:02X}", b).unwrap();
+                        }
+                    }
+                    Some(format!(
+                        r#"<a class="test-arrow" target="_blank" href="{}?code={}{}">Run</a>"#,
+                        url, test_escaped, channel
+                    ))
+                });
+                s.push_str(&highlight::render_with_highlighting(
+                               &text,
+                               Some("rust-example-rendered"),
+                               None,
+                               playground_button.as_ref().map(String::as_str)));
+                let output = CString::new(s).unwrap();
+                hoedown_buffer_puts(ob, output.as_ptr());
+            })
+        }
+    }
+
+    extern fn header(ob: *mut hoedown_buffer, text: *const hoedown_buffer,
+                     level: libc::c_int, data: *const hoedown_renderer_data,
+                     _: libc::size_t) {
+        // hoedown does this, we may as well too
+        unsafe { hoedown_buffer_puts(ob, "\n\0".as_ptr() as *const _); }
+
+        // Extract the text provided
+        let s = if text.is_null() {
+            "".to_owned()
+        } else {
+            let s = unsafe { (*text).as_bytes() };
+            str::from_utf8(&s).unwrap().to_owned()
+        };
+
+        // Discard '<em>', '<code>' tags and some escaped characters,
+        // transform the contents of the header into a hyphenated string
+        // without non-alphanumeric characters other than '-' and '_'.
+        //
+        // This is a terrible hack working around how hoedown gives us rendered
+        // html for text rather than the raw text.
+        let mut id = s.clone();
+        let repl_sub = vec!["<em>", "</em>", "<code>", "</code>",
+                            "<strong>", "</strong>",
+                            "&lt;", "&gt;", "&amp;", "&#39;", "&quot;"];
+        for sub in repl_sub {
+            id = id.replace(sub, "");
+        }
+        let id = id.chars().filter_map(|c| {
+            if c.is_alphanumeric() || c == '-' || c == '_' {
+                if c.is_ascii() {
+                    Some(c.to_ascii_lowercase())
+                } else {
+                    Some(c)
+                }
+            } else if c.is_whitespace() && c.is_ascii() {
+                Some('-')
+            } else {
+                None
+            }
+        }).collect::<String>();
+
+        let opaque = unsafe { (*data).opaque as *mut hoedown_html_renderer_state };
+        let opaque = unsafe { &mut *((*opaque).opaque as *mut MyOpaque) };
+
+        let id = derive_id(id);
+
+        let sec = opaque.toc_builder.as_mut().map_or("".to_owned(), |builder| {
+            format!("{} ", builder.push(level as u32, s.clone(), id.clone()))
+        });
+
+        // Render the HTML
+        let text = format!("<h{lvl} id='{id}' class='section-header'>\
+                           <a href='#{id}'>{sec}{}</a></h{lvl}>",
+                           s, lvl = level, id = id, sec = sec);
+
+        let text = CString::new(text).unwrap();
+        unsafe { hoedown_buffer_puts(ob, text.as_ptr()) }
+    }
+
+    extern fn codespan(
+        ob: *mut hoedown_buffer,
+        text: *const hoedown_buffer,
+        _: *const hoedown_renderer_data,
+        _: libc::size_t
+    ) -> libc::c_int {
+        let content = if text.is_null() {
+            "".to_owned()
+        } else {
+            let bytes = unsafe { (*text).as_bytes() };
+            let s = str::from_utf8(bytes).unwrap();
+            collapse_whitespace(s)
+        };
+
+        let content = format!("<code>{}</code>", Escape(&content));
+        let element = CString::new(content).unwrap();
+        unsafe { hoedown_buffer_puts(ob, element.as_ptr()); }
+        // Return anything except 0, which would mean "also print the code span verbatim".
+        1
+    }
+
+    unsafe {
+        let ob = hoedown_buffer_new(DEF_OUNIT);
+        let renderer = hoedown_html_renderer_new(html_flags, 0);
+        let mut opaque = MyOpaque {
+            dfltblk: (*renderer).blockcode.unwrap(),
+            toc_builder: if print_toc {Some(TocBuilder::new())} else {None}
+        };
+        (*((*renderer).opaque as *mut hoedown_html_renderer_state)).opaque
+                = &mut opaque as *mut _ as *mut libc::c_void;
+        (*renderer).blockcode = Some(block);
+        (*renderer).header = Some(header);
+        (*renderer).codespan = Some(codespan);
+
+        let document = hoedown_document_new(renderer, HOEDOWN_EXTENSIONS, 16);
+        hoedown_document_render(document, ob, s.as_ptr(),
+                                s.len() as libc::size_t);
+        hoedown_document_free(document);
+
+        hoedown_html_renderer_free(renderer);
+
+        let mut ret = opaque.toc_builder.map_or(Ok(()), |builder| {
+            write!(w, "<nav id=\"TOC\">{}</nav>", builder.into_toc())
+        });
+
+        if ret.is_ok() {
+            let buf = (*ob).as_bytes();
+            ret = w.write_str(str::from_utf8(buf).unwrap());
+        }
+        hoedown_buffer_free(ob);
+        ret
+    }
+}
+
 pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) {
     extern fn block(_ob: *mut hoedown_buffer,
                     text: *const hoedown_buffer,
                     lang: *const hoedown_buffer,
                     data: *const hoedown_renderer_data,
-                    _line: libc::size_t) {
+                    line: libc::size_t) {
         unsafe {
             if text.is_null() { return }
             let block_info = if lang.is_null() {
@@ -510,8 +737,19 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
             let lines = text.lines().map(|l| {
                 stripped_filtered_line(l).unwrap_or(l)
             });
+            let text = lines.collect::<Vec<&str>>().join("\n");
             let filename = tests.get_filename();
-            tests.add_old_test(lines.collect::<Vec<&str>>().join("\n"), filename);
+
+            if tests.render_type == RenderType::Hoedown {
+                let line = tests.get_line() + line;
+                tests.add_test(text.to_owned(),
+                               block_info.should_panic, block_info.no_run,
+                               block_info.ignore, block_info.test_harness,
+                               block_info.compile_fail, block_info.error_codes,
+                               line, filename);
+            } else {
+                tests.add_old_test(text, filename);
+            }
         }
     }
 
@@ -533,7 +771,6 @@ pub fn old_find_testable_code(doc: &str, tests: &mut ::test::Collector, position
     }
 
     tests.set_position(position);
-
     unsafe {
         let ob = hoedown_buffer_new(DEF_OUNIT);
         let renderer = hoedown_html_renderer_new(0, 0);
@@ -702,72 +939,84 @@ impl LangString {
 
 impl<'a> fmt::Display for Markdown<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        let Markdown(md) = *self;
+        let Markdown(md, render_type) = *self;
+
         // This is actually common enough to special-case
         if md.is_empty() { return Ok(()) }
+        if render_type == RenderType::Hoedown {
+            render(fmt, md, false, 0)
+        } else {
+            let mut opts = Options::empty();
+            opts.insert(OPTION_ENABLE_TABLES);
+            opts.insert(OPTION_ENABLE_FOOTNOTES);
 
-        let mut opts = Options::empty();
-        opts.insert(OPTION_ENABLE_TABLES);
-        opts.insert(OPTION_ENABLE_FOOTNOTES);
-
-        let p = Parser::new_ext(md, opts);
+            let p = Parser::new_ext(md, opts);
 
-        let mut s = String::with_capacity(md.len() * 3 / 2);
+            let mut s = String::with_capacity(md.len() * 3 / 2);
 
-        html::push_html(&mut s,
-                        Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
+            html::push_html(&mut s,
+                            Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
 
-        fmt.write_str(&s)
+            fmt.write_str(&s)
+        }
     }
 }
 
 impl<'a> fmt::Display for MarkdownWithToc<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        let MarkdownWithToc(md) = *self;
+        let MarkdownWithToc(md, render_type) = *self;
 
-        let mut opts = Options::empty();
-        opts.insert(OPTION_ENABLE_TABLES);
-        opts.insert(OPTION_ENABLE_FOOTNOTES);
+        if render_type == RenderType::Hoedown {
+            render(fmt, md, true, 0)
+        } else {
+            let mut opts = Options::empty();
+            opts.insert(OPTION_ENABLE_TABLES);
+            opts.insert(OPTION_ENABLE_FOOTNOTES);
 
-        let p = Parser::new_ext(md, opts);
+            let p = Parser::new_ext(md, opts);
 
-        let mut s = String::with_capacity(md.len() * 3 / 2);
+            let mut s = String::with_capacity(md.len() * 3 / 2);
 
-        let mut toc = TocBuilder::new();
+            let mut toc = TocBuilder::new();
 
-        html::push_html(&mut s,
-                        Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc)))));
+            html::push_html(&mut s,
+                            Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc)))));
 
-        write!(fmt, "<nav id=\"TOC\">{}</nav>", toc.into_toc())?;
+            write!(fmt, "<nav id=\"TOC\">{}</nav>", toc.into_toc())?;
 
-        fmt.write_str(&s)
+            fmt.write_str(&s)
+        }
     }
 }
 
 impl<'a> fmt::Display for MarkdownHtml<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        let MarkdownHtml(md) = *self;
+        let MarkdownHtml(md, render_type) = *self;
+
         // This is actually common enough to special-case
         if md.is_empty() { return Ok(()) }
+        if render_type == RenderType::Hoedown {
+            render(fmt, md, false, HOEDOWN_HTML_ESCAPE)
+        } else {
+            let mut opts = Options::empty();
+            opts.insert(OPTION_ENABLE_TABLES);
+            opts.insert(OPTION_ENABLE_FOOTNOTES);
 
-        let mut opts = Options::empty();
-        opts.insert(OPTION_ENABLE_TABLES);
-        opts.insert(OPTION_ENABLE_FOOTNOTES);
-
-        let p = Parser::new_ext(md, opts);
+            let p = Parser::new_ext(md, opts);
 
-        // Treat inline HTML as plain text.
-        let p = p.map(|event| match event {
-            Event::Html(text) | Event::InlineHtml(text) => Event::Text(text),
-            _ => event
-        });
+            // Treat inline HTML as plain text.
+            let p = p.map(|event| match event {
+                Event::Html(text) | Event::InlineHtml(text) => Event::Text(text),
+                _ => event
+            });
 
-        let mut s = String::with_capacity(md.len() * 3 / 2);
+            let mut s = String::with_capacity(md.len() * 3 / 2);
 
-        html::push_html(&mut s,
-                        Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
+            html::push_html(&mut s,
+                            Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
 
-        fmt.write_str(&s)
+            fmt.write_str(&s)
+        }
     }
 }
 
@@ -841,6 +1090,7 @@ pub fn plain_summary_line(md: &str) -> String {
 mod tests {
     use super::{LangString, Markdown, MarkdownHtml};
     use super::plain_summary_line;
+    use super::RenderType;
     use html::render::reset_ids;
 
     #[test]
@@ -881,14 +1131,14 @@ mod tests {
     #[test]
     fn issue_17736() {
         let markdown = "# title";
-        format!("{}", Markdown(markdown));
+        format!("{}", Markdown(markdown, RenderType::Pulldown));
         reset_ids(true);
     }
 
     #[test]
     fn test_header() {
         fn t(input: &str, expect: &str) {
-            let output = format!("{}", Markdown(input));
+            let output = format!("{}", Markdown(input, RenderType::Pulldown));
             assert_eq!(output, expect, "original: {}", input);
             reset_ids(true);
         }
@@ -910,7 +1160,7 @@ mod tests {
     #[test]
     fn test_header_ids_multiple_blocks() {
         fn t(input: &str, expect: &str) {
-            let output = format!("{}", Markdown(input));
+            let output = format!("{}", Markdown(input, RenderType::Pulldown));
             assert_eq!(output, expect, "original: {}", input);
         }
 
@@ -951,7 +1201,7 @@ mod tests {
     #[test]
     fn test_markdown_html_escape() {
         fn t(input: &str, expect: &str) {
-            let output = format!("{}", MarkdownHtml(input));
+            let output = format!("{}", MarkdownHtml(input, RenderType::Pulldown));
             assert_eq!(output, expect, "original: {}", input);
         }
 
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index d55a0640562..57d71e6c4e0 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -72,7 +72,7 @@ use html::format::{TyParamBounds, WhereClause, href, AbiSpace};
 use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
 use html::format::fmt_impl_for_trait_page;
 use html::item_type::ItemType;
-use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine};
+use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine, RenderType};
 use html::{highlight, layout};
 
 /// A pair of name and its optional document.
@@ -98,6 +98,7 @@ pub struct Context {
     /// publicly reused items to redirect to the right location.
     pub render_redirect_pages: bool,
     pub shared: Arc<SharedContext>,
+    pub render_type: RenderType,
 }
 
 pub struct SharedContext {
@@ -433,7 +434,8 @@ pub fn run(mut krate: clean::Crate,
            dst: PathBuf,
            passes: FxHashSet<String>,
            css_file_extension: Option<PathBuf>,
-           renderinfo: RenderInfo) -> Result<(), Error> {
+           renderinfo: RenderInfo,
+           render_type: RenderType) -> Result<(), Error> {
     let src_root = match krate.src.parent() {
         Some(p) => p.to_path_buf(),
         None => PathBuf::new(),
@@ -495,6 +497,7 @@ pub fn run(mut krate: clean::Crate,
         dst: dst,
         render_redirect_pages: false,
         shared: Arc::new(scx),
+        render_type: render_type,
     };
 
     // Crawl the crate to build various caches used for the output
@@ -1638,11 +1641,12 @@ fn plain_summary_line(s: Option<&str>) -> String {
 
 fn document(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result {
     document_stability(w, cx, item)?;
-    document_full(w, item)?;
+    document_full(w, item, cx.render_type)?;
     Ok(())
 }
 
-fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink) -> fmt::Result {
+fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink,
+                  render_type: RenderType) -> fmt::Result {
     if let Some(s) = item.doc_value() {
         let markdown = if s.contains('\n') {
             format!("{} [Read more]({})",
@@ -1651,7 +1655,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin
             format!("{}", &plain_summary_line(Some(s)))
         };
         write!(w, "<div class='docblock'>{}</div>",
-               Markdown(&markdown))?;
+               Markdown(&markdown, render_type))?;
     }
     Ok(())
 }
@@ -1681,10 +1685,11 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> {
     }
 }
 
-fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
+fn document_full(w: &mut fmt::Formatter, item: &clean::Item,
+                 render_type: RenderType) -> fmt::Result {
     if let Some(s) = get_doc_value(item) {
         write!(w, "<div class='docblock'>{}</div>",
-               Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?;
+               Markdown(&format!("{}{}", md_render_assoc_item(item), s), render_type))?;
     }
     Ok(())
 }
@@ -1872,7 +1877,13 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
                        </tr>",
                        name = *myitem.name.as_ref().unwrap(),
                        stab_docs = stab_docs,
-                       docs = MarkdownSummaryLine(doc_value),
+                       docs = if cx.render_type == RenderType::Hoedown {
+                           format!("{}",
+                                   shorter(Some(&Markdown(doc_value,
+                                                          RenderType::Hoedown).to_string())))
+                       } else {
+                           format!("{}", MarkdownSummaryLine(doc_value))
+                       },
                        class = myitem.type_(),
                        stab = myitem.stability_class().unwrap_or("".to_string()),
                        unsafety_flag = unsafety_flag,
@@ -1915,7 +1926,9 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
             } else {
                 String::new()
             };
-            let text = format!("Deprecated{}{}", since, MarkdownHtml(&deprecated_reason));
+            let text = format!("Deprecated{}{}",
+                               since,
+                               MarkdownHtml(&deprecated_reason, cx.render_type));
             stability.push(format!("<div class='stab deprecated'>{}</div>", text))
         };
 
@@ -1944,7 +1957,8 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
                     let text = format!("<summary><span class=microscope>🔬</span> \
                                         This is a nightly-only experimental API. {}\
                                         </summary>{}",
-                                       unstable_extra, MarkdownHtml(&stab.unstable_reason));
+                                       unstable_extra,
+                                       MarkdownHtml(&stab.unstable_reason, cx.render_type));
                     stability.push(format!("<div class='stab unstable'><details>{}</details></div>",
                                    text));
                 }
@@ -1964,7 +1978,7 @@ fn short_stability(item: &clean::Item, cx: &Context, show_reason: bool) -> Vec<S
             String::new()
         };
 
-        let text = format!("Deprecated{}{}", since, MarkdownHtml(&note));
+        let text = format!("Deprecated{}{}", since, MarkdownHtml(&note, cx.render_type));
         stability.push(format!("<div class='stab deprecated'>{}</div>", text))
     }
 
@@ -2900,7 +2914,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
         write!(w, "</span>")?;
         write!(w, "</h3>\n")?;
         if let Some(ref dox) = i.impl_item.doc_value() {
-            write!(w, "<div class='docblock'>{}</div>", Markdown(dox))?;
+            write!(w, "<div class='docblock'>{}</div>", Markdown(dox, cx.render_type))?;
         }
     }
 
@@ -2999,11 +3013,11 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
                         // because impls can't have a stability.
                         document_stability(w, cx, it)?;
                         if get_doc_value(item).is_some() {
-                            document_full(w, item)?;
+                            document_full(w, item, cx.render_type)?;
                         } else {
                             // In case the item isn't documented,
                             // provide short documentation from the trait.
-                            document_short(w, it, link)?;
+                            document_short(w, it, link, cx.render_type)?;
                         }
                     }
                 } else {
@@ -3011,7 +3025,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
                 }
             } else {
                 document_stability(w, cx, item)?;
-                document_short(w, item, link)?;
+                document_short(w, item, link, cx.render_type)?;
             }
         }
         Ok(())
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 0ca267bb82d..2a6134fde5c 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -93,6 +93,8 @@ pub mod test;
 
 use clean::AttributesExt;
 
+use html::markdown::RenderType;
+
 struct Output {
     krate: clean::Crate,
     renderinfo: html::render::RenderInfo,
@@ -169,6 +171,7 @@ pub fn opts() -> Vec<RustcOptGroup> {
                         "URL to send code snippets to, may be reset by --markdown-playground-url \
                          or `#![doc(html_playground_url=...)]`",
                         "URL")),
+        unstable(optflag("", "enable-commonmark", "to enable commonmark doc rendering/testing")),
     ]
 }
 
@@ -250,6 +253,12 @@ pub fn main_args(args: &[String]) -> isize {
     let css_file_extension = matches.opt_str("e").map(|s| PathBuf::from(&s));
     let cfgs = matches.opt_strs("cfg");
 
+    let render_type = if matches.opt_present("enable-commonmark") {
+        RenderType::Pulldown
+    } else {
+        RenderType::Hoedown
+    };
+
     if let Some(ref p) = css_file_extension {
         if !p.is_file() {
             writeln!(
@@ -273,15 +282,17 @@ pub fn main_args(args: &[String]) -> isize {
 
     match (should_test, markdown_input) {
         (true, true) => {
-            return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot)
+            return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type)
         }
         (true, false) => {
-            return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot)
+            return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot,
+                             render_type)
         }
         (false, true) => return markdown::render(input,
                                                  output.unwrap_or(PathBuf::from("doc")),
                                                  &matches, &external_html,
-                                                 !matches.opt_present("markdown-no-toc")),
+                                                 !matches.opt_present("markdown-no-toc"),
+                                                 render_type),
         (false, false) => {}
     }
 
@@ -295,7 +306,8 @@ pub fn main_args(args: &[String]) -> isize {
                                   output.unwrap_or(PathBuf::from("doc")),
                                   passes.into_iter().collect(),
                                   css_file_extension,
-                                  renderinfo)
+                                  renderinfo,
+                                  render_type)
                     .expect("failed to generate documentation");
                 0
             }
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index f75144c23ac..b9ed0eeaef7 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -26,6 +26,7 @@ use html::render::reset_ids;
 use html::escape::Escape;
 use html::markdown;
 use html::markdown::{Markdown, MarkdownWithToc, find_testable_code, old_find_testable_code};
+use html::markdown::RenderType;
 use test::{TestOptions, Collector};
 
 /// Separate any lines at the start of the file that begin with `# ` or `%`.
@@ -50,7 +51,8 @@ fn extract_leading_metadata<'a>(s: &'a str) -> (Vec<&'a str>, &'a str) {
 /// Render `input` (e.g. "foo.md") into an HTML file in `output`
 /// (e.g. output = "bar" => "bar/foo.html").
 pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
-              external_html: &ExternalHtml, include_toc: bool) -> isize {
+              external_html: &ExternalHtml, include_toc: bool,
+              render_type: RenderType) -> isize {
     let input_p = Path::new(input);
     output.push(input_p.file_stem().unwrap());
     output.set_extension("html");
@@ -94,9 +96,9 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
     reset_ids(false);
 
     let rendered = if include_toc {
-        format!("{}", MarkdownWithToc(text))
+        format!("{}", MarkdownWithToc(text, render_type))
     } else {
-        format!("{}", Markdown(text))
+        format!("{}", Markdown(text, render_type))
     };
 
     let err = write!(
@@ -147,7 +149,8 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
 
 /// Run any tests/code examples in the markdown file `input`.
 pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
-            mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>) -> isize {
+            mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>,
+            render_type: RenderType) -> isize {
     let input_str = match load_string(input) {
         Ok(s) => s,
         Err(LoadStringError::ReadFail) => return 1,
@@ -158,7 +161,8 @@ pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
     opts.no_crate_inject = true;
     let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
                                        true, opts, maybe_sysroot, None,
-                                       Some(input.to_owned()));
+                                       Some(input.to_owned()),
+                                       render_type);
     old_find_testable_code(&input_str, &mut collector, DUMMY_SP);
     find_testable_code(&input_str, &mut collector, DUMMY_SP);
     test_args.insert(0, "rustdoctest".to_string());
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 3206b502107..5b9ab304db0 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -43,7 +43,7 @@ use errors;
 use errors::emitter::ColorConfig;
 
 use clean::Attributes;
-use html::markdown;
+use html::markdown::{self, RenderType};
 
 #[derive(Clone, Default)]
 pub struct TestOptions {
@@ -57,7 +57,8 @@ pub fn run(input: &str,
            externs: Externs,
            mut test_args: Vec<String>,
            crate_name: Option<String>,
-           maybe_sysroot: Option<PathBuf>)
+           maybe_sysroot: Option<PathBuf>,
+           render_type: RenderType)
            -> isize {
     let input_path = PathBuf::from(input);
     let input = config::Input::File(input_path.clone());
@@ -106,7 +107,8 @@ pub fn run(input: &str,
                                        opts,
                                        maybe_sysroot,
                                        Some(codemap),
-                                       None);
+                                       None,
+                                       render_type);
 
     {
         let dep_graph = DepGraph::new(false);
@@ -396,12 +398,15 @@ pub struct Collector {
     position: Span,
     codemap: Option<Rc<CodeMap>>,
     filename: Option<String>,
+    // to be removed when hoedown will be removed as well
+    pub render_type: RenderType,
 }
 
 impl Collector {
     pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
                use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>,
-               codemap: Option<Rc<CodeMap>>, filename: Option<String>) -> Collector {
+               codemap: Option<Rc<CodeMap>>, filename: Option<String>,
+               render_type: RenderType) -> Collector {
         Collector {
             tests: Vec::new(),
             old_tests: HashMap::new(),
@@ -418,6 +423,7 @@ impl Collector {
             position: DUMMY_SP,
             codemap: codemap,
             filename: filename,
+            render_type: render_type,
         }
     }
 
@@ -458,20 +464,22 @@ impl Collector {
                     as_test_harness: bool, compile_fail: bool, error_codes: Vec<String>,
                     line: usize, filename: String) {
         let name = self.generate_name(line, &filename);
-        let name_beg = self.generate_name_beginning(&filename);
-        let mut found = false;
         // to be removed when hoedown is removed
-        let test = test.trim().to_owned();
-        if let Some(entry) = self.old_tests.get_mut(&name_beg) {
-            found = entry.remove_item(&test).is_some();
-        }
-        if !found {
-            let _ = writeln!(&mut io::stderr(),
-                             "WARNING: {} Code block is not currently run as a test, but will in \
-                              future versions of rustdoc. Please ensure this code block is a \
-                              runnable test, or use the `ignore` directive.",
-                             name);
-            return
+        if self.render_type == RenderType::Pulldown {
+            let name_beg = self.generate_name_beginning(&filename);
+            let mut found = false;
+            let test = test.trim().to_owned();
+            if let Some(entry) = self.old_tests.get_mut(&name_beg) {
+                found = entry.remove_item(&test).is_some();
+            }
+            if !found {
+                let _ = writeln!(&mut io::stderr(),
+                                 "WARNING: {} Code block is not currently run as a test, but will \
+                                  in future versions of rustdoc. Please ensure this code block is \
+                                  a runnable test, or use the `ignore` directive.",
+                                 name);
+                return
+            }
         }
         let cfgs = self.cfgs.clone();
         let libs = self.libs.clone();
@@ -587,10 +595,15 @@ impl<'a, 'hir> HirCollector<'a, 'hir> {
         attrs.unindent_doc_comments();
         if let Some(doc) = attrs.doc_value() {
             self.collector.cnt = 0;
-            markdown::old_find_testable_code(doc, self.collector,
+            if self.collector.render_type == RenderType::Pulldown {
+                markdown::old_find_testable_code(doc, self.collector,
+                                                 attrs.span.unwrap_or(DUMMY_SP));
+                markdown::find_testable_code(doc, self.collector,
                                              attrs.span.unwrap_or(DUMMY_SP));
-            markdown::find_testable_code(doc, self.collector,
-                                         attrs.span.unwrap_or(DUMMY_SP));
+            } else {
+                markdown::old_find_testable_code(doc, self.collector,
+                                                 attrs.span.unwrap_or(DUMMY_SP));
+            }
         }
 
         nested(self);
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index eacb59d375a..51d127f8ba7 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -1377,7 +1377,7 @@ pub struct IterMut<'a, K: 'a, V: 'a> {
 
 /// An owning iterator over the entries of a `HashMap`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`HashMap`]
+/// This `struct` is created by the [`into_iter`] method on [`HashMap`][`HashMap`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`into_iter`]: struct.HashMap.html#method.into_iter
@@ -2017,13 +2017,6 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
         self.elem.read().0
     }
 
-    /// Deprecated, renamed to `remove_entry`
-    #[unstable(feature = "map_entry_recover_keys", issue = "34285")]
-    #[rustc_deprecated(since = "1.12.0", reason = "renamed to `remove_entry`")]
-    pub fn remove_pair(self) -> (K, V) {
-        self.remove_entry()
-    }
-
     /// Take the ownership of the key and value from the map.
     ///
     /// # Examples
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index e3fad285025..7215e1bde85 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -890,7 +890,7 @@ pub struct Iter<'a, K: 'a> {
 
 /// An owning iterator over the items of a `HashSet`.
 ///
-/// This `struct` is created by the [`into_iter`] method on [`HashSet`]
+/// This `struct` is created by the [`into_iter`] method on [`HashSet`][`HashSet`]
 /// (provided by the `IntoIterator` trait). See its documentation for more.
 ///
 /// [`HashSet`]: struct.HashSet.html
diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index 316e6841c4f..4abad7e24f8 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -22,8 +22,6 @@ use core::num;
 #[cfg(not(test))]
 use intrinsics;
 #[cfg(not(test))]
-use libc::c_int;
-#[cfg(not(test))]
 use num::FpCategory;
 
 
@@ -73,8 +71,6 @@ mod cmath {
         pub fn atan2f(a: c_float, b: c_float) -> c_float;
         pub fn atanf(n: c_float) -> c_float;
         pub fn coshf(n: c_float) -> c_float;
-        pub fn frexpf(n: c_float, value: &mut c_int) -> c_float;
-        pub fn ldexpf(x: c_float, n: c_int) -> c_float;
         pub fn sinhf(n: c_float) -> c_float;
         pub fn tanf(n: c_float) -> c_float;
         pub fn tanhf(n: c_float) -> c_float;
@@ -84,7 +80,7 @@ mod cmath {
     pub use self::shims::*;
     #[cfg(target_env = "msvc")]
     mod shims {
-        use libc::{c_float, c_int};
+        use libc::c_float;
 
         #[inline]
         pub unsafe fn acosf(n: c_float) -> c_float {
@@ -112,20 +108,6 @@ mod cmath {
         }
 
         #[inline]
-        #[allow(deprecated)]
-        pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float {
-            let (a, b) = f64::frexp(x as f64);
-            *value = b as c_int;
-            a as c_float
-        }
-
-        #[inline]
-        #[allow(deprecated)]
-        pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float {
-            f64::ldexp(x as f64, n as isize) as c_float
-        }
-
-        #[inline]
         pub unsafe fn sinhf(n: c_float) -> c_float {
             f64::sinh(n as f64) as c_float
         }
@@ -244,40 +226,6 @@ impl f32 {
     #[inline]
     pub fn classify(self) -> FpCategory { num::Float::classify(self) }
 
-    /// Returns the mantissa, base 2 exponent, and sign as integers, respectively.
-    /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`.
-    /// The floating point encoding is documented in the [Reference][floating-point].
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// use std::f32;
-    ///
-    /// let num = 2.0f32;
-    ///
-    /// // (8388608, -22, 1)
-    /// let (mantissa, exponent, sign) = num.integer_decode();
-    /// let sign_f = sign as f32;
-    /// let mantissa_f = mantissa as f32;
-    /// let exponent_f = num.powf(exponent as f32);
-    ///
-    /// // 1 * 8388608 * 2^(-22) == 2
-    /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs();
-    ///
-    /// assert!(abs_difference <= f32::EPSILON);
-    /// ```
-    /// [floating-point]: ../reference/types.html#machine-types
-    #[unstable(feature = "float_extras", reason = "signature is undecided",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    #[allow(deprecated)]
-    pub fn integer_decode(self) -> (u64, i16, i8) {
-        num::Float::integer_decode(self)
-    }
-
     /// Returns the largest integer less than or equal to a number.
     ///
     /// ```
@@ -712,89 +660,6 @@ impl f32 {
     #[inline]
     pub fn to_radians(self) -> f32 { num::Float::to_radians(self) }
 
-    /// Constructs a floating point number of `x*2^exp`.
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// use std::f32;
-    /// // 3*2^2 - 12 == 0
-    /// let abs_difference = (f32::ldexp(3.0, 2) - 12.0).abs();
-    ///
-    /// assert!(abs_difference <= f32::EPSILON);
-    /// ```
-    #[unstable(feature = "float_extras",
-               reason = "pending integer conventions",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    pub fn ldexp(x: f32, exp: isize) -> f32 {
-        unsafe { cmath::ldexpf(x, exp as c_int) }
-    }
-
-    /// Breaks the number into a normalized fraction and a base-2 exponent,
-    /// satisfying:
-    ///
-    ///  * `self = x * 2^exp`
-    ///  * `0.5 <= abs(x) < 1.0`
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// use std::f32;
-    ///
-    /// let x = 4.0f32;
-    ///
-    /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0
-    /// let f = x.frexp();
-    /// let abs_difference_0 = (f.0 - 0.5).abs();
-    /// let abs_difference_1 = (f.1 as f32 - 3.0).abs();
-    ///
-    /// assert!(abs_difference_0 <= f32::EPSILON);
-    /// assert!(abs_difference_1 <= f32::EPSILON);
-    /// ```
-    #[unstable(feature = "float_extras",
-               reason = "pending integer conventions",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    pub fn frexp(self) -> (f32, isize) {
-        unsafe {
-            let mut exp = 0;
-            let x = cmath::frexpf(self, &mut exp);
-            (x, exp as isize)
-        }
-    }
-
-    /// Returns the next representable floating-point value in the direction of
-    /// `other`.
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// use std::f32;
-    ///
-    /// let x = 1.0f32;
-    ///
-    /// let abs_diff = (x.next_after(2.0) - 1.00000011920928955078125_f32).abs();
-    ///
-    /// assert!(abs_diff <= f32::EPSILON);
-    /// ```
-    #[unstable(feature = "float_extras",
-               reason = "unsure about its place in the world",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    pub fn next_after(self, other: f32) -> f32 {
-        unsafe { cmath::nextafterf(self, other) }
-    }
-
     /// Returns the maximum of the two numbers.
     ///
     /// ```
@@ -1463,23 +1328,6 @@ mod tests {
     }
 
     #[test]
-    #[allow(deprecated)]
-    fn test_integer_decode() {
-        assert_eq!(3.14159265359f32.integer_decode(), (13176795, -22, 1));
-        assert_eq!((-8573.5918555f32).integer_decode(), (8779358, -10, -1));
-        assert_eq!(2f32.powf(100.0).integer_decode(), (8388608, 77, 1));
-        assert_eq!(0f32.integer_decode(), (0, -150, 1));
-        assert_eq!((-0f32).integer_decode(), (0, -150, -1));
-        assert_eq!(INFINITY.integer_decode(), (8388608, 105, 1));
-        assert_eq!(NEG_INFINITY.integer_decode(), (8388608, 105, -1));
-
-        // Ignore the "sign" (quiet / signalling flag) of NAN.
-        // It can vary between runtime operations and LLVM folding.
-        let (nan_m, nan_e, _nan_s) = NAN.integer_decode();
-        assert_eq!((nan_m, nan_e), (12582912, 105));
-    }
-
-    #[test]
     fn test_floor() {
         assert_approx_eq!(1.0f32.floor(), 1.0f32);
         assert_approx_eq!(1.3f32.floor(), 1.0f32);
@@ -1791,58 +1639,6 @@ mod tests {
     }
 
     #[test]
-    #[allow(deprecated)]
-    fn test_ldexp() {
-        let f1 = 2.0f32.powi(-123);
-        let f2 = 2.0f32.powi(-111);
-        let f3 = 1.75 * 2.0f32.powi(-12);
-        assert_eq!(f32::ldexp(1f32, -123), f1);
-        assert_eq!(f32::ldexp(1f32, -111), f2);
-        assert_eq!(f32::ldexp(1.75f32, -12), f3);
-
-        assert_eq!(f32::ldexp(0f32, -123), 0f32);
-        assert_eq!(f32::ldexp(-0f32, -123), -0f32);
-
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        let nan: f32 = f32::NAN;
-        assert_eq!(f32::ldexp(inf, -123), inf);
-        assert_eq!(f32::ldexp(neg_inf, -123), neg_inf);
-        assert!(f32::ldexp(nan, -123).is_nan());
-    }
-
-    #[test]
-    #[allow(deprecated)]
-    fn test_frexp() {
-        let f1 = 2.0f32.powi(-123);
-        let f2 = 2.0f32.powi(-111);
-        let f3 = 1.75 * 2.0f32.powi(-123);
-        let (x1, exp1) = f1.frexp();
-        let (x2, exp2) = f2.frexp();
-        let (x3, exp3) = f3.frexp();
-        assert_eq!((x1, exp1), (0.5f32, -122));
-        assert_eq!((x2, exp2), (0.5f32, -110));
-        assert_eq!((x3, exp3), (0.875f32, -122));
-        assert_eq!(f32::ldexp(x1, exp1), f1);
-        assert_eq!(f32::ldexp(x2, exp2), f2);
-        assert_eq!(f32::ldexp(x3, exp3), f3);
-
-        assert_eq!(0f32.frexp(), (0f32, 0));
-        assert_eq!((-0f32).frexp(), (-0f32, 0));
-    }
-
-    #[test] #[cfg_attr(windows, ignore)] // FIXME #8755
-    #[allow(deprecated)]
-    fn test_frexp_nowin() {
-        let inf: f32 = f32::INFINITY;
-        let neg_inf: f32 = f32::NEG_INFINITY;
-        let nan: f32 = f32::NAN;
-        assert_eq!(match inf.frexp() { (x, _) => x }, inf);
-        assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf);
-        assert!(match nan.frexp() { (x, _) => x.is_nan() })
-    }
-
-    #[test]
     fn test_asinh() {
         assert_eq!(0.0f32.asinh(), 0.0f32);
         assert_eq!((-0.0f32).asinh(), -0.0f32);
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
index be55cb80c92..82e3903eec7 100644
--- a/src/libstd/f64.rs
+++ b/src/libstd/f64.rs
@@ -22,8 +22,6 @@ use core::num;
 #[cfg(not(test))]
 use intrinsics;
 #[cfg(not(test))]
-use libc::c_int;
-#[cfg(not(test))]
 use num::FpCategory;
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -188,36 +186,6 @@ impl f64 {
     #[inline]
     pub fn classify(self) -> FpCategory { num::Float::classify(self) }
 
-    /// Returns the mantissa, base 2 exponent, and sign as integers, respectively.
-    /// The original number can be recovered by `sign * mantissa * 2 ^ exponent`.
-    /// The floating point encoding is documented in the [Reference][floating-point].
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// let num = 2.0f64;
-    ///
-    /// // (8388608, -22, 1)
-    /// let (mantissa, exponent, sign) = num.integer_decode();
-    /// let sign_f = sign as f64;
-    /// let mantissa_f = mantissa as f64;
-    /// let exponent_f = num.powf(exponent as f64);
-    ///
-    /// // 1 * 8388608 * 2^(-22) == 2
-    /// let abs_difference = (sign_f * mantissa_f * exponent_f - num).abs();
-    ///
-    /// assert!(abs_difference < 1e-10);
-    /// ```
-    /// [floating-point]: ../reference/types.html#machine-types
-    #[unstable(feature = "float_extras", reason = "signature is undecided",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    #[allow(deprecated)]
-    pub fn integer_decode(self) -> (u64, i16, i8) { num::Float::integer_decode(self) }
-
     /// Returns the largest integer less than or equal to a number.
     ///
     /// ```
@@ -606,84 +574,6 @@ impl f64 {
     #[inline]
     pub fn to_radians(self) -> f64 { num::Float::to_radians(self) }
 
-    /// Constructs a floating point number of `x*2^exp`.
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// // 3*2^2 - 12 == 0
-    /// let abs_difference = (f64::ldexp(3.0, 2) - 12.0).abs();
-    ///
-    /// assert!(abs_difference < 1e-10);
-    /// ```
-    #[unstable(feature = "float_extras",
-               reason = "pending integer conventions",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    pub fn ldexp(x: f64, exp: isize) -> f64 {
-        unsafe { cmath::ldexp(x, exp as c_int) }
-    }
-
-    /// Breaks the number into a normalized fraction and a base-2 exponent,
-    /// satisfying:
-    ///
-    ///  * `self = x * 2^exp`
-    ///  * `0.5 <= abs(x) < 1.0`
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// let x = 4.0_f64;
-    ///
-    /// // (1/2)*2^3 -> 1 * 8/2 -> 4.0
-    /// let f = x.frexp();
-    /// let abs_difference_0 = (f.0 - 0.5).abs();
-    /// let abs_difference_1 = (f.1 as f64 - 3.0).abs();
-    ///
-    /// assert!(abs_difference_0 < 1e-10);
-    /// assert!(abs_difference_1 < 1e-10);
-    /// ```
-    #[unstable(feature = "float_extras",
-               reason = "pending integer conventions",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    pub fn frexp(self) -> (f64, isize) {
-        unsafe {
-            let mut exp = 0;
-            let x = cmath::frexp(self, &mut exp);
-            (x, exp as isize)
-        }
-    }
-
-    /// Returns the next representable floating-point value in the direction of
-    /// `other`.
-    ///
-    /// ```
-    /// #![feature(float_extras)]
-    ///
-    /// let x = 1.0f64;
-    ///
-    /// let abs_diff = (x.next_after(2.0) - 1.0000000000000002220446049250313_f64).abs();
-    ///
-    /// assert!(abs_diff < 1e-10);
-    /// ```
-    #[unstable(feature = "float_extras",
-               reason = "unsure about its place in the world",
-               issue = "27752")]
-    #[rustc_deprecated(since = "1.11.0",
-                       reason = "never really came to fruition and easily \
-                                 implementable outside the standard library")]
-    #[inline]
-    pub fn next_after(self, other: f64) -> f64 {
-        unsafe { cmath::nextafter(self, other) }
-    }
-
     /// Returns the maximum of the two numbers.
     ///
     /// ```
@@ -1354,23 +1244,6 @@ mod tests {
     }
 
     #[test]
-    #[allow(deprecated)]
-    fn test_integer_decode() {
-        assert_eq!(3.14159265359f64.integer_decode(), (7074237752028906, -51, 1));
-        assert_eq!((-8573.5918555f64).integer_decode(), (4713381968463931, -39, -1));
-        assert_eq!(2f64.powf(100.0).integer_decode(), (4503599627370496, 48, 1));
-        assert_eq!(0f64.integer_decode(), (0, -1075, 1));
-        assert_eq!((-0f64).integer_decode(), (0, -1075, -1));
-        assert_eq!(INFINITY.integer_decode(), (4503599627370496, 972, 1));
-        assert_eq!(NEG_INFINITY.integer_decode(), (4503599627370496, 972, -1));
-
-        // Ignore the "sign" (quiet / signalling flag) of NAN.
-        // It can vary between runtime operations and LLVM folding.
-        let (nan_m, nan_e, _nan_s) = NAN.integer_decode();
-        assert_eq!((nan_m, nan_e), (6755399441055744, 972));
-    }
-
-    #[test]
     fn test_floor() {
         assert_approx_eq!(1.0f64.floor(), 1.0f64);
         assert_approx_eq!(1.3f64.floor(), 1.0f64);
@@ -1682,58 +1555,6 @@ mod tests {
     }
 
     #[test]
-    #[allow(deprecated)]
-    fn test_ldexp() {
-        let f1 = 2.0f64.powi(-123);
-        let f2 = 2.0f64.powi(-111);
-        let f3 = 1.75 * 2.0f64.powi(-12);
-        assert_eq!(f64::ldexp(1f64, -123), f1);
-        assert_eq!(f64::ldexp(1f64, -111), f2);
-        assert_eq!(f64::ldexp(1.75f64, -12), f3);
-
-        assert_eq!(f64::ldexp(0f64, -123), 0f64);
-        assert_eq!(f64::ldexp(-0f64, -123), -0f64);
-
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
-        let nan: f64 = NAN;
-        assert_eq!(f64::ldexp(inf, -123), inf);
-        assert_eq!(f64::ldexp(neg_inf, -123), neg_inf);
-        assert!(f64::ldexp(nan, -123).is_nan());
-    }
-
-    #[test]
-    #[allow(deprecated)]
-    fn test_frexp() {
-        let f1 = 2.0f64.powi(-123);
-        let f2 = 2.0f64.powi(-111);
-        let f3 = 1.75 * 2.0f64.powi(-123);
-        let (x1, exp1) = f1.frexp();
-        let (x2, exp2) = f2.frexp();
-        let (x3, exp3) = f3.frexp();
-        assert_eq!((x1, exp1), (0.5f64, -122));
-        assert_eq!((x2, exp2), (0.5f64, -110));
-        assert_eq!((x3, exp3), (0.875f64, -122));
-        assert_eq!(f64::ldexp(x1, exp1), f1);
-        assert_eq!(f64::ldexp(x2, exp2), f2);
-        assert_eq!(f64::ldexp(x3, exp3), f3);
-
-        assert_eq!(0f64.frexp(), (0f64, 0));
-        assert_eq!((-0f64).frexp(), (-0f64, 0));
-    }
-
-    #[test] #[cfg_attr(windows, ignore)] // FIXME #8755
-    #[allow(deprecated)]
-    fn test_frexp_nowin() {
-        let inf: f64 = INFINITY;
-        let neg_inf: f64 = NEG_INFINITY;
-        let nan: f64 = NAN;
-        assert_eq!(match inf.frexp() { (x, _) => x }, inf);
-        assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf);
-        assert!(match nan.frexp() { (x, _) => x.is_nan() })
-    }
-
-    #[test]
     fn test_asinh() {
         assert_eq!(0.0f64.asinh(), 0.0f64);
         assert_eq!((-0.0f64).asinh(), -0.0f64);
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 367779bb701..70225da5f33 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -248,7 +248,6 @@
 #![feature(allow_internal_unstable)]
 #![feature(asm)]
 #![feature(associated_consts)]
-#![feature(borrow_state)]
 #![feature(box_syntax)]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_thread_local)]
@@ -263,7 +262,6 @@
 #![feature(core_intrinsics)]
 #![feature(dropck_eyepatch)]
 #![feature(exact_size_is_empty)]
-#![feature(float_extras)]
 #![feature(float_from_str_radix)]
 #![feature(fn_traits)]
 #![feature(fnbox)]
@@ -319,7 +317,6 @@
 #![feature(untagged_unions)]
 #![feature(unwind_attributes)]
 #![feature(vec_push_all)]
-#![feature(zero_one)]
 #![cfg_attr(test, feature(update_panic_count))]
 #![cfg_attr(stage0, feature(pub_restricted))]
 #![cfg_attr(test, feature(float_bits_conv))]
diff --git a/src/libstd/num.rs b/src/libstd/num.rs
index 5f83d077a13..ff89887ac92 100644
--- a/src/libstd/num.rs
+++ b/src/libstd/num.rs
@@ -17,9 +17,6 @@
 #![allow(missing_docs)]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(deprecated)]
-pub use core::num::{Zero, One};
-#[stable(feature = "rust1", since = "1.0.0")]
 pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::num::Wrapping;
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 15bc74a8340..9d66430bc93 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -10,7 +10,7 @@
 
 //! Cross-platform path manipulation.
 //!
-//! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`]
+//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`]
 //! and [`str`]), for working with paths abstractly. These types are thin wrappers
 //! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly
 //! on strings according to the local platform's path syntax.
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
index 852675edc02..6c8839224f7 100644
--- a/src/libstd/sync/mpsc/mod.rs
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -452,7 +452,7 @@ pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
 /// An error returned from the [`recv`] function on a [`Receiver`].
 ///
 /// The [`recv`] operation can only fail if the sending half of a
-/// [`channel`] (or [`sync_channel`]) is disconnected, implying that no further
+/// [`channel`][`channel`] (or [`sync_channel`]) is disconnected, implying that no further
 /// messages will ever be received.
 ///
 /// [`recv`]: struct.Receiver.html#method.recv
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 0cdb09a842f..1baf0d1b54c 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -152,6 +152,7 @@ fn maybe_append(mut lhs: Vec<Attribute>, rhs: Option<Vec<Attribute>>)
 enum PrevTokenKind {
     DocComment,
     Comma,
+    Plus,
     Interpolated,
     Eof,
     Other,
@@ -1061,6 +1062,7 @@ impl<'a> Parser<'a> {
         self.prev_token_kind = match self.token {
             token::DocComment(..) => PrevTokenKind::DocComment,
             token::Comma => PrevTokenKind::Comma,
+            token::BinOp(token::Plus) => PrevTokenKind::Plus,
             token::Interpolated(..) => PrevTokenKind::Interpolated,
             token::Eof => PrevTokenKind::Eof,
             _ => PrevTokenKind::Other,
@@ -1354,20 +1356,26 @@ impl<'a> Parser<'a> {
                     break;
                 }
             }
+            let trailing_plus = self.prev_token_kind == PrevTokenKind::Plus;
             self.expect(&token::CloseDelim(token::Paren))?;
 
             if ts.len() == 1 && !last_comma {
                 let ty = ts.into_iter().nth(0).unwrap().unwrap();
+                let maybe_bounds = allow_plus && self.token == token::BinOp(token::Plus);
                 match ty.node {
-                    // Accept `(Trait1) + Trait2 + 'a` for backward compatibility (#39318).
-                    TyKind::Path(None, ref path)
-                            if allow_plus && self.token == token::BinOp(token::Plus) => {
-                        self.bump(); // `+`
-                        let pt = PolyTraitRef::new(Vec::new(), path.clone(), lo.to(self.prev_span));
-                        let mut bounds = vec![TraitTyParamBound(pt, TraitBoundModifier::None)];
-                        bounds.append(&mut self.parse_ty_param_bounds()?);
-                        TyKind::TraitObject(bounds)
+                    // `(TY_BOUND_NOPAREN) + BOUND + ...`.
+                    TyKind::Path(None, ref path) if maybe_bounds => {
+                        self.parse_remaining_bounds(Vec::new(), path.clone(), lo, true)?
                     }
+                    TyKind::TraitObject(ref bounds)
+                            if maybe_bounds && bounds.len() == 1 && !trailing_plus => {
+                        let path = match bounds[0] {
+                            TraitTyParamBound(ref pt, ..) => pt.trait_ref.path.clone(),
+                            _ => self.bug("unexpected lifetime bound"),
+                        };
+                        self.parse_remaining_bounds(Vec::new(), path, lo, true)?
+                    }
+                    // `(TYPE)`
                     _ => TyKind::Paren(P(ty))
                 }
             } else {
@@ -1418,11 +1426,8 @@ impl<'a> Parser<'a> {
                 // Just a type path or bound list (trait object type) starting with a trait.
                 //   `Type`
                 //   `Trait1 + Trait2 + 'a`
-                if allow_plus && self.eat(&token::BinOp(token::Plus)) {
-                    let poly_trait = PolyTraitRef::new(Vec::new(), path, lo.to(self.prev_span));
-                    let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)];
-                    bounds.append(&mut self.parse_ty_param_bounds()?);
-                    TyKind::TraitObject(bounds)
+                if allow_plus && self.check(&token::BinOp(token::Plus)) {
+                    self.parse_remaining_bounds(Vec::new(), path, lo, true)?
                 } else {
                     TyKind::Path(None, path)
                 }
@@ -1440,12 +1445,8 @@ impl<'a> Parser<'a> {
                 self.parse_ty_bare_fn(lifetime_defs)?
             } else {
                 let path = self.parse_path(PathStyle::Type)?;
-                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
-                let mut bounds = vec![TraitTyParamBound(poly_trait, TraitBoundModifier::None)];
-                if allow_plus && self.eat(&token::BinOp(token::Plus)) {
-                    bounds.append(&mut self.parse_ty_param_bounds()?)
-                }
-                TyKind::TraitObject(bounds)
+                let parse_plus = allow_plus && self.check(&token::BinOp(token::Plus));
+                self.parse_remaining_bounds(lifetime_defs, path, lo, parse_plus)?
             }
         } else if self.eat_keyword(keywords::Impl) {
             // FIXME: figure out priority of `+` in `impl Trait1 + Trait2` (#34511).
@@ -1468,6 +1469,17 @@ impl<'a> Parser<'a> {
         Ok(P(ty))
     }
 
+    fn parse_remaining_bounds(&mut self, lifetime_defs: Vec<LifetimeDef>, path: ast::Path,
+                              lo: Span, parse_plus: bool) -> PResult<'a, TyKind> {
+        let poly_trait_ref = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
+        let mut bounds = vec![TraitTyParamBound(poly_trait_ref, TraitBoundModifier::None)];
+        if parse_plus {
+            self.bump(); // `+`
+            bounds.append(&mut self.parse_ty_param_bounds()?);
+        }
+        Ok(TyKind::TraitObject(bounds))
+    }
+
     fn maybe_recover_from_bad_type_plus(&mut self, allow_plus: bool, ty: &Ty) -> PResult<'a, ()> {
         // Do not add `+` to expected tokens.
         if !allow_plus || self.token != token::BinOp(token::Plus) {
@@ -4070,28 +4082,43 @@ impl<'a> Parser<'a> {
     // Parse bounds of a type parameter `BOUND + BOUND + BOUND`, possibly with trailing `+`.
     // BOUND = TY_BOUND | LT_BOUND
     // LT_BOUND = LIFETIME (e.g. `'a`)
-    // TY_BOUND = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`)
+    // TY_BOUND = TY_BOUND_NOPAREN | (TY_BOUND_NOPAREN)
+    // TY_BOUND_NOPAREN = [?] [for<LT_PARAM_DEFS>] SIMPLE_PATH (e.g. `?for<'a: 'b> m::Trait<'a>`)
     fn parse_ty_param_bounds_common(&mut self, allow_plus: bool) -> PResult<'a, TyParamBounds> {
         let mut bounds = Vec::new();
         loop {
-            let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None };
-            if self.check_lifetime() {
-                if let Some(question_span) = question {
-                    self.span_err(question_span,
-                                  "`?` may only modify trait bounds, not lifetime bounds");
-                }
-                bounds.push(RegionTyParamBound(self.expect_lifetime()));
-            } else if self.check_keyword(keywords::For) || self.check_path() {
-                let lo = self.span;
-                let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
-                let path = self.parse_path(PathStyle::Type)?;
-                let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
-                let modifier = if question.is_some() {
-                    TraitBoundModifier::Maybe
+            let is_bound_start = self.check_path() || self.check_lifetime() ||
+                                 self.check(&token::Question) ||
+                                 self.check_keyword(keywords::For) ||
+                                 self.check(&token::OpenDelim(token::Paren));
+            if is_bound_start {
+                let has_parens = self.eat(&token::OpenDelim(token::Paren));
+                let question = if self.eat(&token::Question) { Some(self.prev_span) } else { None };
+                if self.token.is_lifetime() {
+                    if let Some(question_span) = question {
+                        self.span_err(question_span,
+                                      "`?` may only modify trait bounds, not lifetime bounds");
+                    }
+                    bounds.push(RegionTyParamBound(self.expect_lifetime()));
                 } else {
-                    TraitBoundModifier::None
-                };
-                bounds.push(TraitTyParamBound(poly_trait, modifier));
+                    let lo = self.span;
+                    let lifetime_defs = self.parse_late_bound_lifetime_defs()?;
+                    let path = self.parse_path(PathStyle::Type)?;
+                    let poly_trait = PolyTraitRef::new(lifetime_defs, path, lo.to(self.prev_span));
+                    let modifier = if question.is_some() {
+                        TraitBoundModifier::Maybe
+                    } else {
+                        TraitBoundModifier::None
+                    };
+                    bounds.push(TraitTyParamBound(poly_trait, modifier));
+                }
+                if has_parens {
+                    self.expect(&token::CloseDelim(token::Paren))?;
+                    if let Some(&RegionTyParamBound(..)) = bounds.last() {
+                        self.span_err(self.prev_span,
+                                      "parenthesized lifetime bounds are not supported");
+                    }
+                }
             } else {
                 break
             }
diff --git a/src/test/codegen/drop.rs b/src/test/codegen/drop.rs
index a4bd5cf2c15..d7e2cb6d9a5 100644
--- a/src/test/codegen/drop.rs
+++ b/src/test/codegen/drop.rs
@@ -36,7 +36,7 @@ pub fn droppy() {
 // CHECK-NOT: call{{.*}}drop{{.*}}SomeUniqueName
 // CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName
 // CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName
-// CHECK: invoke{{.*}}drop{{.*}}SomeUniqueName
+// CHECK: call{{.*}}drop{{.*}}SomeUniqueName
 // CHECK-NOT: {{(call|invoke).*}}drop{{.*}}SomeUniqueName
 // The next line checks for the } that ends the function definition
 // CHECK-LABEL: {{^[}]}}
diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs
index e0de64b26df..9fd600b32e6 100644
--- a/src/test/codegen/personality_lifetimes.rs
+++ b/src/test/codegen/personality_lifetimes.rs
@@ -37,5 +37,6 @@ pub fn test() {
     // CHECK: bitcast{{.*}}personalityslot
     // CHECK-NEXT: call void @llvm.lifetime.start
     might_unwind();
+    let _t = S;
     might_unwind();
 }
diff --git a/src/test/compile-fail/const-call.rs b/src/test/compile-fail/const-call.rs
index ff83dd004a2..0745ac02d07 100644
--- a/src/test/compile-fail/const-call.rs
+++ b/src/test/compile-fail/const-call.rs
@@ -17,6 +17,4 @@ fn f(x: usize) -> usize {
 fn main() {
     let _ = [0; f(2)];
     //~^ ERROR calls in constants are limited to constant functions
-    //~| ERROR constant evaluation error [E0080]
-    //~| non-constant path in constant expression
 }
diff --git a/src/test/compile-fail/const-pattern-not-const-evaluable.rs b/src/test/compile-fail/const-pattern-not-const-evaluable.rs
index b40aa2a8e27..71cac3edbc1 100644
--- a/src/test/compile-fail/const-pattern-not-const-evaluable.rs
+++ b/src/test/compile-fail/const-pattern-not-const-evaluable.rs
@@ -10,21 +10,22 @@
 
 #![feature(const_fn)]
 
+#[derive(PartialEq, Eq)]
 enum Cake {
     BlackForest,
     Marmor,
 }
 use Cake::*;
 
-const BOO: (Cake, Cake) = (Marmor, BlackForest);
+struct Pair<A, B>(A, B);
+
+const BOO: Pair<Cake, Cake> = Pair(Marmor, BlackForest);
 //~^ ERROR: constant evaluation error [E0080]
-//~| unimplemented constant expression: enum variants
+//~| unimplemented constant expression: tuple struct constructors
 const FOO: Cake = BOO.1;
 
 const fn foo() -> Cake {
     Marmor
-        //~^ ERROR: constant evaluation error [E0080]
-        //~| unimplemented constant expression: enum variants
 }
 
 const WORKS: Cake = Marmor;
@@ -34,7 +35,7 @@ const GOO: Cake = foo();
 fn main() {
     match BlackForest {
         FOO => println!("hi"), //~ NOTE: for pattern here
-        GOO => println!("meh"), //~ NOTE: for pattern here
+        GOO => println!("meh"),
         WORKS => println!("möp"),
         _ => println!("bye"),
     }
diff --git a/src/test/compile-fail/issue-39559.rs b/src/test/compile-fail/issue-39559.rs
index 06e8406cbc0..b7f767f109c 100644
--- a/src/test/compile-fail/issue-39559.rs
+++ b/src/test/compile-fail/issue-39559.rs
@@ -28,10 +28,6 @@ pub struct Vector<T, D: Dim> {
 fn main() {
     let array: [usize; Dim3::dim()]
     //~^ ERROR calls in constants are limited to constant functions
-    //~| ERROR constant evaluation error
-    //~| non-constant path in constant expression
         = [0; Dim3::dim()];
         //~^ ERROR calls in constants are limited to constant functions
-        //~| ERROR constant evaluation error
-        //~| non-constant path in constant expression
 }
diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/compile-fail/issue-41394.rs
index f048b64d104..1fb3b7c4ee1 100644
--- a/src/test/rustdoc/check-hard-break.rs
+++ b/src/test/compile-fail/issue-41394.rs
@@ -8,13 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![crate_name = "foo"]
+enum Foo {
+    A = "" + 1
+    //~^ ERROR binary operation `+` cannot be applied to type `&'static str`
+}
 
-// ignore-tidy-end-whitespace
+enum Bar {
+    A = Foo::A as isize
+}
 
-// @has foo/fn.f.html
-// @has - '<p>hard break:<br />'
-// @has - 'after hard break</p>'
-/// hard break:  
-/// after hard break
-pub fn f() {}
+fn main() {}
diff --git a/src/test/parse-fail/bound-single-question-mark.rs b/src/test/parse-fail/bound-single-question-mark.rs
new file mode 100644
index 00000000000..9dde5268c08
--- /dev/null
+++ b/src/test/parse-fail/bound-single-question-mark.rs
@@ -0,0 +1,13 @@
+// Copyright 2017 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.
+
+// compile-flags: -Z parse-only
+
+fn f<T: ?>() {} //~ ERROR expected identifier, found `>`
diff --git a/src/test/parse-fail/trait-object-bad-parens.rs b/src/test/parse-fail/trait-object-bad-parens.rs
new file mode 100644
index 00000000000..a44c0c3f32f
--- /dev/null
+++ b/src/test/parse-fail/trait-object-bad-parens.rs
@@ -0,0 +1,20 @@
+// Copyright 2017 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.
+
+// compile-flags: -Z parse-only -Z continue-parse-after-error
+
+fn main() {
+    let _: Box<((Copy)) + Copy>;
+    //~^ ERROR expected a path on the left-hand side of `+`, not `((Copy))`
+    let _: Box<(Copy + Copy) + Copy>;
+    //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy + Copy)`
+    let _: Box<(Copy +) + Copy>;
+    //~^ ERROR expected a path on the left-hand side of `+`, not `( Copy)`
+}
diff --git a/src/test/parse-fail/trait-object-lifetime-parens.rs b/src/test/parse-fail/trait-object-lifetime-parens.rs
new file mode 100644
index 00000000000..6be62d966eb
--- /dev/null
+++ b/src/test/parse-fail/trait-object-lifetime-parens.rs
@@ -0,0 +1,18 @@
+// Copyright 2017 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.
+
+// compile-flags: -Z parse-only -Z continue-parse-after-error
+
+fn f<T: Copy + ('a)>() {} //~ ERROR parenthesized lifetime bounds are not supported
+
+fn main() {
+    let _: Box<Copy + ('a)>; //~ ERROR parenthesized lifetime bounds are not supported
+    let _: Box<('a) + Copy>; //~ ERROR expected type, found `'a`
+}
diff --git a/src/test/parse-fail/trait-object-trait-parens.rs b/src/test/parse-fail/trait-object-trait-parens.rs
new file mode 100644
index 00000000000..dc44f4f3fb1
--- /dev/null
+++ b/src/test/parse-fail/trait-object-trait-parens.rs
@@ -0,0 +1,21 @@
+// Copyright 2017 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.
+
+// compile-flags: -Z parse-only
+
+fn f<T: (Copy) + (?Sized) + (for<'a> Trait<'a>)>() {}
+
+fn main() {
+    let _: Box<(Copy) + (?Sized) + (for<'a> Trait<'a>)>;
+    let _: Box<(?Sized) + (for<'a> Trait<'a>) + (Copy)>;
+    let _: Box<(for<'a> Trait<'a>) + (Copy) + (?Sized)>;
+}
+
+FAIL //~ ERROR
diff --git a/src/test/run-pass/auxiliary/issue-41394.rs b/src/test/run-pass/auxiliary/issue-41394.rs
new file mode 100644
index 00000000000..f06b81279ac
--- /dev/null
+++ b/src/test/run-pass/auxiliary/issue-41394.rs
@@ -0,0 +1,26 @@
+// Copyright 2017 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.
+
+#![crate_type = "lib"]
+
+#[repr(u32)]
+pub enum Foo {
+    Foo = Private::Variant as u32
+}
+
+#[repr(u8)]
+enum Private {
+    Variant = 42
+}
+
+#[inline(always)]
+pub fn foo() -> Foo {
+    Foo::Foo
+}
diff --git a/src/test/run-pass/const-pattern-variant.rs b/src/test/run-pass/const-pattern-variant.rs
new file mode 100644
index 00000000000..104ab6e19db
--- /dev/null
+++ b/src/test/run-pass/const-pattern-variant.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.
+
+#![feature(const_fn)]
+
+#[derive(PartialEq, Eq)]
+enum Cake {
+    BlackForest,
+    Marmor,
+}
+use Cake::*;
+
+const BOO: (Cake, Cake) = (Marmor, BlackForest);
+const FOO: Cake = BOO.1;
+
+const fn foo() -> Cake {
+    Marmor
+}
+
+const WORKS: Cake = Marmor;
+
+const GOO: Cake = foo();
+
+fn main() {
+    match BlackForest {
+        FOO => println!("hi"),
+        GOO => println!("meh"),
+        WORKS => println!("möp"),
+        _ => println!("bye"),
+    }
+}
diff --git a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs b/src/test/run-pass/issue-23898.rs
index cadfec5a38d..3f5546ce83d 100644
--- a/src/test/compile-fail/non-constant-enum-for-vec-repeat.rs
+++ b/src/test/run-pass/issue-23898.rs
@@ -8,13 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Note: This test is checking that we forbid a coding pattern that
-// Issue #5873 explicitly wants to allow.
+// Note: This test was used to demonstrate #5873 (now #23898).
 
 enum State { ST_NULL, ST_WHITESPACE }
 
 fn main() {
     [State::ST_NULL; (State::ST_WHITESPACE as usize)];
-    //~^ ERROR constant evaluation error
-    //~| unimplemented constant expression: enum variants
 }
diff --git a/src/test/run-pass/issue-41394.rs b/src/test/run-pass/issue-41394.rs
new file mode 100644
index 00000000000..798905599a8
--- /dev/null
+++ b/src/test/run-pass/issue-41394.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 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:issue-41394.rs
+
+extern crate issue_41394 as lib;
+
+fn main() {
+    assert_eq!(lib::foo() as u32, 42);
+}
diff --git a/src/test/run-pass/issue-8460.rs b/src/test/run-pass/issue-8460.rs
index 5148be5af83..17ea5b9a794 100644
--- a/src/test/run-pass/issue-8460.rs
+++ b/src/test/run-pass/issue-8460.rs
@@ -9,11 +9,22 @@
 // except according to those terms.
 
 // ignore-emscripten no threads support
-#![feature(rustc_attrs, zero_one)]
+#![feature(rustc_attrs)]
 
-use std::num::Zero;
 use std::thread;
 
+trait Int {
+    fn zero() -> Self;
+    fn one() -> Self;
+}
+macro_rules! doit {
+    ($($t:ident)*) => ($(impl Int for $t {
+        fn zero() -> $t { 0 }
+        fn one() -> $t { 1 }
+    })*)
+}
+doit! { i8 i16 i32 i64 isize }
+
 macro_rules! check {
     ($($e:expr),*) => {
         $(assert!(thread::spawn({
@@ -24,21 +35,21 @@ macro_rules! check {
 
 fn main() {
     check![
-        isize::min_value() / -1,
-        i8::min_value() / -1,
-        i16::min_value() / -1,
-        i32::min_value() / -1,
-        i64::min_value() / -1,
+        isize::min_value() / -isize::one(),
+        i8::min_value() / -i8::one(),
+        i16::min_value() / -i16::one(),
+        i32::min_value() / -i32::one(),
+        i64::min_value() / -i64::one(),
         1isize / isize::zero(),
         1i8 / i8::zero(),
         1i16 / i16::zero(),
         1i32 / i32::zero(),
         1i64 / i64::zero(),
-        isize::min_value() % -1,
-        i8::min_value() % -1,
-        i16::min_value() % -1,
-        i32::min_value() % -1,
-        i64::min_value() % -1,
+        isize::min_value() % -isize::one(),
+        i8::min_value() % -i8::one(),
+        i16::min_value() % -i16::one(),
+        i32::min_value() % -i32::one(),
+        i64::min_value() % -i64::one(),
         1isize % isize::zero(),
         1i8 % i8::zero(),
         1i16 % i16::zero(),
diff --git a/src/test/run-pass/sync-send-iterators-in-libcollections.rs b/src/test/run-pass/sync-send-iterators-in-libcollections.rs
index d046705c94b..ea154590dee 100644
--- a/src/test/run-pass/sync-send-iterators-in-libcollections.rs
+++ b/src/test/run-pass/sync-send-iterators-in-libcollections.rs
@@ -10,13 +10,12 @@
 
 #![allow(warnings)]
 #![feature(collections)]
-#![feature(drain, enumset, collections_bound, btree_range, vecmap)]
+#![feature(drain, collections_bound, btree_range, vecmap)]
 
 extern crate collections;
 
 use collections::BinaryHeap;
 use collections::{BTreeMap, BTreeSet};
-use collections::EnumSet;
 use collections::LinkedList;
 use collections::String;
 use collections::Vec;
@@ -25,7 +24,6 @@ use std::collections::HashMap;
 use std::collections::HashSet;
 
 use collections::Bound::Included;
-use collections::enum_set::CLike;
 use std::mem;
 
 fn is_sync<T>(_: T) where T: Sync {}
@@ -76,21 +74,6 @@ fn main() {
 
     all_sync_send!(LinkedList::<usize>::new(), iter, iter_mut, into_iter);
 
-    #[derive(Copy, Clone)]
-    #[repr(usize)]
-    #[allow(dead_code)]
-    enum Foo { A, B, C }
-    impl CLike for Foo {
-        fn to_usize(&self) -> usize {
-            *self as usize
-        }
-
-        fn from_usize(v: usize) -> Foo {
-            unsafe { mem::transmute(v) }
-        }
-    }
-    all_sync_send!(EnumSet::<Foo>::new(), iter);
-
     all_sync_send!(VecDeque::<usize>::new(), iter, iter_mut, into_iter);
     is_sync_send!(VecDeque::<usize>::new(), drain(..));
 
diff --git a/src/test/run-pass/union/union-transmute.rs b/src/test/run-pass/union/union-transmute.rs
index 4eb66268ab8..7a0b4c6aaca 100644
--- a/src/test/run-pass/union/union-transmute.rs
+++ b/src/test/run-pass/union/union-transmute.rs
@@ -8,12 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(core_float)]
-#![feature(float_extras)]
 #![feature(untagged_unions)]
 
 extern crate core;
-use core::num::Float;
+use core::f32;
 
 union U {
     a: (u8, u8),
@@ -33,8 +31,8 @@ fn main() {
         assert_eq!(u.a, (2, 2));
 
         let mut w = W { a: 0b0_11111111_00000000000000000000000 };
-        assert_eq!(w.b, f32::infinity());
-        w.b = f32::neg_infinity();
+        assert_eq!(w.b, f32::INFINITY);
+        w.b = f32::NEG_INFINITY;
         assert_eq!(w.a, 0b1_11111111_00000000000000000000000);
     }
 }
diff --git a/src/test/run-pass/while-let.rs b/src/test/run-pass/while-let.rs
index 9ffba2c7999..aed6986c5fe 100644
--- a/src/test/run-pass/while-let.rs
+++ b/src/test/run-pass/while-let.rs
@@ -9,8 +9,6 @@
 // except according to those terms.
 
 
-#![feature(binary_heap_extras)]
-
 use std::collections::BinaryHeap;
 
 fn make_pq() -> BinaryHeap<isize> {
diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs
deleted file mode 100644
index 46542677857..00000000000
--- a/src/test/rustdoc/check-rule-image-footnote.rs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright 2017 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.
-
-#![crate_name = "foo"]
-
-// ignore-tidy-linelength
-
-// @has foo/fn.f.html
-// @has - '<p>markdown test</p>'
-// @has - '<p>this is a <a href="https://example.com" title="this is a title">link</a>.</p>'
-// @has - '<hr />'
-// @has - '<p>a footnote<sup id="supref1"><a href="#ref1">1</a></sup>.</p>'
-// @has - '<p>another footnote<sup id="supref2"><a href="#ref2">2</a></sup>.</p>'
-// @has - '<p><img src="https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png" alt="Rust" /></p>'
-// @has - '<div class="footnotes"><hr><ol><li id="ref1">'
-// @has - '<p>Thing&nbsp;<a href="#supref1" rev="footnote">↩</a></p></li><li id="ref2">'
-// @has - '<p>Another Thing&nbsp;<a href="#supref2" rev="footnote">↩</a></p></li></ol></div>'
-/// markdown test
-///
-/// this is a [link].
-///
-/// [link]: https://example.com "this is a title"
-///
-/// -----------
-///
-/// a footnote[^footnote].
-///
-/// another footnote[^footnotebis].
-///
-/// [^footnote]: Thing
-///
-///
-/// [^footnotebis]: Another Thing
-///
-///
-/// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png)
-pub fn f() {}
diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs
index efadde99227..ca383b5add0 100644
--- a/src/tools/error_index_generator/main.rs
+++ b/src/tools/error_index_generator/main.rs
@@ -24,7 +24,7 @@ use std::path::PathBuf;
 
 use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
 
-use rustdoc::html::markdown::{Markdown, PLAYGROUND};
+use rustdoc::html::markdown::{Markdown, PLAYGROUND, RenderType};
 use rustc_serialize::json;
 
 enum OutputFormat {
@@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter {
 
         // Description rendered as markdown.
         match info.description {
-            Some(ref desc) => write!(output, "{}", Markdown(desc))?,
+            Some(ref desc) => write!(output, "{}", Markdown(desc, RenderType::Hoedown))?,
             None => write!(output, "<p>No description.</p>\n")?,
         }