summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.gitignore16
-rw-r--r--src/doc/book/advanced-linking.md4
-rw-r--r--src/doc/book/closures.md49
-rw-r--r--src/doc/book/compiler-plugins.md10
-rw-r--r--src/doc/book/concurrency.md8
-rw-r--r--src/doc/book/documentation.md12
-rw-r--r--src/doc/book/ffi.md12
-rw-r--r--src/doc/book/functions.md4
-rw-r--r--src/doc/book/inline-assembly.md2
-rw-r--r--src/doc/book/loops.md2
-rw-r--r--src/doc/book/macros.md10
-rw-r--r--src/doc/book/mutability.md2
-rw-r--r--src/doc/book/operators-and-overloading.md2
-rw-r--r--src/doc/book/trait-objects.md2
-rw-r--r--src/doc/book/traits.md2
-rw-r--r--src/doc/book/vectors.md4
-rw-r--r--src/libcore/char.rs12
-rw-r--r--src/libcore/slice.rs17
-rw-r--r--src/libcore/sync/atomic.rs11
-rw-r--r--src/libcoretest/char.rs33
m---------src/liblibc0
-rw-r--r--src/librustc/cfg/construct.rs4
-rw-r--r--src/librustc/cfg/mod.rs2
-rw-r--r--src/librustc/dep_graph/debug.rs69
-rw-r--r--src/librustc/dep_graph/dep_node.rs7
-rw-r--r--src/librustc/dep_graph/mod.rs2
-rw-r--r--src/librustc/dep_graph/query.rs21
-rw-r--r--src/librustc/dep_graph/thread.rs3
-rw-r--r--src/librustc/dep_graph/visit.rs3
-rw-r--r--src/librustc/hir/fold.rs30
-rw-r--r--src/librustc/hir/intravisit.rs31
-rw-r--r--src/librustc/hir/lowering.rs100
-rw-r--r--src/librustc/hir/map/def_collector.rs4
-rw-r--r--src/librustc/hir/map/definitions.rs37
-rw-r--r--src/librustc/hir/map/mod.rs15
-rw-r--r--src/librustc/hir/mod.rs91
-rw-r--r--src/librustc/hir/pat_util.rs18
-rw-r--r--src/librustc/hir/print.rs36
-rw-r--r--src/librustc/hir/svh.rs72
-rw-r--r--src/librustc/infer/error_reporting.rs6
-rw-r--r--src/librustc/infer/region_inference/mod.rs4
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/lint/builtin.rs10
-rw-r--r--src/librustc/middle/cstore.rs25
-rw-r--r--src/librustc/middle/dependency_format.rs7
-rw-r--r--src/librustc/middle/liveness.rs4
-rw-r--r--src/librustc/middle/reachable.rs2
-rw-r--r--src/librustc/middle/resolve_lifetime.rs2
-rw-r--r--src/librustc/middle/weak_lang_items.rs1
-rw-r--r--src/librustc/session/config.rs19
-rw-r--r--src/librustc/session/mod.rs28
-rw-r--r--src/librustc/traits/error_reporting.rs98
-rw-r--r--src/librustc/traits/mod.rs1
-rw-r--r--src/librustc/traits/project.rs469
-rw-r--r--src/librustc/traits/specialize/mod.rs32
-rw-r--r--src/librustc/ty/context.rs51
-rw-r--r--src/librustc/ty/fold.rs80
-rw-r--r--src/librustc/ty/mod.rs2
-rw-r--r--src/librustc/ty/util.rs2
-rw-r--r--src/librustc_back/target/i686_linux_android.rs6
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs2
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs2
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/move_error.rs18
-rw-r--r--src/librustc_borrowck/diagnostics.rs29
-rw-r--r--src/librustc_const_eval/check_match.rs8
-rw-r--r--src/librustc_data_structures/graph/mod.rs14
-rw-r--r--src/librustc_driver/driver.rs14
-rw-r--r--src/librustc_driver/lib.rs15
-rw-r--r--src/librustc_driver/pretty.rs2
-rw-r--r--src/librustc_driver/test.rs11
-rw-r--r--src/librustc_incremental/assert_dep_graph.rs30
-rw-r--r--src/librustc_incremental/calculate_svh.rs19
-rw-r--r--src/librustc_incremental/persist/data.rs61
-rw-r--r--src/librustc_incremental/persist/directory.rs21
-rw-r--r--src/librustc_incremental/persist/hash.rs163
-rw-r--r--src/librustc_incremental/persist/load.rs20
-rw-r--r--src/librustc_incremental/persist/mod.rs1
-rw-r--r--src/librustc_incremental/persist/save.rs197
-rw-r--r--src/librustc_incremental/persist/util.rs21
-rw-r--r--src/librustc_lint/bad_style.rs4
-rw-r--r--src/librustc_lint/builtin.rs2
-rw-r--r--src/librustc_lint/lib.rs6
-rw-r--r--src/librustc_metadata/common.rs3
-rw-r--r--src/librustc_metadata/creader.rs2
-rw-r--r--src/librustc_metadata/csearch.rs64
-rw-r--r--src/librustc_metadata/cstore.rs16
-rw-r--r--src/librustc_metadata/decoder.rs47
-rw-r--r--src/librustc_metadata/encoder.rs135
-rw-r--r--src/librustc_metadata/index.rs2
-rw-r--r--src/librustc_metadata/loader.rs2
-rw-r--r--src/librustc_mir/build/mod.rs4
-rw-r--r--src/librustc_mir/hair/cx/pattern.rs4
-rw-r--r--src/librustc_resolve/lib.rs7
-rw-r--r--src/librustc_trans/_match.rs8
-rw-r--r--src/librustc_trans/back/link.rs83
-rw-r--r--src/librustc_trans/back/linker.rs125
-rw-r--r--src/librustc_trans/back/lto.rs7
-rw-r--r--src/librustc_trans/base.rs38
-rw-r--r--src/librustc_trans/context.rs6
-rw-r--r--src/librustc_trans/debuginfo/create_scope_map.rs6
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs2
-rw-r--r--src/librustc_trans/debuginfo/mod.rs50
-rw-r--r--src/librustc_trans/expr.rs4
-rw-r--r--src/librustc_typeck/astconv.rs123
-rw-r--r--src/librustc_typeck/check/_match.rs4
-rw-r--r--src/librustc_typeck/check/method/suggest.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs37
-rw-r--r--src/librustc_typeck/collect.rs3
-rw-r--r--src/librustc_typeck/diagnostics.rs8
-rw-r--r--src/librustdoc/clean/mod.rs18
-rw-r--r--src/librustdoc/core.rs19
-rw-r--r--src/librustdoc/html/render.rs5
-rw-r--r--src/librustdoc/html/static/rustdoc.css4
-rw-r--r--src/librustdoc/test.rs13
-rw-r--r--src/libstd/thread/mod.rs4
-rw-r--r--src/libsyntax/ast.rs4
-rw-r--r--src/libsyntax/errors/emitter.rs12
-rw-r--r--src/libsyntax/errors/mod.rs64
-rw-r--r--src/libsyntax/errors/snippet/mod.rs50
-rw-r--r--src/libsyntax/ext/expand.rs8
-rw-r--r--src/libsyntax_ext/format.rs26
-rw-r--r--src/test/compile-fail/E0027.rs22
-rw-r--r--src/test/compile-fail/E0029.rs18
-rw-r--r--src/test/compile-fail/E0030.rs16
-rw-r--r--src/test/compile-fail/E0033.rs19
-rw-r--r--src/test/compile-fail/E0034.rs26
-rw-r--r--src/test/compile-fail/E0035.rs20
-rw-r--r--src/test/compile-fail/associated-types-eq-hr.rs49
-rw-r--r--src/test/compile-fail/associated-types/bound-lifetime-constrained.rs66
-rw-r--r--src/test/compile-fail/associated-types/bound-lifetime-in-binding-only.rs90
-rw-r--r--src/test/compile-fail/associated-types/bound-lifetime-in-return-only.rs64
-rw-r--r--src/test/compile-fail/auxiliary/cdylib-dep.rs11
-rw-r--r--src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs3
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-error-with-note.rs14
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs6
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs6
-rw-r--r--src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs4
-rw-r--r--src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs6
-rw-r--r--src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs28
-rw-r--r--src/test/compile-fail/cdylib-deps-must-be-static.rs17
-rw-r--r--src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs2
-rw-r--r--src/test/compile-fail/issue-15167.rs12
-rw-r--r--src/test/compile-fail/issue-26480.rs4
-rw-r--r--src/test/compile-fail/issue-30255.rs35
-rw-r--r--src/test/compile-fail/macro-backtrace-invalid-internals.rs10
-rw-r--r--src/test/compile-fail/macro-backtrace-nested.rs11
-rw-r--r--src/test/compile-fail/macro-backtrace-println.rs8
-rw-r--r--src/test/compile-fail/moves-based-on-type-block-bad.rs5
-rw-r--r--src/test/compile-fail/on-unimplemented/bad-annotation.rs (renamed from src/test/compile-fail/on-unimplemented-bad-anno.rs)0
-rw-r--r--src/test/compile-fail/on-unimplemented/multiple-impls.rs55
-rw-r--r--src/test/compile-fail/on-unimplemented/on-impl.rs (renamed from src/test/compile-fail/check_on_unimplemented.rs)0
-rw-r--r--src/test/compile-fail/on-unimplemented/on-trait.rs (renamed from src/test/compile-fail/on-unimplemented.rs)0
-rw-r--r--src/test/compile-fail/on-unimplemented/slice-index.rs (renamed from src/test/compile-fail/check_on_unimplemented_on_slice.rs)4
-rw-r--r--src/test/compile-fail/variant-used-as-type.rs30
-rw-r--r--src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs24
-rw-r--r--src/test/incremental/callee_caller_cross_crate/b.rs28
-rw-r--r--src/test/incremental/type_alias_cross_crate/auxiliary/a.rs21
-rw-r--r--src/test/incremental/type_alias_cross_crate/b.rs29
-rw-r--r--src/test/run-make/cdylib/Makefile19
-rw-r--r--src/test/run-make/cdylib/bar.rs15
-rw-r--r--src/test/run-make/cdylib/foo.c20
-rw-r--r--src/test/run-make/cdylib/foo.rs23
-rw-r--r--src/test/run-make/execution-engine/test.rs12
-rw-r--r--src/test/run-make/issue-19371/foo.rs6
-rw-r--r--src/tools/compiletest/src/header.rs16
-rw-r--r--src/tools/compiletest/src/json.rs11
-rw-r--r--src/tools/compiletest/src/runtest.rs77
167 files changed, 3061 insertions, 1189 deletions
diff --git a/.gitignore b/.gitignore
index acd47803969..5e8c40d03fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,7 +17,6 @@
 *.elc
 *.epub
 *.exe
-*.pdb
 *.fn
 *.html
 *.kdev4
@@ -29,6 +28,7 @@
 *.orig
 *.out
 *.patch
+*.pdb
 *.pdf
 *.pg
 *.pot
@@ -50,6 +50,10 @@
 .cproject
 .hg/
 .hgignore
+.idea
+__pycache__/
+*.py[cod]
+*$py.class
 .project
 .settings/
 .valgrindrc
@@ -65,6 +69,7 @@
 /llvm/
 /mingw-build/
 /nd/
+/obj/
 /rt/
 /rustllvm/
 /src/libunicode/DerivedCoreProperties.txt
@@ -73,13 +78,10 @@
 /src/libunicode/PropList.txt
 /src/libunicode/Scripts.txt
 /src/libunicode/UnicodeData.txt
-/stage0/
-/stage1/
-/stage2/
-/stage3/
+/stage[0-9]+/
+/target
 /test/
 /tmp/
-/obj/
 TAGS
 TAGS.emacs
 TAGS.vi
@@ -89,11 +91,9 @@ config.mk
 config.stamp
 keywords.md
 lexer.ml
-src/.DS_Store
 src/etc/dl
 src/librustc_llvm/llvmdeps.rs
 tmp.*.rs
 version.md
 version.ml
 version.texi
-/target
diff --git a/src/doc/book/advanced-linking.md b/src/doc/book/advanced-linking.md
index 9ef6d5c2bff..c8a9082947e 100644
--- a/src/doc/book/advanced-linking.md
+++ b/src/doc/book/advanced-linking.md
@@ -12,7 +12,7 @@ the `link_args` attribute. This attribute is applied to `extern` blocks and
 specifies raw flags which need to get passed to the linker when producing an
 artifact. An example usage would be:
 
-``` no_run
+```rust,no_run
 #![feature(link_args)]
 
 #[link_args = "-foo -bar -baz"]
@@ -52,7 +52,7 @@ By default, all Rust programs on Linux will link to the system `libc` along with
 a number of other libraries. Let's look at an example on a 64-bit Linux machine
 with GCC and `glibc` (by far the most common `libc` on Linux):
 
-``` text
+```text
 $ cat example.rs
 fn main() {}
 $ rustc example.rs
diff --git a/src/doc/book/closures.md b/src/doc/book/closures.md
index d81619b647f..dedf9d5c28a 100644
--- a/src/doc/book/closures.md
+++ b/src/doc/book/closures.md
@@ -319,6 +319,53 @@ assert_eq!(3, answer);
 Now we take a trait object, a `&Fn`. And we have to make a reference
 to our closure when we pass it to `call_with_one`, so we use `&||`.
 
+A quick note about closures that use explicit lifetimes. Sometimes you might have a closure
+that takes a reference like so:
+
+```
+fn call_with_ref<F>(some_closure:F) -> i32
+    where F: Fn(&i32) -> i32 {
+
+    let mut value = 0;
+    some_closure(&value)
+}
+```
+
+Normally you can specify the lifetime of the parameter to our closure. We
+could annotate it on the function declaration:
+
+```ignore
+fn call_with_ref<'a, F>(some_closure:F) -> i32 
+    where F: Fn(&'a 32) -> i32 {
+```
+
+However this presents a problem with in our case. When you specify the explict
+lifetime on a function it binds that lifetime to the *entire* scope of the function
+instead of just the invocation scope of our closure. This means that the borrow checker
+will see a mutable reference in the same lifetime as our immutable reference and fail
+to compile.
+
+In order to say that we only need the lifetime to be valid for the invocation scope
+of the closure we can use Higher-Ranked Trait Bounds with the `for<...>` syntax:
+
+```ignore
+fn call_with_ref<F>(some_closure:F) -> i32
+    where F: for<'a> Fn(&'a 32) -> i32 {
+```
+
+This lets the Rust compiler find the minimum lifetime to invoke our closure and 
+satisfy the borrow checker's rules. Our function then compiles and excutes as we
+expect.
+
+```
+fn call_with_ref<F>(some_closure:F) -> i32
+    where F: for<'a> Fn(&'a i32) -> i32 {
+
+    let mut value = 0;
+    some_closure(&value)
+}
+```
+
 # Function pointers and closures
 
 A function pointer is kind of like a closure that has no environment. As such,
@@ -344,7 +391,7 @@ assert_eq!(2, answer);
 In this example, we don’t strictly need the intermediate variable `f`,
 the name of the function works just fine too:
 
-```ignore
+```rust,ignore
 let answer = call_with_one(&add_one);
 ```
 
diff --git a/src/doc/book/compiler-plugins.md b/src/doc/book/compiler-plugins.md
index 1af05bfea19..2d0cc61fb11 100644
--- a/src/doc/book/compiler-plugins.md
+++ b/src/doc/book/compiler-plugins.md
@@ -37,7 +37,7 @@ Let's write a plugin
 [`roman_numerals.rs`](https://github.com/rust-lang/rust/tree/master/src/test/auxiliary/roman_numerals.rs)
 that implements Roman numeral integer literals.
 
-```ignore
+```rust,ignore
 #![crate_type="dylib"]
 #![feature(plugin_registrar, rustc_private)]
 
@@ -102,7 +102,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
 
 Then we can use `rn!()` like any other macro:
 
-```ignore
+```rust,ignore
 #![feature(plugin)]
 #![plugin(roman_numerals)]
 
@@ -132,7 +132,7 @@ Some of the [macro debugging tips](macros.html#debugging-macro-code) are applica
 You can use `syntax::parse` to turn token trees into
 higher-level syntax elements like expressions:
 
-```ignore
+```rust,ignore
 fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
         -> Box<MacResult+'static> {
 
@@ -169,7 +169,7 @@ infrastructure](../reference.html#lint-check-attributes) with additional checks
 code style, safety, etc. Now let's write a plugin [`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/auxiliary/lint_plugin_test.rs)
 that warns about any item named `lintme`.
 
-```ignore
+```rust,ignore
 #![feature(plugin_registrar)]
 #![feature(box_syntax, rustc_private)]
 
@@ -211,7 +211,7 @@ pub fn plugin_registrar(reg: &mut Registry) {
 
 Then code like
 
-```ignore
+```rust,ignore
 #![plugin(lint_plugin_test)]
 
 fn lintme() { }
diff --git a/src/doc/book/concurrency.md b/src/doc/book/concurrency.md
index c179629a79a..a783650f8ea 100644
--- a/src/doc/book/concurrency.md
+++ b/src/doc/book/concurrency.md
@@ -165,7 +165,7 @@ concurrency bugs.
 As an example, here is a Rust program that would have a data race in many
 languages. It will not compile:
 
-```ignore
+```rust,ignore
 use std::thread;
 use std::time::Duration;
 
@@ -204,7 +204,7 @@ Calling `clone()` on an `Rc<T>` will return a new owned reference and bump the
 internal reference count. We create one of these for each thread:
 
 
-```ignore
+```rust,ignore
 use std::thread;
 use std::time::Duration;
 use std::rc::Rc;
@@ -250,7 +250,7 @@ In essence, `Arc<T>` is a type that lets us share ownership of data _across
 threads_.
 
 
-```ignore
+```rust,ignore
 use std::thread;
 use std::sync::Arc;
 use std::time::Duration;
@@ -336,7 +336,7 @@ The lock "release" here is implicit; when the result of the lock (in this case,
 Note that [`lock`](../std/sync/struct.Mutex.html#method.lock) method of
 [`Mutex`](../std/sync/struct.Mutex.html) has this signature:
 
-```ignore
+```rust,ignore
 fn lock(&self) -> LockResult<MutexGuard<T>>
 ```
 
diff --git a/src/doc/book/documentation.md b/src/doc/book/documentation.md
index 8d1e58ac173..4a41bb7b7f3 100644
--- a/src/doc/book/documentation.md
+++ b/src/doc/book/documentation.md
@@ -362,7 +362,7 @@ Here’s an example of documenting a macro:
 /// # }
 /// ```
 ///
-/// ```should_panic
+/// ```rust,should_panic
 /// # #[macro_use] extern crate foo;
 /// # fn main() {
 /// panic_unless!(true == false, “I’m broken.”);
@@ -429,7 +429,7 @@ There are a few more annotations that are useful to help `rustdoc` do the right
 thing when testing your code:
 
 ```rust
-/// ```ignore
+/// ```rust,ignore
 /// fn foo() {
 /// ```
 # fn foo() {}
@@ -441,7 +441,7 @@ with `text` if it's not code, or using `#`s to get a working example that
 only shows the part you care about.
 
 ```rust
-/// ```should_panic
+/// ```rust,should_panic
 /// assert!(false);
 /// ```
 # fn foo() {}
@@ -451,7 +451,7 @@ only shows the part you care about.
 not actually pass as a test.
 
 ```rust
-/// ```no_run
+/// ```rust,no_run
 /// loop {
 ///     println!("Hello, world");
 /// }
@@ -563,7 +563,7 @@ can be useful when changing some options, or when writing a macro.
 
 `rustdoc` will show the documentation for a public re-export in both places:
 
-```ignore
+```rust,ignore
 extern crate foo;
 
 pub use foo::bar;
@@ -575,7 +575,7 @@ documentation in both places.
 
 This behavior can be suppressed with `no_inline`:
 
-```ignore
+```rust,ignore
 extern crate foo;
 
 #[doc(no_inline)]
diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md
index 6aec8d2a048..f48e87c4224 100644
--- a/src/doc/book/ffi.md
+++ b/src/doc/book/ffi.md
@@ -28,7 +28,7 @@ and add `extern crate libc;` to your crate root.
 The following is a minimal example of calling a foreign function which will
 compile if snappy is installed:
 
-```no_run
+```rust,no_run
 # #![feature(libc)]
 extern crate libc;
 use libc::size_t;
@@ -62,7 +62,7 @@ keeping the binding correct at runtime.
 
 The `extern` block can be extended to cover the entire snappy API:
 
-```no_run
+```rust,no_run
 # #![feature(libc)]
 extern crate libc;
 use libc::{c_int, size_t};
@@ -209,7 +209,7 @@ A basic example is:
 
 Rust code:
 
-```no_run
+```rust,no_run
 extern fn callback(a: i32) {
     println!("I'm called from C with value {0}", a);
 }
@@ -262,7 +262,7 @@ referenced Rust object.
 
 Rust code:
 
-```no_run
+```rust,no_run
 #[repr(C)]
 struct RustObject {
     a: i32,
@@ -406,7 +406,7 @@ Foreign APIs often export a global variable which could do something like track
 global state. In order to access these variables, you declare them in `extern`
 blocks with the `static` keyword:
 
-```no_run
+```rust,no_run
 # #![feature(libc)]
 extern crate libc;
 
@@ -425,7 +425,7 @@ Alternatively, you may need to alter global state provided by a foreign
 interface. To do this, statics can be declared with `mut` so we can mutate
 them.
 
-```no_run
+```rust,no_run
 # #![feature(libc)]
 extern crate libc;
 
diff --git a/src/doc/book/functions.md b/src/doc/book/functions.md
index 8a2444323f1..3a10d2aecc2 100644
--- a/src/doc/book/functions.md
+++ b/src/doc/book/functions.md
@@ -134,7 +134,7 @@ x = y = 5
 In Rust, however, using `let` to introduce a binding is _not_ an expression. The
 following will produce a compile-time error:
 
-```ignore
+```rust,ignore
 let x = (let y = 5); // expected identifier, found keyword `let`
 ```
 
@@ -283,7 +283,7 @@ stack backtrace:
 
 A diverging function can be used as any type:
 
-```should_panic
+```rust,should_panic
 # fn diverges() -> ! {
 #    panic!("This function never returns!");
 # }
diff --git a/src/doc/book/inline-assembly.md b/src/doc/book/inline-assembly.md
index a5a2d7ce74e..2c2d89a1fbf 100644
--- a/src/doc/book/inline-assembly.md
+++ b/src/doc/book/inline-assembly.md
@@ -4,7 +4,7 @@ For extremely low-level manipulations and performance reasons, one
 might wish to control the CPU directly. Rust supports using inline
 assembly to do this via the `asm!` macro.
 
-```ignore
+```rust,ignore
 asm!(assembly template
    : output operands
    : input operands
diff --git a/src/doc/book/loops.md b/src/doc/book/loops.md
index b5dde9be17f..97ca2e3e702 100644
--- a/src/doc/book/loops.md
+++ b/src/doc/book/loops.md
@@ -74,7 +74,7 @@ for x in 0..10 {
 
 In slightly more abstract terms,
 
-```ignore
+```rust,ignore
 for var in expression {
     code
 }
diff --git a/src/doc/book/macros.md b/src/doc/book/macros.md
index c16e2ea4535..f535fb96af8 100644
--- a/src/doc/book/macros.md
+++ b/src/doc/book/macros.md
@@ -78,7 +78,7 @@ macro_rules! vec {
 
 Whoa, that’s a lot of new syntax! Let’s break it down.
 
-```ignore
+```rust,ignore
 macro_rules! vec { ... }
 ```
 
@@ -92,7 +92,7 @@ syntax and serves to distinguish a macro from an ordinary function.
 The macro is defined through a series of rules, which are pattern-matching
 cases. Above, we had
 
-```ignore
+```rust,ignore
 ( $( $x:expr ),* ) => { ... };
 ```
 
@@ -112,7 +112,7 @@ separated by commas.
 Aside from the special matcher syntax, any Rust tokens that appear in a matcher
 must match exactly. For example,
 
-```rust
+```rust,ignore
 macro_rules! foo {
     (x => $e:expr) => (println!("mode X: {}", $e));
     (y => $e:expr) => (println!("mode Y: {}", $e));
@@ -147,7 +147,7 @@ The right-hand side of a macro rule is ordinary Rust syntax, for the most part.
 But we can splice in bits of syntax captured by the matcher. From the original
 example:
 
-```ignore
+```rust,ignore
 $(
     temp_vec.push($x);
 )*
@@ -165,7 +165,7 @@ within the repeated block.
 Another detail: the `vec!` macro has *two* pairs of braces on the right-hand
 side. They are often combined like so:
 
-```ignore
+```rust,ignore
 macro_rules! foo {
     () => {{
         ...
diff --git a/src/doc/book/mutability.md b/src/doc/book/mutability.md
index 6aad3c5f746..e4627151146 100644
--- a/src/doc/book/mutability.md
+++ b/src/doc/book/mutability.md
@@ -55,6 +55,8 @@ fn foo(mut x: i32) {
 # }
 ```
 
+Note that here, the `x` is mutable, but not the `y`.
+
 [pattern]: patterns.html
 
 # Interior vs. Exterior Mutability
diff --git a/src/doc/book/operators-and-overloading.md b/src/doc/book/operators-and-overloading.md
index fcce831c2d0..424e2cda615 100644
--- a/src/doc/book/operators-and-overloading.md
+++ b/src/doc/book/operators-and-overloading.md
@@ -123,7 +123,7 @@ fn main() {
 For `HasArea` and `Square`, we declare a type parameter `T` and replace
 `f64` with it. The `impl` needs more involved modifications:
 
-```ignore
+```rust,ignore
 impl<T> HasArea<T> for Square<T>
         where T: Mul<Output=T> + Copy { ... }
 ```
diff --git a/src/doc/book/trait-objects.md b/src/doc/book/trait-objects.md
index 1d63435ed5f..b31a34a0425 100644
--- a/src/doc/book/trait-objects.md
+++ b/src/doc/book/trait-objects.md
@@ -306,7 +306,7 @@ let y = TraitObject {
 Not every trait can be used to make a trait object. For example, vectors implement
 `Clone`, but if we try to make a trait object:
 
-```ignore
+```rust,ignore
 let v = vec![1, 2, 3];
 let o = &v as &Clone;
 ```
diff --git a/src/doc/book/traits.md b/src/doc/book/traits.md
index b3b41979245..107ef2b44d5 100644
--- a/src/doc/book/traits.md
+++ b/src/doc/book/traits.md
@@ -195,7 +195,7 @@ fn main() {
 `is_square()` needs to check that the sides are equal, so the sides must be of
 a type that implements the [`core::cmp::PartialEq`][PartialEq] trait:
 
-```ignore
+```rust,ignore
 impl<T: PartialEq> Rectangle<T> { ... }
 ```
 
diff --git a/src/doc/book/vectors.md b/src/doc/book/vectors.md
index 75e961e4c4a..1c44af2f21a 100644
--- a/src/doc/book/vectors.md
+++ b/src/doc/book/vectors.md
@@ -40,7 +40,7 @@ The indices count from `0`, so the third element is `v[2]`.
 
 It’s also important to note that you must index with the `usize` type:
 
-```ignore
+```rust,ignore
 let v = vec![1, 2, 3, 4, 5];
 
 let i: usize = 0;
@@ -71,7 +71,7 @@ you cannot index with an `i32`.
 
 If you try to access an index that doesn’t exist:
 
-```ignore
+```rust,ignore
 let v = vec![1, 2, 3];
 println!("Item 7 is {}", v[7]);
 ```
diff --git a/src/libcore/char.rs b/src/libcore/char.rs
index 140403884b9..65b9a27bb68 100644
--- a/src/libcore/char.rs
+++ b/src/libcore/char.rs
@@ -471,6 +471,18 @@ impl Iterator for EscapeUnicode {
         let n = n + self.hex_digit_idx;
         (n, Some(n))
     }
+
+    fn last(self) -> Option<char> {
+        match self.state {
+            EscapeUnicodeState::Done => None,
+
+            EscapeUnicodeState::RightBrace |
+            EscapeUnicodeState::Value |
+            EscapeUnicodeState::LeftBrace |
+            EscapeUnicodeState::Type |
+            EscapeUnicodeState::Backslash => Some('}'),
+        }
+    }
 }
 
 /// An iterator that yields the literal escape code of a `char`.
diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs
index e4b98ed6445..542dfcbe628 100644
--- a/src/libcore/slice.rs
+++ b/src/libcore/slice.rs
@@ -523,8 +523,7 @@ impl<T> SliceExt for [T] {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(unused_attributes)]
-#[rustc_on_unimplemented = "a usize is required to index into a slice"]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::Index<usize> for [T] {
     type Output = T;
 
@@ -535,8 +534,7 @@ impl<T> ops::Index<usize> for [T] {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[allow(unused_attributes)]
-#[rustc_on_unimplemented = "a usize is required to index into a slice"]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::IndexMut<usize> for [T] {
     #[inline]
     fn index_mut(&mut self, index: usize) -> &mut T {
@@ -570,6 +568,7 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! {
 /// Requires that `begin <= end` and `end <= self.len()`,
 /// otherwise slicing will panic.
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::Index<ops::Range<usize>> for [T] {
     type Output = [T];
 
@@ -596,6 +595,7 @@ impl<T> ops::Index<ops::Range<usize>> for [T] {
 ///
 /// Equivalent to `&self[0 .. end]`
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::Index<ops::RangeTo<usize>> for [T] {
     type Output = [T];
 
@@ -611,6 +611,7 @@ impl<T> ops::Index<ops::RangeTo<usize>> for [T] {
 ///
 /// Equivalent to `&self[begin .. self.len()]`
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::Index<ops::RangeFrom<usize>> for [T] {
     type Output = [T];
 
@@ -636,6 +637,7 @@ impl<T> ops::Index<RangeFull> for [T] {
 }
 
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::Index<ops::RangeInclusive<usize>> for [T] {
     type Output = [T];
 
@@ -651,6 +653,7 @@ impl<T> ops::Index<ops::RangeInclusive<usize>> for [T] {
     }
 }
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::Index<ops::RangeToInclusive<usize>> for [T] {
     type Output = [T];
 
@@ -671,6 +674,7 @@ impl<T> ops::Index<ops::RangeToInclusive<usize>> for [T] {
 /// Requires that `begin <= end` and `end <= self.len()`,
 /// otherwise slicing will panic.
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::IndexMut<ops::Range<usize>> for [T] {
     #[inline]
     fn index_mut(&mut self, index: ops::Range<usize>) -> &mut [T] {
@@ -695,6 +699,7 @@ impl<T> ops::IndexMut<ops::Range<usize>> for [T] {
 ///
 /// Equivalent to `&mut self[0 .. end]`
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::IndexMut<ops::RangeTo<usize>> for [T] {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut [T] {
@@ -708,6 +713,7 @@ impl<T> ops::IndexMut<ops::RangeTo<usize>> for [T] {
 ///
 /// Equivalent to `&mut self[begin .. self.len()]`
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::IndexMut<ops::RangeFrom<usize>> for [T] {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut [T] {
@@ -730,6 +736,7 @@ impl<T> ops::IndexMut<RangeFull> for [T] {
 }
 
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for [T] {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeInclusive<usize>) -> &mut [T] {
@@ -743,6 +750,7 @@ impl<T> ops::IndexMut<ops::RangeInclusive<usize>> for [T] {
     }
 }
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
+#[rustc_on_unimplemented = "slice indices are of type `usize`"]
 impl<T> ops::IndexMut<ops::RangeToInclusive<usize>> for [T] {
     #[inline]
     fn index_mut(&mut self, index: ops::RangeToInclusive<usize>) -> &mut [T] {
@@ -1933,4 +1941,3 @@ macro_rules! impl_marker_for {
 
 impl_marker_for!(BytewiseEquality,
                  u8 i8 u16 i16 u32 i32 u64 i64 usize isize char bool);
-
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 52ba8d9a631..1bdab88d71d 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -26,8 +26,9 @@
 //! [1]: http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations
 //!
 //! Atomic variables are safe to share between threads (they implement `Sync`)
-//! but they do not themselves provide the mechanism for sharing. The most
-//! common way to share an atomic variable is to put it into an `Arc` (an
+//! but they do not themselves provide the mechanism for sharing and follow the
+//! [threading model](../../../std/thread/index.html#the-threading-model) of rust.
+//! The most common way to share an atomic variable is to put it into an `Arc` (an
 //! atomically-reference-counted shared pointer).
 //!
 //! Most atomic types may be stored in static variables, initialized using
@@ -48,12 +49,16 @@
 //!     let spinlock = Arc::new(AtomicUsize::new(1));
 //!
 //!     let spinlock_clone = spinlock.clone();
-//!     thread::spawn(move|| {
+//!     let thread = thread::spawn(move|| {
 //!         spinlock_clone.store(0, Ordering::SeqCst);
 //!     });
 //!
 //!     // Wait for the other thread to release the lock
 //!     while spinlock.load(Ordering::SeqCst) != 0 {}
+//!
+//!     if let Err(panic) = thread.join() {
+//!         println!("Thread had an error: {:?}", panic);
+//!     }
 //! }
 //! ```
 //!
diff --git a/src/libcoretest/char.rs b/src/libcoretest/char.rs
index 41fd742c9e0..e959e71daf7 100644
--- a/src/libcoretest/char.rs
+++ b/src/libcoretest/char.rs
@@ -262,4 +262,37 @@ fn ed_iterator_specializations() {
     assert_eq!('\''.escape_default().last(), Some('\''));
 }
 
+#[test]
+fn eu_iterator_specializations() {
+    fn check(c: char) {
+        let len = c.escape_unicode().count();
+
+        // Check OoB
+        assert_eq!(c.escape_unicode().nth(len), None);
+
+        // For all possible in-bound offsets
+        let mut iter = c.escape_unicode();
+        for offset in 0..len {
+            // Check last
+            assert_eq!(iter.clone().last(), Some('}'));
 
+            // Check counting
+            assert_eq!(iter.clone().count(), len - offset);
+
+            // Check nth
+            assert_eq!(c.escape_unicode().nth(offset), iter.next());
+        }
+
+        // Check post-last
+        assert_eq!(iter.clone().last(), None);
+        assert_eq!(iter.clone().count(), 0);
+    }
+
+    check('\u{0}');
+    check('\u{1}');
+    check('\u{12}');
+    check('\u{123}');
+    check('\u{1234}');
+    check('\u{12340}');
+    check('\u{10FFFF}');
+}
diff --git a/src/liblibc b/src/liblibc
-Subproject 6598e2cbfd7e09bfca249cc3dcbf889735f73ce
+Subproject b19b5465a1235be3323363cdc11838739b59302
diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs
index 64c51c94328..76699f13959 100644
--- a/src/librustc/cfg/construct.rs
+++ b/src/librustc/cfg/construct.rs
@@ -285,7 +285,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             }
 
             hir::ExprBreak(label) => {
-                let loop_scope = self.find_scope(expr, label.map(|l| l.node.name));
+                let loop_scope = self.find_scope(expr, label.map(|l| l.node));
                 let b = self.add_ast_node(expr.id, &[pred]);
                 self.add_exiting_edge(expr, b,
                                       loop_scope, loop_scope.break_index);
@@ -293,7 +293,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
             }
 
             hir::ExprAgain(label) => {
-                let loop_scope = self.find_scope(expr, label.map(|l| l.node.name));
+                let loop_scope = self.find_scope(expr, label.map(|l| l.node));
                 let a = self.add_ast_node(expr.id, &[pred]);
                 self.add_exiting_edge(expr, a,
                                       loop_scope, loop_scope.continue_index);
diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs
index 617e2ed2f1a..d06f51073df 100644
--- a/src/librustc/cfg/mod.rs
+++ b/src/librustc/cfg/mod.rs
@@ -64,7 +64,7 @@ impl CFG {
     }
 
     pub fn node_is_reachable(&self, id: ast::NodeId) -> bool {
-        self.graph.depth_traverse(self.entry)
+        self.graph.depth_traverse(self.entry, graph::OUTGOING)
                   .any(|idx| self.graph.node_data(idx).id() == id)
     }
 }
diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs
new file mode 100644
index 00000000000..15b0380374c
--- /dev/null
+++ b/src/librustc/dep_graph/debug.rs
@@ -0,0 +1,69 @@
+// Copyright 2012-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.
+
+//! Code for debugging the dep-graph.
+
+use super::dep_node::DepNode;
+use std::error::Error;
+use std::fmt::Debug;
+
+/// A dep-node filter goes from a user-defined string to a query over
+/// nodes. Right now the format is like this:
+///
+///     x & y & z
+///
+/// where the format-string of the dep-node must contain `x`, `y`, and
+/// `z`.
+#[derive(Debug)]
+pub struct DepNodeFilter {
+    text: String
+}
+
+impl DepNodeFilter {
+    pub fn new(text: &str) -> Self {
+        DepNodeFilter {
+            text: text.trim().to_string()
+        }
+    }
+
+    /// True if all nodes always pass the filter.
+    pub fn accepts_all(&self) -> bool {
+        self.text.is_empty()
+    }
+
+    /// Tests whether `node` meets the filter, returning true if so.
+    pub fn test<D: Clone + Debug>(&self, node: &DepNode<D>) -> bool {
+        let debug_str = format!("{:?}", node);
+        self.text.split("&")
+                 .map(|s| s.trim())
+                 .all(|f| debug_str.contains(f))
+    }
+}
+
+/// A filter like `F -> G` where `F` and `G` are valid dep-node
+/// filters. This can be used to test the source/target independently.
+pub struct EdgeFilter {
+    pub source: DepNodeFilter,
+    pub target: DepNodeFilter,
+}
+
+impl EdgeFilter {
+    pub fn new(test: &str) -> Result<EdgeFilter, Box<Error>> {
+        let parts: Vec<_> = test.split("->").collect();
+        if parts.len() != 2 {
+            Err(format!("expected a filter like `a&b -> c&d`, not `{}`", test).into())
+        } else {
+            Ok(EdgeFilter {
+                source: DepNodeFilter::new(parts[0]),
+                target: DepNodeFilter::new(parts[1]),
+            })
+        }
+    }
+}
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 3e43c8e2c93..84c84a7ed57 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -32,6 +32,10 @@ pub enum DepNode<D: Clone + Debug> {
     // Represents the HIR node with the given node-id
     Hir(D),
 
+    // Represents the metadata for a given HIR node, typically found
+    // in an extern crate.
+    MetaData(D),
+
     // Represents different phases in the compiler.
     CrateReader,
     CollectLanguageItems,
@@ -77,6 +81,7 @@ pub enum DepNode<D: Clone + Debug> {
     TransCrateItem(D),
     TransInlinedItem(D),
     TransWriteMetadata,
+    LinkBinary,
 
     // Nodes representing bits of computed IR in the tcx. Each shared
     // table in the tcx (or elsewhere) maps to one of these
@@ -174,7 +179,9 @@ impl<D: Clone + Debug> DepNode<D> {
             LateLintCheck => Some(LateLintCheck),
             TransCrate => Some(TransCrate),
             TransWriteMetadata => Some(TransWriteMetadata),
+            LinkBinary => Some(LinkBinary),
             Hir(ref d) => op(d).map(Hir),
+            MetaData(ref d) => op(d).map(MetaData),
             CollectItem(ref d) => op(d).map(CollectItem),
             CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
             CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
diff --git a/src/librustc/dep_graph/mod.rs b/src/librustc/dep_graph/mod.rs
index 49481dcb796..e65f6bbcf7a 100644
--- a/src/librustc/dep_graph/mod.rs
+++ b/src/librustc/dep_graph/mod.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+pub mod debug;
 mod dep_node;
 mod dep_tracking_map;
 mod edges;
@@ -22,3 +23,4 @@ pub use self::dep_node::DepNode;
 pub use self::graph::DepGraph;
 pub use self::query::DepGraphQuery;
 pub use self::visit::visit_all_items_in_krate;
+pub use self::raii::DepTask;
diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs
index acc6660da6e..93248edb197 100644
--- a/src/librustc/dep_graph/query.rs
+++ b/src/librustc/dep_graph/query.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 use rustc_data_structures::fnv::FnvHashMap;
-use rustc_data_structures::graph::{Graph, NodeIndex};
+use rustc_data_structures::graph::{Direction, INCOMING, Graph, NodeIndex, OUTGOING};
 use std::fmt::Debug;
 use std::hash::Hash;
 
@@ -63,11 +63,9 @@ impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> {
                   .collect()
     }
 
-    /// All nodes reachable from `node`. In other words, things that
-    /// will have to be recomputed if `node` changes.
-    pub fn transitive_dependents(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
+    fn reachable_nodes(&self, node: DepNode<D>, direction: Direction) -> Vec<DepNode<D>> {
         if let Some(&index) = self.indices.get(&node) {
-            self.graph.depth_traverse(index)
+            self.graph.depth_traverse(index, direction)
                       .map(|s| self.graph.node_data(s).clone())
                       .collect()
         } else {
@@ -75,8 +73,19 @@ impl<D: Clone + Debug + Hash + Eq> DepGraphQuery<D> {
         }
     }
 
+    /// All nodes reachable from `node`. In other words, things that
+    /// will have to be recomputed if `node` changes.
+    pub fn transitive_successors(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
+        self.reachable_nodes(node, OUTGOING)
+    }
+
+    /// All nodes that can reach `node`.
+    pub fn transitive_predecessors(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
+        self.reachable_nodes(node, INCOMING)
+    }
+
     /// Just the outgoing edges from `node`.
-    pub fn immediate_dependents(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
+    pub fn immediate_successors(&self, node: DepNode<D>) -> Vec<DepNode<D>> {
         if let Some(&index) = self.indices.get(&node) {
             self.graph.successor_nodes(index)
                       .map(|s| self.graph.node_data(s).clone())
diff --git a/src/librustc/dep_graph/thread.rs b/src/librustc/dep_graph/thread.rs
index b15e0e33b84..70d0a4e315c 100644
--- a/src/librustc/dep_graph/thread.rs
+++ b/src/librustc/dep_graph/thread.rs
@@ -28,6 +28,7 @@ use super::DepGraphQuery;
 use super::DepNode;
 use super::edges::DepGraphEdges;
 
+#[derive(Debug)]
 pub enum DepMessage {
     Read(DepNode<DefId>),
     Write(DepNode<DefId>),
@@ -117,6 +118,8 @@ impl DepGraphThreadData {
     /// the buffer is full, this may swap.)
     #[inline]
     pub fn enqueue(&self, message: DepMessage) {
+        debug!("enqueue: {:?} tasks_pushed={}", message, self.tasks_pushed.get());
+
         // Regardless of whether dep graph construction is enabled, we
         // still want to check that we always have a valid task on the
         // stack when a read/write/etc event occurs.
diff --git a/src/librustc/dep_graph/visit.rs b/src/librustc/dep_graph/visit.rs
index 321d109ca0e..9133b4d22ee 100644
--- a/src/librustc/dep_graph/visit.rs
+++ b/src/librustc/dep_graph/visit.rs
@@ -42,7 +42,8 @@ pub fn visit_all_items_in_krate<'a, 'tcx, V, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             let _task = self.tcx.dep_graph.in_task(task_id);
             debug!("Started task {:?}", task_id);
             self.tcx.dep_graph.read(DepNode::Hir(item_def_id));
-            self.visitor.visit_item(i)
+            self.visitor.visit_item(i);
+            debug!("Ended task {:?}", task_id);
         }
     }
 
diff --git a/src/librustc/hir/fold.rs b/src/librustc/hir/fold.rs
index 740d72f4c3e..a91d16f25a2 100644
--- a/src/librustc/hir/fold.rs
+++ b/src/librustc/hir/fold.rs
@@ -126,10 +126,6 @@ pub trait Folder : Sized {
         noop_fold_name(n, self)
     }
 
-    fn fold_ident(&mut self, i: Ident) -> Ident {
-        noop_fold_ident(i, self)
-    }
-
     fn fold_usize(&mut self, i: usize) -> usize {
         noop_fold_usize(i, self)
     }
@@ -407,10 +403,6 @@ pub fn noop_fold_name<T: Folder>(n: Name, _: &mut T) -> Name {
     n
 }
 
-pub fn noop_fold_ident<T: Folder>(i: Ident, _: &mut T) -> Ident {
-    i
-}
-
 pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize {
     i
 }
@@ -418,9 +410,9 @@ pub fn noop_fold_usize<T: Folder>(i: usize, _: &mut T) -> usize {
 pub fn noop_fold_path<T: Folder>(Path { global, segments, span }: Path, fld: &mut T) -> Path {
     Path {
         global: global,
-        segments: segments.move_map(|PathSegment { identifier, parameters }| {
+        segments: segments.move_map(|PathSegment { name, parameters }| {
             PathSegment {
-                identifier: fld.fold_ident(identifier),
+                name: fld.fold_name(name),
                 parameters: fld.fold_path_parameters(parameters),
             }
         }),
@@ -926,7 +918,7 @@ pub fn noop_fold_pat<T: Folder>(p: P<Pat>, folder: &mut T) -> P<Pat> {
                     PatKind::Ident(binding_mode,
                              Spanned {
                                  span: folder.new_span(pth1.span),
-                                 node: folder.fold_ident(pth1.node),
+                                 node: folder.fold_name(pth1.node),
                              },
                              sub.map(|x| folder.fold_pat(x)))
                 }
@@ -1014,14 +1006,14 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &
                        folder.fold_block(tr),
                        fl.map(|x| folder.fold_expr(x)))
             }
-            ExprWhile(cond, body, opt_ident) => {
+            ExprWhile(cond, body, opt_name) => {
                 ExprWhile(folder.fold_expr(cond),
                           folder.fold_block(body),
-                          opt_ident.map(|i| folder.fold_ident(i)))
+                          opt_name.map(|i| folder.fold_name(i)))
             }
-            ExprLoop(body, opt_ident) => {
+            ExprLoop(body, opt_name) => {
                 ExprLoop(folder.fold_block(body),
-                         opt_ident.map(|i| folder.fold_ident(i)))
+                         opt_name.map(|i| folder.fold_name(i)))
             }
             ExprMatch(expr, arms, source) => {
                 ExprMatch(folder.fold_expr(expr),
@@ -1061,11 +1053,11 @@ pub fn noop_fold_expr<T: Folder>(Expr { id, node, span, attrs }: Expr, folder: &
                 });
                 ExprPath(qself, folder.fold_path(path))
             }
-            ExprBreak(opt_ident) => ExprBreak(opt_ident.map(|label| {
-                respan(folder.new_span(label.span), folder.fold_ident(label.node))
+            ExprBreak(opt_name) => ExprBreak(opt_name.map(|label| {
+                respan(folder.new_span(label.span), folder.fold_name(label.node))
             })),
-            ExprAgain(opt_ident) => ExprAgain(opt_ident.map(|label| {
-                respan(folder.new_span(label.span), folder.fold_ident(label.node))
+            ExprAgain(opt_name) => ExprAgain(opt_name.map(|label| {
+                respan(folder.new_span(label.span), folder.fold_name(label.node))
             })),
             ExprRet(e) => ExprRet(e.map(|x| folder.fold_expr(x))),
             ExprInlineAsm(asm, outputs, inputs) => {
diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs
index b387ced4822..2e9e433b830 100644
--- a/src/librustc/hir/intravisit.rs
+++ b/src/librustc/hir/intravisit.rs
@@ -97,9 +97,6 @@ pub trait Visitor<'v> : Sized {
     fn visit_name(&mut self, _span: Span, _name: Name) {
         // Nothing to do.
     }
-    fn visit_ident(&mut self, span: Span, ident: Ident) {
-        walk_ident(self, span, ident);
-    }
     fn visit_mod(&mut self, m: &'v Mod, _s: Span, _n: NodeId) {
         walk_mod(self, m)
     }
@@ -211,16 +208,6 @@ pub fn walk_opt_name<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_name:
     }
 }
 
-pub fn walk_opt_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, opt_ident: Option<Ident>) {
-    for ident in opt_ident {
-        visitor.visit_ident(span, ident);
-    }
-}
-
-pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, span: Span, ident: Ident) {
-    visitor.visit_name(span, ident.name);
-}
-
 /// Walks the contents of a crate. See also `Crate::visit_all_items`.
 pub fn walk_crate<'v, V: Visitor<'v>>(visitor: &mut V, krate: &'v Crate) {
     visitor.visit_mod(&krate.module, krate.span, CRATE_NODE_ID);
@@ -439,7 +426,7 @@ pub fn walk_path_list_item<'v, V: Visitor<'v>>(visitor: &mut V,
 pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V,
                                              path_span: Span,
                                              segment: &'v PathSegment) {
-    visitor.visit_ident(path_span, segment.identifier);
+    visitor.visit_name(path_span, segment.name);
     visitor.visit_path_parameters(path_span, &segment.parameters);
 }
 
@@ -495,7 +482,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) {
             visitor.visit_pat(subpattern)
         }
         PatKind::Ident(_, ref pth1, ref optional_subpattern) => {
-            visitor.visit_ident(pth1.span, pth1.node);
+            visitor.visit_name(pth1.span, pth1.node);
             walk_list!(visitor, visit_pat, optional_subpattern);
         }
         PatKind::Lit(ref expression) => visitor.visit_expr(expression),
@@ -750,14 +737,14 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             visitor.visit_block(if_block);
             walk_list!(visitor, visit_expr, optional_else);
         }
-        ExprWhile(ref subexpression, ref block, opt_ident) => {
+        ExprWhile(ref subexpression, ref block, opt_name) => {
             visitor.visit_expr(subexpression);
             visitor.visit_block(block);
-            walk_opt_ident(visitor, expression.span, opt_ident)
+            walk_opt_name(visitor, expression.span, opt_name)
         }
-        ExprLoop(ref block, opt_ident) => {
+        ExprLoop(ref block, opt_name) => {
             visitor.visit_block(block);
-            walk_opt_ident(visitor, expression.span, opt_ident)
+            walk_opt_name(visitor, expression.span, opt_name)
         }
         ExprMatch(ref subexpression, ref arms, _) => {
             visitor.visit_expr(subexpression);
@@ -796,9 +783,9 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
             }
             visitor.visit_path(path, expression.id)
         }
-        ExprBreak(ref opt_sp_ident) | ExprAgain(ref opt_sp_ident) => {
-            for sp_ident in opt_sp_ident {
-                visitor.visit_ident(sp_ident.span, sp_ident.node);
+        ExprBreak(ref opt_sp_name) | ExprAgain(ref opt_sp_name) => {
+            for sp_name in opt_sp_name {
+                visitor.visit_name(sp_name.span, sp_name.node);
             }
         }
         ExprRet(ref optional_expression) => {
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 5b539439435..28506fd20fe 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -44,7 +44,8 @@ use hir;
 use hir::map::Definitions;
 use hir::map::definitions::DefPathData;
 use hir::def_id::{DefIndex, DefId};
-use hir::def::Def;
+use hir::def::{Def, PathResolution};
+use session::Session;
 
 use std::collections::BTreeMap;
 use std::iter;
@@ -53,7 +54,7 @@ use syntax::attr::{ThinAttributes, ThinAttributesExt};
 use syntax::ext::mtwt;
 use syntax::ptr::P;
 use syntax::codemap::{respan, Spanned, Span};
-use syntax::parse::token;
+use syntax::parse::token::{self, keywords};
 use syntax::std_inject;
 use syntax::visit::{self, Visitor};
 
@@ -72,6 +73,9 @@ pub trait Resolver {
     // Resolve a global hir path generated by the lowerer when expanding `for`, `if let`, etc.
     fn resolve_generated_global_path(&mut self, path: &hir::Path, is_value: bool) -> Def;
 
+    // Obtain the resolution for a node id
+    fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution>;
+
     // Record the resolution of a path or binding generated by the lowerer when expanding.
     fn record_resolution(&mut self, id: NodeId, def: Def);
 
@@ -85,14 +89,25 @@ impl Resolver for DummyResolver {
     fn resolve_generated_global_path(&mut self, _path: &hir::Path, _is_value: bool) -> Def {
         Def::Err
     }
+    fn get_resolution(&mut self, _id: NodeId) -> Option<PathResolution> {
+        None
+    }
     fn record_resolution(&mut self, _id: NodeId, _def: Def) {}
     fn definitions(&mut self) -> Option<&mut Definitions> {
         None
     }
 }
 
-pub fn lower_crate(krate: &Crate, id_assigner: &NodeIdAssigner, resolver: &mut Resolver)
+pub fn lower_crate(sess: &Session,
+                   krate: &Crate,
+                   id_assigner: &NodeIdAssigner,
+                   resolver: &mut Resolver)
                    -> hir::Crate {
+    // We're constructing the HIR here; we don't care what we will
+    // read, since we haven't even constructed the *input* to
+    // incr. comp. yet.
+    let _ignore = sess.dep_graph.in_ignore();
+
     LoweringContext {
         crate_root: if std_inject::no_core(krate) {
             None
@@ -150,8 +165,8 @@ impl<'a> LoweringContext<'a> {
         self.id_assigner.next_node_id()
     }
 
-    fn str_to_ident(&self, s: &'static str) -> hir::Ident {
-        hir::Ident::from_name(token::gensym(s))
+    fn str_to_ident(&self, s: &'static str) -> Name {
+        token::gensym(s)
     }
 
     fn with_parent_def<T, F>(&mut self, parent_id: NodeId, f: F) -> T
@@ -169,10 +184,11 @@ impl<'a> LoweringContext<'a> {
         result
     }
 
-    fn lower_ident(&mut self, ident: Ident) -> hir::Ident {
-        hir::Ident {
-            name: mtwt::resolve(ident),
-            unhygienic_name: ident.name,
+    fn lower_ident(&mut self, ident: Ident) -> Name {
+        if ident.name != keywords::Invalid.name() {
+            mtwt::resolve(ident)
+        } else {
+            ident.name
         }
     }
 
@@ -318,21 +334,17 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    // Path segments are usually unhygienic, hygienic path segments can occur only in
-    // identifier-like paths originating from `ExprPath`.
-    // Make life simpler for rustc_resolve by renaming only such segments.
-    fn lower_path_full(&mut self, p: &Path, maybe_hygienic: bool) -> hir::Path {
-        let maybe_hygienic = maybe_hygienic && !p.global && p.segments.len() == 1;
+    fn lower_path_full(&mut self, p: &Path, rename: bool) -> hir::Path {
         hir::Path {
             global: p.global,
             segments: p.segments
                        .iter()
                        .map(|&PathSegment { identifier, ref parameters }| {
                            hir::PathSegment {
-                               identifier: if maybe_hygienic {
+                               name: if rename {
                                    self.lower_ident(identifier)
                                } else {
-                                   hir::Ident::from_name(identifier.name)
+                                   identifier.name
                                },
                                parameters: self.lower_path_parameters(parameters),
                            }
@@ -849,9 +861,14 @@ impl<'a> LoweringContext<'a> {
                 PatKind::Wild => hir::PatKind::Wild,
                 PatKind::Ident(ref binding_mode, pth1, ref sub) => {
                     self.with_parent_def(p.id, |this| {
+                        let name = match this.resolver.get_resolution(p.id).map(|d| d.full_def()) {
+                            // Only pattern bindings are renamed
+                            None | Some(Def::Local(..)) => this.lower_ident(pth1.node),
+                            _ => pth1.node.name,
+                        };
                         hir::PatKind::Ident(this.lower_binding_mode(binding_mode),
-                                      respan(pth1.span, this.lower_ident(pth1.node)),
-                                      sub.as_ref().map(|x| this.lower_pat(x)))
+                                            respan(pth1.span, name),
+                                            sub.as_ref().map(|x| this.lower_pat(x)))
                     })
                 }
                 PatKind::Lit(ref e) => hir::PatKind::Lit(self.lower_expr(e)),
@@ -1215,7 +1232,16 @@ impl<'a> LoweringContext<'a> {
                             position: position,
                         }
                     });
-                    hir::ExprPath(hir_qself, self.lower_path_full(path, qself.is_none()))
+                    let rename = if path.segments.len() == 1 {
+                        // Only local variables are renamed
+                        match self.resolver.get_resolution(e.id).map(|d| d.full_def()) {
+                            Some(Def::Local(..)) | Some(Def::Upvar(..)) => true,
+                            _ => false,
+                        }
+                    } else {
+                        false
+                    };
+                    hir::ExprPath(hir_qself, self.lower_path_full(path, rename))
                 }
                 ExprKind::Break(opt_ident) => hir::ExprBreak(opt_ident.map(|sp_ident| {
                     respan(sp_ident.span, self.lower_ident(sp_ident.node))
@@ -1696,7 +1722,7 @@ impl<'a> LoweringContext<'a> {
         self.expr(span, hir::ExprCall(e, args), attrs)
     }
 
-    fn expr_ident(&mut self, span: Span, id: hir::Ident, attrs: ThinAttributes, binding: NodeId)
+    fn expr_ident(&mut self, span: Span, id: Name, attrs: ThinAttributes, binding: NodeId)
                   -> P<hir::Expr> {
         let expr_path = hir::ExprPath(None, self.path_ident(span, id));
         let expr = self.expr(span, expr_path, attrs);
@@ -1764,7 +1790,7 @@ impl<'a> LoweringContext<'a> {
     fn stmt_let(&mut self,
                 sp: Span,
                 mutbl: bool,
-                ident: hir::Ident,
+                ident: Name,
                 ex: P<hir::Expr>,
                 attrs: ThinAttributes)
                 -> (hir::Stmt, NodeId) {
@@ -1838,16 +1864,16 @@ impl<'a> LoweringContext<'a> {
         pat
     }
 
-    fn pat_ident(&mut self, span: Span, ident: hir::Ident) -> P<hir::Pat> {
-        self.pat_ident_binding_mode(span, ident, hir::BindByValue(hir::MutImmutable))
+    fn pat_ident(&mut self, span: Span, name: Name) -> P<hir::Pat> {
+        self.pat_ident_binding_mode(span, name, hir::BindByValue(hir::MutImmutable))
     }
 
-    fn pat_ident_binding_mode(&mut self, span: Span, ident: hir::Ident, bm: hir::BindingMode)
+    fn pat_ident_binding_mode(&mut self, span: Span, name: Name, bm: hir::BindingMode)
                               -> P<hir::Pat> {
         let pat_ident = hir::PatKind::Ident(bm,
                                             Spanned {
                                                 span: span,
-                                                node: ident,
+                                                node: name,
                                             },
                                             None);
 
@@ -1855,7 +1881,7 @@ impl<'a> LoweringContext<'a> {
 
         let parent_def = self.parent_def;
         let def = self.resolver.definitions().map(|defs| {
-            let def_path_data = DefPathData::Binding(ident.name);
+            let def_path_data = DefPathData::Binding(name);
             let def_index = defs.create_def_with_parent(parent_def, pat.id, def_path_data);
             Def::Local(DefId::local(def_index), pat.id)
         }).unwrap_or(Def::Err);
@@ -1876,36 +1902,36 @@ impl<'a> LoweringContext<'a> {
         })
     }
 
-    fn path_ident(&mut self, span: Span, id: hir::Ident) -> hir::Path {
+    fn path_ident(&mut self, span: Span, id: Name) -> hir::Path {
         self.path(span, vec![id])
     }
 
-    fn path(&mut self, span: Span, strs: Vec<hir::Ident>) -> hir::Path {
+    fn path(&mut self, span: Span, strs: Vec<Name>) -> hir::Path {
         self.path_all(span, false, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new())
     }
 
-    fn path_global(&mut self, span: Span, strs: Vec<hir::Ident>) -> hir::Path {
+    fn path_global(&mut self, span: Span, strs: Vec<Name>) -> hir::Path {
         self.path_all(span, true, strs, hir::HirVec::new(), hir::HirVec::new(), hir::HirVec::new())
     }
 
     fn path_all(&mut self,
                 sp: Span,
                 global: bool,
-                mut idents: Vec<hir::Ident>,
+                mut names: Vec<Name>,
                 lifetimes: hir::HirVec<hir::Lifetime>,
                 types: hir::HirVec<P<hir::Ty>>,
                 bindings: hir::HirVec<hir::TypeBinding>)
                 -> hir::Path {
-        let last_identifier = idents.pop().unwrap();
-        let mut segments: Vec<hir::PathSegment> = idents.into_iter().map(|ident| {
+        let last_identifier = names.pop().unwrap();
+        let mut segments: Vec<hir::PathSegment> = names.into_iter().map(|name| {
             hir::PathSegment {
-                identifier: ident,
+                name: name,
                 parameters: hir::PathParameters::none(),
            }
         }).collect();
 
         segments.push(hir::PathSegment {
-            identifier: last_identifier,
+            name: last_identifier,
             parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
                 lifetimes: lifetimes,
                 types: types,
@@ -1919,12 +1945,12 @@ impl<'a> LoweringContext<'a> {
         }
     }
 
-    fn std_path(&mut self, components: &[&str]) -> Vec<hir::Ident> {
+    fn std_path(&mut self, components: &[&str]) -> Vec<Name> {
         let mut v = Vec::new();
         if let Some(s) = self.crate_root {
-            v.push(hir::Ident::from_name(token::intern(s)));
+            v.push(token::intern(s));
         }
-        v.extend(components.iter().map(|s| hir::Ident::from_name(token::intern(s))));
+        v.extend(components.iter().map(|s| token::intern(s)));
         return v;
     }
 
diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs
index 640ef48493a..e783d84dc1b 100644
--- a/src/librustc/hir/map/def_collector.rs
+++ b/src/librustc/hir/map/def_collector.rs
@@ -396,8 +396,8 @@ impl<'ast> intravisit::Visitor<'ast> for DefCollector<'ast> {
     fn visit_pat(&mut self, pat: &'ast hir::Pat) {
         let parent_def = self.parent_def;
 
-        if let hir::PatKind::Ident(_, id, _) = pat.node {
-            let def = self.create_def(pat.id, DefPathData::Binding(id.node.name));
+        if let hir::PatKind::Ident(_, name, _) = pat.node {
+            let def = self.create_def(pat.id, DefPathData::Binding(name.node));
             self.parent_def = Some(def);
         }
 
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 358301ab404..457511cdbc3 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -82,8 +82,10 @@ impl DefPath {
         let mut data = vec![];
         let mut index = Some(start_index);
         loop {
+            debug!("DefPath::make: krate={:?} index={:?}", krate, index);
             let p = index.unwrap();
             let key = get_key(p);
+            debug!("DefPath::make: key={:?}", key);
             match key.disambiguated_data.data {
                 DefPathData::CrateRoot => {
                     assert!(key.parent.is_none());
@@ -178,6 +180,10 @@ impl Definitions {
         self.data[index.as_usize()].key.clone()
     }
 
+    pub fn def_index_for_def_key(&self, key: DefKey) -> Option<DefIndex> {
+        self.key_map.get(&key).cloned()
+    }
+
     /// Returns the path from the crate root to `index`. The root
     /// nodes are not included in the path (i.e., this will be an
     /// empty vector for the crate root). For an inlined item, this
@@ -208,37 +214,6 @@ impl Definitions {
         }
     }
 
-    pub fn retrace_path(&self, path: &DefPath) -> Option<DefIndex> {
-        debug!("retrace_path(path={:?})", path);
-
-        // we assume that we only want to retrace paths relative to
-        // the crate root
-        assert!(path.is_local());
-
-        let root_key = DefKey {
-            parent: None,
-            disambiguated_data: DisambiguatedDefPathData {
-                data: DefPathData::CrateRoot,
-                disambiguator: 0,
-            },
-        };
-        let root_id = self.key_map[&root_key];
-
-        debug!("retrace_path: root_id={:?}", root_id);
-
-        let mut id = root_id;
-        for data in &path.data {
-            let key = DefKey { parent: Some(id), disambiguated_data: data.clone() };
-            debug!("key = {:?}", key);
-            id = match self.key_map.get(&key) {
-                Some(&id) => id,
-                None => return None
-            };
-        }
-
-        Some(id)
-    }
-
     pub fn create_def_with_parent(&mut self,
                                   parent: Option<DefIndex>,
                                   node_id: ast::NodeId,
diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs
index f0eb580cfd5..2f310806a74 100644
--- a/src/librustc/hir/map/mod.rs
+++ b/src/librustc/hir/map/mod.rs
@@ -19,7 +19,7 @@ use dep_graph::{DepGraph, DepNode};
 
 use middle::cstore::InlinedItem;
 use middle::cstore::InlinedItem as II;
-use hir::def_id::{CRATE_DEF_INDEX, DefId};
+use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
 
 use syntax::abi::Abi;
 use syntax::ast::{self, Name, NodeId, DUMMY_NODE_ID, };
@@ -160,10 +160,10 @@ pub struct Forest {
 }
 
 impl Forest {
-    pub fn new(krate: Crate, dep_graph: DepGraph) -> Forest {
+    pub fn new(krate: Crate, dep_graph: &DepGraph) -> Forest {
         Forest {
             krate: krate,
-            dep_graph: dep_graph,
+            dep_graph: dep_graph.clone(),
             inlined_items: TypedArena::new()
         }
     }
@@ -285,9 +285,8 @@ impl<'ast> Map<'ast> {
         self.definitions.borrow().def_path(def_id.index)
     }
 
-    pub fn retrace_path(&self, path: &DefPath) -> Option<DefId> {
-        self.definitions.borrow().retrace_path(path)
-                                 .map(DefId::local)
+    pub fn def_index_for_def_key(&self, def_key: DefKey) -> Option<DefIndex> {
+        self.definitions.borrow().def_index_for_def_key(def_key)
     }
 
     pub fn local_def_id(&self, node: NodeId) -> DefId {
@@ -562,9 +561,7 @@ impl<'ast> Map<'ast> {
             NodeVariant(v) => v.node.name,
             NodeLifetime(lt) => lt.name,
             NodeTyParam(tp) => tp.name,
-            NodeLocal(&Pat { node: PatKind::Ident(_,l,_), .. }) => {
-                l.node.name
-            },
+            NodeLocal(&Pat { node: PatKind::Ident(_,l,_), .. }) => l.node,
             NodeStructCtor(_) => self.name(self.get_parent(id)),
             _ => bug!("no name for {}", self.node_to_string(id))
         }
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index eb38458a3ac..39a6ec9f3af 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -46,8 +46,6 @@ use syntax::ptr::P;
 
 use std::collections::BTreeMap;
 use std::fmt;
-use std::hash::{Hash, Hasher};
-use serialize::{Encodable, Decodable, Encoder, Decoder};
 
 /// HIR doesn't commit to a concrete storage type and have its own alias for a vector.
 /// It can be `Vec`, `P<[T]>` or potentially `Box<[T]>`, or some other container with similar
@@ -76,63 +74,6 @@ pub mod pat_util;
 pub mod print;
 pub mod svh;
 
-/// Identifier in HIR
-#[derive(Clone, Copy, Eq)]
-pub struct Ident {
-    /// Hygienic name (renamed), should be used by default
-    pub name: Name,
-    /// Unhygienic name (original, not renamed), needed in few places in name resolution
-    pub unhygienic_name: Name,
-}
-
-impl Ident {
-    /// Creates a HIR identifier with both `name` and `unhygienic_name` initialized with
-    /// the argument. Hygiene properties of the created identifier depend entirely on this
-    /// argument. If the argument is a plain interned string `intern("iter")`, then the result
-    /// is unhygienic and can interfere with other entities named "iter". If the argument is
-    /// a "fresh" name created with `gensym("iter")`, then the result is hygienic and can't
-    /// interfere with other entities having the same string as a name.
-    pub fn from_name(name: Name) -> Ident {
-        Ident { name: name, unhygienic_name: name }
-    }
-}
-
-impl PartialEq for Ident {
-    fn eq(&self, other: &Ident) -> bool {
-        self.name == other.name
-    }
-}
-
-impl Hash for Ident {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        self.name.hash(state)
-    }
-}
-
-impl fmt::Debug for Ident {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&self.name, f)
-    }
-}
-
-impl fmt::Display for Ident {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Display::fmt(&self.name, f)
-    }
-}
-
-impl Encodable for Ident {
-    fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
-        self.name.encode(s)
-    }
-}
-
-impl Decodable for Ident {
-    fn decode<D: Decoder>(d: &mut D) -> Result<Ident, D::Error> {
-        Ok(Ident::from_name(Name::decode(d)?))
-    }
-}
-
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Copy)]
 pub struct Lifetime {
     pub id: NodeId,
@@ -184,12 +125,12 @@ impl fmt::Display for Path {
 impl Path {
     /// Convert a span and an identifier to the corresponding
     /// 1-segment path.
-    pub fn from_ident(s: Span, ident: Ident) -> Path {
+    pub fn from_name(s: Span, name: Name) -> Path {
         Path {
             span: s,
             global: false,
             segments: hir_vec![PathSegment {
-                identifier: ident,
+                name: name,
                 parameters: PathParameters::none()
             }],
         }
@@ -201,15 +142,7 @@ impl Path {
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
 pub struct PathSegment {
     /// The identifier portion of this path segment.
-    ///
-    /// Hygiene properties of this identifier are worth noting.
-    /// Most path segments are not hygienic and they are not renamed during
-    /// lowering from AST to HIR (see comments to `fn lower_path`). However segments from
-    /// unqualified paths with one segment originating from `ExprPath` (local-variable-like paths)
-    /// can be hygienic, so they are renamed. You should not normally care about this peculiarity
-    /// and just use `identifier.name` unless you modify identifier resolution code
-    /// (`fn resolve_identifier` and other functions called by it in `rustc_resolve`).
-    pub identifier: Ident,
+    pub name: Name,
 
     /// Type/lifetime parameters attached to this path. They come in
     /// two flavors: `Path<A,B,C>` and `Path(A,B) -> C`. Note that
@@ -600,7 +533,7 @@ pub enum PatKind {
     /// which it is. The resolver determines this, and
     /// records this pattern's `NodeId` in an auxiliary
     /// set (of "PatIdents that refer to unit patterns or constants").
-    Ident(BindingMode, Spanned<Ident>, Option<P<Pat>>),
+    Ident(BindingMode, Spanned<Name>, Option<P<Pat>>),
 
     /// A struct or struct variant pattern, e.g. `Variant {x, y, ..}`.
     /// The `bool` is `true` in the presence of a `..`.
@@ -940,11 +873,11 @@ pub enum Expr_ {
     /// A while loop, with an optional label
     ///
     /// `'label: while expr { block }`
-    ExprWhile(P<Expr>, P<Block>, Option<Ident>),
+    ExprWhile(P<Expr>, P<Block>, Option<Name>),
     /// Conditionless loop (can be exited with break, continue, or return)
     ///
     /// `'label: loop { block }`
-    ExprLoop(P<Block>, Option<Ident>),
+    ExprLoop(P<Block>, Option<Name>),
     /// A `match` block, with a source that indicates whether or not it is
     /// the result of a desugaring, and if so, which kind.
     ExprMatch(P<Expr>, HirVec<Arm>, MatchSource),
@@ -980,9 +913,9 @@ pub enum Expr_ {
     /// A referencing operation (`&a` or `&mut a`)
     ExprAddrOf(Mutability, P<Expr>),
     /// A `break`, with an optional label to break
-    ExprBreak(Option<Spanned<Ident>>),
+    ExprBreak(Option<Spanned<Name>>),
     /// A `continue`, with an optional label
-    ExprAgain(Option<Spanned<Ident>>),
+    ExprAgain(Option<Spanned<Name>>),
     /// A `return`, with an optional value to be returned
     ExprRet(Option<P<Expr>>),
 
@@ -1209,8 +1142,8 @@ pub type ExplicitSelf = Spanned<SelfKind>;
 
 impl Arg {
     pub fn to_self(&self) -> Option<ExplicitSelf> {
-        if let PatKind::Ident(BindByValue(mutbl), ident, _) = self.pat.node {
-            if ident.node.unhygienic_name == keywords::SelfValue.name() {
+        if let PatKind::Ident(BindByValue(mutbl), name, _) = self.pat.node {
+            if name.node.unhygienize() == keywords::SelfValue.name() {
                 return match self.ty.node {
                     TyInfer => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
                     TyRptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyInfer => {
@@ -1225,8 +1158,8 @@ impl Arg {
     }
 
     pub fn is_self(&self) -> bool {
-        if let PatKind::Ident(_, ident, _) = self.pat.node {
-            ident.node.unhygienic_name == keywords::SelfValue.name()
+        if let PatKind::Ident(_, name, _) = self.pat.node {
+            name.node.unhygienize() == keywords::SelfValue.name()
         } else {
             false
         }
diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs
index 6bbd6a207ee..15f2310607f 100644
--- a/src/librustc/hir/pat_util.rs
+++ b/src/librustc/hir/pat_util.rs
@@ -117,19 +117,6 @@ pub fn pat_bindings<I>(dm: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) where
     pat.walk(|p| {
         match p.node {
           PatKind::Ident(binding_mode, ref pth, _) if pat_is_binding(&dm.borrow(), p) => {
-            it(binding_mode, p.id, p.span, &respan(pth.span, pth.node.name));
-          }
-          _ => {}
-        }
-        true
-    });
-}
-pub fn pat_bindings_ident<I>(dm: &RefCell<DefMap>, pat: &hir::Pat, mut it: I) where
-    I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned<hir::Ident>),
-{
-    pat.walk(|p| {
-        match p.node {
-          PatKind::Ident(binding_mode, ref pth, _) if pat_is_binding(&dm.borrow(), p) => {
             it(binding_mode, p.id, p.span, &respan(pth.span, pth.node));
           }
           _ => {}
@@ -201,7 +188,7 @@ pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool {
 pub fn simple_name<'a>(pat: &'a hir::Pat) -> Option<ast::Name> {
     match pat.node {
         PatKind::Ident(hir::BindByValue(_), ref path1, None) => {
-            Some(path1.node.name)
+            Some(path1.node)
         }
         _ => {
             None
@@ -210,8 +197,7 @@ pub fn simple_name<'a>(pat: &'a hir::Pat) -> Option<ast::Name> {
 }
 
 pub fn def_to_path<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: DefId) -> hir::Path {
-    let name = tcx.item_name(id);
-    hir::Path::from_ident(DUMMY_SP, hir::Ident::from_name(name))
+    hir::Path::from_name(DUMMY_SP, tcx.item_name(id))
 }
 
 /// Return variants that are necessary to exist for the pattern to match.
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index c3617cb768d..4455c7da3ba 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -1351,9 +1351,9 @@ impl<'a> State<'a> {
             hir::ExprIf(ref test, ref blk, ref elseopt) => {
                 self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?;
             }
-            hir::ExprWhile(ref test, ref blk, opt_ident) => {
-                if let Some(ident) = opt_ident {
-                    self.print_name(ident.name)?;
+            hir::ExprWhile(ref test, ref blk, opt_name) => {
+                if let Some(name) = opt_name {
+                    self.print_name(name)?;
                     self.word_space(":")?;
                 }
                 self.head("while")?;
@@ -1361,9 +1361,9 @@ impl<'a> State<'a> {
                 space(&mut self.s)?;
                 self.print_block(&blk)?;
             }
-            hir::ExprLoop(ref blk, opt_ident) => {
-                if let Some(ident) = opt_ident {
-                    self.print_name(ident.name)?;
+            hir::ExprLoop(ref blk, opt_name) => {
+                if let Some(name) = opt_name {
+                    self.print_name(name)?;
                     self.word_space(":")?;
                 }
                 self.head("loop")?;
@@ -1455,19 +1455,19 @@ impl<'a> State<'a> {
             hir::ExprPath(Some(ref qself), ref path) => {
                 self.print_qpath(path, qself, true)?
             }
-            hir::ExprBreak(opt_ident) => {
+            hir::ExprBreak(opt_name) => {
                 word(&mut self.s, "break")?;
                 space(&mut self.s)?;
-                if let Some(ident) = opt_ident {
-                    self.print_name(ident.node.name)?;
+                if let Some(name) = opt_name {
+                    self.print_name(name.node)?;
                     space(&mut self.s)?;
                 }
             }
-            hir::ExprAgain(opt_ident) => {
+            hir::ExprAgain(opt_name) => {
                 word(&mut self.s, "continue")?;
                 space(&mut self.s)?;
-                if let Some(ident) = opt_ident {
-                    self.print_name(ident.node.name)?;
+                if let Some(name) = opt_name {
+                    self.print_name(name.node)?;
                     space(&mut self.s)?
                 }
             }
@@ -1615,7 +1615,7 @@ impl<'a> State<'a> {
                 word(&mut self.s, "::")?
             }
 
-            self.print_name(segment.identifier.name)?;
+            self.print_name(segment.name)?;
 
             self.print_path_parameters(&segment.parameters, colons_before_params)?;
         }
@@ -1639,7 +1639,7 @@ impl<'a> State<'a> {
         word(&mut self.s, ">")?;
         word(&mut self.s, "::")?;
         let item_segment = path.segments.last().unwrap();
-        self.print_name(item_segment.identifier.name)?;
+        self.print_name(item_segment.name)?;
         self.print_path_parameters(&item_segment.parameters, colons_before_params)
     }
 
@@ -1727,7 +1727,7 @@ impl<'a> State<'a> {
                         self.word_nbsp("mut")?;
                     }
                 }
-                self.print_name(path1.node.name)?;
+                self.print_name(path1.node)?;
                 match *sub {
                     Some(ref p) => {
                         word(&mut self.s, "@")?;
@@ -2095,7 +2095,7 @@ impl<'a> State<'a> {
             hir::ViewPathSimple(name, ref path) => {
                 self.print_path(path, false, 0)?;
 
-                if path.segments.last().unwrap().identifier.name != name {
+                if path.segments.last().unwrap().name != name {
                     space(&mut self.s)?;
                     self.word_space("as")?;
                     self.print_name(name)?;
@@ -2151,8 +2151,8 @@ impl<'a> State<'a> {
                 if let Some(eself) = input.to_self() {
                     self.print_explicit_self(&eself)?;
                 } else {
-                    let invalid = if let PatKind::Ident(_, ident, _) = input.pat.node {
-                        ident.node.name == keywords::Invalid.name()
+                    let invalid = if let PatKind::Ident(_, name, _) = input.pat.node {
+                        name.node == keywords::Invalid.name()
                     } else {
                         false
                     };
diff --git a/src/librustc/hir/svh.rs b/src/librustc/hir/svh.rs
index 1536f884b09..d4e797c9f2d 100644
--- a/src/librustc/hir/svh.rs
+++ b/src/librustc/hir/svh.rs
@@ -10,78 +10,44 @@
 
 //! Calculation and management of a Strict Version Hash for crates
 //!
-//! # Today's ABI problem
-//!
-//! In today's implementation of rustc, it is incredibly difficult to achieve
-//! forward binary compatibility without resorting to C-like interfaces. Within
-//! rust code itself, abi details such as symbol names suffer from a variety of
-//! unrelated factors to code changing such as the "def id drift" problem. This
-//! ends up yielding confusing error messages about metadata mismatches and
-//! such.
-//!
-//! The core of this problem is when an upstream dependency changes and
-//! downstream dependents are not recompiled. This causes compile errors because
-//! the upstream crate's metadata has changed but the downstream crates are
-//! still referencing the older crate's metadata.
-//!
-//! This problem exists for many reasons, the primary of which is that rust does
-//! not currently support forwards ABI compatibility (in place upgrades of a
-//! crate).
-//!
-//! # SVH and how it alleviates the problem
-//!
-//! With all of this knowledge on hand, this module contains the implementation
-//! of a notion of a "Strict Version Hash" for a crate. This is essentially a
-//! hash of all contents of a crate which can somehow be exposed to downstream
-//! crates.
-//!
-//! This hash is currently calculated by just hashing the AST, but this is
-//! obviously wrong (doc changes should not result in an incompatible ABI).
-//! Implementation-wise, this is required at this moment in time.
-//!
-//! By encoding this strict version hash into all crate's metadata, stale crates
-//! can be detected immediately and error'd about by rustc itself.
-//!
-//! # Relevant links
-//!
-//! Original issue: https://github.com/rust-lang/rust/issues/10207
+//! The SVH is used for incremental compilation to track when HIR
+//! nodes have changed between compilations, and also to detect
+//! mismatches where we have two versions of the same crate that were
+//! compiled from distinct sources.
 
 use std::fmt;
+use std::hash::{Hash, Hasher};
 
-#[derive(Clone, Eq, Hash, PartialEq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub struct Svh {
-    hash: String,
+    hash: u64,
 }
 
 impl Svh {
     /// Create a new `Svh` given the hash. If you actually want to
     /// compute the SVH from some HIR, you want the `calculate_svh`
-    /// function found in `librustc_trans`.
-    pub fn new(hash: String) -> Svh {
-        assert!(hash.len() == 16);
+    /// function found in `librustc_incremental`.
+    pub fn new(hash: u64) -> Svh {
         Svh { hash: hash }
     }
 
-    pub fn from_hash(hash: u64) -> Svh {
-        return Svh::new((0..64).step_by(4).map(|i| hex(hash >> i)).collect());
+    pub fn as_u64(&self) -> u64 {
+        self.hash
+    }
 
-        fn hex(b: u64) -> char {
-            let b = (b & 0xf) as u8;
-            let b = match b {
-                0 ... 9 => '0' as u8 + b,
-                _ => 'a' as u8 + b - 10,
-            };
-            b as char
-        }
+    pub fn to_string(&self) -> String {
+        format!("{:016x}", self.hash)
     }
+}
 
-    pub fn as_str<'a>(&'a self) -> &'a str {
-        &self.hash
+impl Hash for Svh {
+    fn hash<H>(&self, state: &mut H) where H: Hasher {
+        self.hash.to_le().hash(state);
     }
 }
 
 impl fmt::Display for Svh {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        f.pad(self.as_str())
+        f.pad(&self.to_string())
     }
 }
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 950b7f68ed8..8afee54c4bc 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -90,7 +90,7 @@ use std::cell::{Cell, RefCell};
 use std::char::from_u32;
 use std::fmt;
 use syntax::ast;
-use syntax::errors::DiagnosticBuilder;
+use syntax::errors::{DiagnosticBuilder, check_old_skool};
 use syntax::codemap::{self, Pos, Span};
 use syntax::parse::token;
 use syntax::ptr::P;
@@ -481,7 +481,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                        "{}",
                                        trace.origin);
 
-        if !is_simple_error {
+        if !is_simple_error || check_old_skool() {
             err.note_expected_found(&"type", &expected, &found);
         }
 
@@ -1514,7 +1514,7 @@ impl<'a, 'gcx, 'tcx> Rebuilder<'a, 'gcx, 'tcx> {
             }
         };
         let new_seg = hir::PathSegment {
-            identifier: last_seg.identifier,
+            name: last_seg.name,
             parameters: new_parameters
         };
         let mut new_segs = Vec::new();
diff --git a/src/librustc/infer/region_inference/mod.rs b/src/librustc/infer/region_inference/mod.rs
index 9d2d52015e3..5312d030525 100644
--- a/src/librustc/infer/region_inference/mod.rs
+++ b/src/librustc/infer/region_inference/mod.rs
@@ -20,7 +20,7 @@ pub use self::VarValue::*;
 use super::{RegionVariableOrigin, SubregionOrigin, MiscVariable};
 use super::unify_key;
 
-use rustc_data_structures::graph::{self, Direction, NodeIndex};
+use rustc_data_structures::graph::{self, Direction, NodeIndex, OUTGOING};
 use rustc_data_structures::unify::{self, UnificationTable};
 use middle::free_region::FreeRegionMap;
 use ty::{self, Ty, TyCtxt};
@@ -872,7 +872,7 @@ impl<'a, 'gcx, 'tcx> RegionVarBindings<'a, 'gcx, 'tcx> {
         let seeds: Vec<_> = givens.iter().cloned().collect();
         for (fr, vid) in seeds {
             let seed_index = NodeIndex(vid.index as usize);
-            for succ_index in graph.depth_traverse(seed_index) {
+            for succ_index in graph.depth_traverse(seed_index, OUTGOING) {
                 let succ_index = succ_index.0 as u32;
                 if succ_index < self.num_vars() {
                     let succ_vid = RegionVid { index: succ_index };
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index ed63783366b..e1fb701e641 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -37,7 +37,6 @@
 #![feature(rustc_private)]
 #![feature(slice_patterns)]
 #![feature(staged_api)]
-#![feature(step_by)]
 #![feature(question_mark)]
 #![cfg_attr(test, feature(test))]
 
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 6dd98425df3..d7971cd2cf0 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -168,6 +168,13 @@ declare_lint! {
 }
 
 declare_lint! {
+    pub HR_LIFETIME_IN_ASSOC_TYPE,
+    Warn,
+    "binding for associated type references higher-ranked lifetime \
+     that does not appear in the trait input types"
+}
+
+declare_lint! {
     pub OVERLAPPING_INHERENT_IMPLS,
     Warn,
     "two overlapping inherent impls define an item with the same name were erroneously allowed"
@@ -234,7 +241,8 @@ impl LintPass for HardwiredLints {
             RENAMED_AND_REMOVED_LINTS,
             SUPER_OR_SELF_IN_GLOBAL_PATH,
             UNSIZED_IN_TUPLE,
-            OBJECT_UNSAFE_FRAGMENT
+            OBJECT_UNSAFE_FRAGMENT,
+            HR_LIFETIME_IN_ASSOC_TYPE
         )
     }
 }
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index c0af457ed23..e5a8c1d1b4e 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -22,19 +22,19 @@
 // are *mostly* used as a part of that interface, but these should
 // probably get a better home if someone can find one.
 
-use hir::svh::Svh;
-use hir::map as hir_map;
 use hir::def::{self, Def};
+use hir::def_id::{DefId, DefIndex};
+use hir::map as hir_map;
+use hir::map::definitions::DefKey;
+use hir::svh::Svh;
 use middle::lang_items;
 use ty::{self, Ty, TyCtxt, VariantKind};
-use hir::def_id::{DefId, DefIndex};
 use mir::repr::Mir;
 use mir::mir_map::MirMap;
 use session::Session;
 use session::config::PanicStrategy;
 use session::search_paths::PathKind;
 use util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
-use std::any::Any;
 use std::cell::RefCell;
 use std::rc::Rc;
 use std::path::PathBuf;
@@ -150,12 +150,7 @@ pub struct ExternCrate {
 
 /// A store of Rust crates, through with their metadata
 /// can be accessed.
-///
-/// The `: Any` bound is a temporary measure that allows access
-/// to the backing `rustc_metadata::cstore::CStore` object. It
-/// will be removed in the near future - if you need to access
-/// internal APIs, please tell us.
-pub trait CrateStore<'tcx> : Any {
+pub trait CrateStore<'tcx> {
     // item info
     fn stability(&self, def: DefId) -> Option<attr::Stability>;
     fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>;
@@ -240,6 +235,10 @@ pub trait CrateStore<'tcx> : Any {
     fn reachable_ids(&self, cnum: ast::CrateNum) -> Vec<DefId>;
 
     // resolve
+    fn def_index_for_def_key(&self,
+                             cnum: ast::CrateNum,
+                             def: DefKey)
+                             -> Option<DefIndex>;
     fn def_key(&self, def: DefId) -> hir_map::DefKey;
     fn relative_def_path(&self, def: DefId) -> hir_map::DefPath;
     fn variant_kind(&self, def_id: DefId) -> Option<VariantKind>;
@@ -367,6 +366,12 @@ impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
                                   -> Vec<Rc<ty::Method<'tcx>>> { bug!("provided_trait_methods") }
     fn trait_item_def_ids(&self, def: DefId)
                           -> Vec<ty::ImplOrTraitItemId> { bug!("trait_item_def_ids") }
+    fn def_index_for_def_key(&self,
+                             cnum: ast::CrateNum,
+                             def: DefKey)
+                             -> Option<DefIndex> {
+        None
+    }
 
     // impl info
     fn impl_items(&self, impl_def_id: DefId) -> Vec<ty::ImplOrTraitItemId>
diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs
index fe22cfdb43f..0b398fd0d47 100644
--- a/src/librustc/middle/dependency_format.rs
+++ b/src/librustc/middle/dependency_format.rs
@@ -115,9 +115,10 @@ fn calculate_type(sess: &session::Session,
         // got long ago), so don't bother with anything.
         config::CrateTypeRlib => return Vec::new(),
 
-        // Staticlibs must have all static dependencies. If any fail to be
-        // found, we generate some nice pretty errors.
-        config::CrateTypeStaticlib => {
+        // Staticlibs and cdylibs must have all static dependencies. If any fail
+        // to be found, we generate some nice pretty errors.
+        config::CrateTypeStaticlib |
+        config::CrateTypeCdylib => {
             match attempt_static(sess) {
                 Some(v) => return v,
                 None => {}
diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs
index 473fd7d9be6..be8caeb436a 100644
--- a/src/librustc/middle/liveness.rs
+++ b/src/librustc/middle/liveness.rs
@@ -1050,7 +1050,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprBreak(opt_label) => {
               // Find which label this break jumps to
-              let sc = self.find_loop_scope(opt_label.map(|l| l.node.name), expr.id, expr.span);
+              let sc = self.find_loop_scope(opt_label.map(|l| l.node), expr.id, expr.span);
 
               // Now that we know the label we're going to,
               // look it up in the break loop nodes table
@@ -1063,7 +1063,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
 
           hir::ExprAgain(opt_label) => {
               // Find which label this expr continues to
-              let sc = self.find_loop_scope(opt_label.map(|l| l.node.name), expr.id, expr.span);
+              let sc = self.find_loop_scope(opt_label.map(|l| l.node), expr.id, expr.span);
 
               // Now that we know the label we're going to,
               // look it up in the continue loop nodes table
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index bca5af69edf..55d75ace081 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -145,7 +145,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
     // Creates a new reachability computation context.
     fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> {
         let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| {
-            *ty != config::CrateTypeExecutable
+            *ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib
         });
         ReachableContext {
             tcx: tcx,
diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs
index 932f2882b49..2200d72c883 100644
--- a/src/librustc/middle/resolve_lifetime.rs
+++ b/src/librustc/middle/resolve_lifetime.rs
@@ -433,7 +433,7 @@ fn extract_labels<'v, 'a>(ctxt: &mut LifetimeContext<'a>, b: &'v hir::Block) {
     fn expression_label(ex: &hir::Expr) -> Option<ast::Name> {
         match ex.node {
             hir::ExprWhile(_, _, Some(label)) |
-            hir::ExprLoop(_, Some(label)) => Some(label.unhygienic_name),
+            hir::ExprLoop(_, Some(label)) => Some(label.unhygienize()),
             _ => None,
         }
     }
diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs
index b7dfc867204..32588768491 100644
--- a/src/librustc/middle/weak_lang_items.rs
+++ b/src/librustc/middle/weak_lang_items.rs
@@ -70,6 +70,7 @@ fn verify(sess: &Session, items: &lang_items::LanguageItems) {
     let needs_check = sess.crate_types.borrow().iter().any(|kind| {
         match *kind {
             config::CrateTypeDylib |
+            config::CrateTypeCdylib |
             config::CrateTypeExecutable |
             config::CrateTypeStaticlib => true,
             config::CrateTypeRlib => false,
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index 7d1d5dba398..da5555dbd64 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -300,6 +300,7 @@ pub enum CrateType {
     CrateTypeDylib,
     CrateTypeRlib,
     CrateTypeStaticlib,
+    CrateTypeCdylib,
 }
 
 #[derive(Clone)]
@@ -1326,6 +1327,7 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
                 "rlib"      => CrateTypeRlib,
                 "staticlib" => CrateTypeStaticlib,
                 "dylib"     => CrateTypeDylib,
+                "cdylib"    => CrateTypeCdylib,
                 "bin"       => CrateTypeExecutable,
                 _ => {
                     return Err(format!("unknown crate type: `{}`",
@@ -1413,13 +1415,15 @@ impl fmt::Display for CrateType {
             CrateTypeExecutable => "bin".fmt(f),
             CrateTypeDylib => "dylib".fmt(f),
             CrateTypeRlib => "rlib".fmt(f),
-            CrateTypeStaticlib => "staticlib".fmt(f)
+            CrateTypeStaticlib => "staticlib".fmt(f),
+            CrateTypeCdylib => "cdylib".fmt(f),
         }
     }
 }
 
 #[cfg(test)]
 mod tests {
+    use dep_graph::DepGraph;
     use middle::cstore::DummyCrateStore;
     use session::config::{build_configuration, build_session_options};
     use session::build_session;
@@ -1439,6 +1443,7 @@ mod tests {
     // When the user supplies --test we should implicitly supply --cfg test
     #[test]
     fn test_switch_implies_cfg_test() {
+        let dep_graph = DepGraph::new(false);
         let matches =
             &match getopts(&["--test".to_string()], &optgroups()) {
               Ok(m) => m,
@@ -1446,7 +1451,7 @@ mod tests {
             };
         let registry = diagnostics::registry::Registry::new(&[]);
         let sessopts = build_session_options(matches);
-        let sess = build_session(sessopts, None, registry, Rc::new(DummyCrateStore));
+        let sess = build_session(sessopts, &dep_graph, None, registry, Rc::new(DummyCrateStore));
         let cfg = build_configuration(&sess);
         assert!((attr::contains_name(&cfg[..], "test")));
     }
@@ -1455,6 +1460,7 @@ mod tests {
     // another --cfg test
     #[test]
     fn test_switch_implies_cfg_test_unless_cfg_test() {
+        let dep_graph = DepGraph::new(false);
         let matches =
             &match getopts(&["--test".to_string(), "--cfg=test".to_string()],
                            &optgroups()) {
@@ -1465,7 +1471,7 @@ mod tests {
             };
         let registry = diagnostics::registry::Registry::new(&[]);
         let sessopts = build_session_options(matches);
-        let sess = build_session(sessopts, None, registry,
+        let sess = build_session(sessopts, &dep_graph, None, registry,
                                  Rc::new(DummyCrateStore));
         let cfg = build_configuration(&sess);
         let mut test_items = cfg.iter().filter(|m| m.name() == "test");
@@ -1475,13 +1481,14 @@ mod tests {
 
     #[test]
     fn test_can_print_warnings() {
+        let dep_graph = DepGraph::new(false);
         {
             let matches = getopts(&[
                 "-Awarnings".to_string()
             ], &optgroups()).unwrap();
             let registry = diagnostics::registry::Registry::new(&[]);
             let sessopts = build_session_options(&matches);
-            let sess = build_session(sessopts, None, registry,
+            let sess = build_session(sessopts, &dep_graph, None, registry,
                                      Rc::new(DummyCrateStore));
             assert!(!sess.diagnostic().can_emit_warnings);
         }
@@ -1493,7 +1500,7 @@ mod tests {
             ], &optgroups()).unwrap();
             let registry = diagnostics::registry::Registry::new(&[]);
             let sessopts = build_session_options(&matches);
-            let sess = build_session(sessopts, None, registry,
+            let sess = build_session(sessopts, &dep_graph, None, registry,
                                      Rc::new(DummyCrateStore));
             assert!(sess.diagnostic().can_emit_warnings);
         }
@@ -1504,7 +1511,7 @@ mod tests {
             ], &optgroups()).unwrap();
             let registry = diagnostics::registry::Registry::new(&[]);
             let sessopts = build_session_options(&matches);
-            let sess = build_session(sessopts, None, registry,
+            let sess = build_session(sessopts, &dep_graph, None, registry,
                                      Rc::new(DummyCrateStore));
             assert!(sess.diagnostic().can_emit_warnings);
         }
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index 1bea01c4849..907241d1746 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use dep_graph::DepGraph;
 use lint;
 use middle::cstore::CrateStore;
 use middle::dependency_format;
@@ -49,6 +50,7 @@ pub mod search_paths;
 // Represents the data associated with a compilation
 // session for a single crate.
 pub struct Session {
+    pub dep_graph: DepGraph,
     pub target: config::Config,
     pub host: Target,
     pub opts: config::Options,
@@ -408,18 +410,21 @@ fn split_msg_into_multilines(msg: &str) -> Option<String> {
 }
 
 pub fn build_session(sopts: config::Options,
+                     dep_graph: &DepGraph,
                      local_crate_source_file: Option<PathBuf>,
                      registry: diagnostics::registry::Registry,
                      cstore: Rc<for<'a> CrateStore<'a>>)
                      -> Session {
     build_session_with_codemap(sopts,
-                              local_crate_source_file,
-                              registry,
-                              cstore,
-                              Rc::new(codemap::CodeMap::new()))
+                               dep_graph,
+                               local_crate_source_file,
+                               registry,
+                               cstore,
+                               Rc::new(codemap::CodeMap::new()))
 }
 
 pub fn build_session_with_codemap(sopts: config::Options,
+                                  dep_graph: &DepGraph,
                                   local_crate_source_file: Option<PathBuf>,
                                   registry: diagnostics::registry::Registry,
                                   cstore: Rc<for<'a> CrateStore<'a>>,
@@ -450,10 +455,16 @@ pub fn build_session_with_codemap(sopts: config::Options,
                                       treat_err_as_bug,
                                       emitter);
 
-    build_session_(sopts, local_crate_source_file, diagnostic_handler, codemap, cstore)
+    build_session_(sopts,
+                   dep_graph,
+                   local_crate_source_file,
+                   diagnostic_handler,
+                   codemap,
+                   cstore)
 }
 
 pub fn build_session_(sopts: config::Options,
+                      dep_graph: &DepGraph,
                       local_crate_source_file: Option<PathBuf>,
                       span_diagnostic: errors::Handler,
                       codemap: Rc<codemap::CodeMap>,
@@ -482,6 +493,7 @@ pub fn build_session_(sopts: config::Options,
     );
 
     let sess = Session {
+        dep_graph: dep_graph.clone(),
         target: target_cfg,
         host: host,
         opts: sopts,
@@ -616,9 +628,9 @@ pub fn span_bug_fmt<S: Into<MultiSpan>>(file: &'static str,
 }
 
 fn opt_span_bug_fmt<S: Into<MultiSpan>>(file: &'static str,
-                                          line: u32,
-                                          span: Option<S>,
-                                          args: fmt::Arguments) -> ! {
+                                        line: u32,
+                                        span: Option<S>,
+                                        args: fmt::Arguments) -> ! {
     tls::with_opt(move |tcx| {
         let msg = format!("{}:{}: {}", file, line, args);
         match (tcx, span) {
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 847aade630f..9a69958fea0 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -30,7 +30,7 @@ use infer::{InferCtxt};
 use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable};
 use ty::fast_reject;
 use ty::fold::TypeFolder;
-use ty::subst::{self, Subst};
+use ty::subst::{self, Subst, TypeSpace};
 use util::nodemap::{FnvHashMap, FnvHashSet};
 
 use std::cmp;
@@ -135,8 +135,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         let ity = tcx.lookup_item_type(did);
         let (tps, rps, _) =
-            (ity.generics.types.get_slice(subst::TypeSpace),
-             ity.generics.regions.get_slice(subst::TypeSpace),
+            (ity.generics.types.get_slice(TypeSpace),
+             ity.generics.regions.get_slice(TypeSpace),
              ity.ty);
 
         let rps = self.region_vars_for_defs(obligation.cause.span, rps);
@@ -144,56 +144,102 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             subst::VecPerParamSpace::empty(),
             subst::VecPerParamSpace::new(rps, Vec::new(), Vec::new()));
         self.type_vars_for_defs(obligation.cause.span,
-                                subst::ParamSpace::TypeSpace,
+                                TypeSpace,
                                 &mut substs,
                                 tps);
         substs
     }
 
-    fn impl_with_self_type_of(&self,
-                              trait_ref: ty::PolyTraitRef<'tcx>,
-                              obligation: &PredicateObligation<'tcx>)
-                              -> Option<DefId>
+    fn fuzzy_match_tys(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
+        /// returns the fuzzy category of a given type, or None
+        /// if the type can be equated to any type.
+        fn type_category<'tcx>(t: Ty<'tcx>) -> Option<u32> {
+            match t.sty {
+                ty::TyBool => Some(0),
+                ty::TyChar => Some(1),
+                ty::TyStr => Some(2),
+                ty::TyInt(..) | ty::TyUint(..) |
+                ty::TyInfer(ty::IntVar(..)) => Some(3),
+                ty::TyFloat(..) | ty::TyInfer(ty::FloatVar(..)) => Some(4),
+                ty::TyEnum(..) => Some(5),
+                ty::TyStruct(..) => Some(6),
+                ty::TyBox(..) | ty::TyRef(..) | ty::TyRawPtr(..) => Some(7),
+                ty::TyArray(..) | ty::TySlice(..) => Some(8),
+                ty::TyFnDef(..) | ty::TyFnPtr(..) => Some(9),
+                ty::TyTrait(..) => Some(10),
+                ty::TyClosure(..) => Some(11),
+                ty::TyTuple(..) => Some(12),
+                ty::TyProjection(..) => Some(13),
+                ty::TyParam(..) => Some(14),
+                ty::TyInfer(..) | ty::TyError => None
+            }
+        }
+
+        match (type_category(a), type_category(b)) {
+            (Some(cat_a), Some(cat_b)) => match (&a.sty, &b.sty) {
+                (&ty::TyStruct(def_a, _), &ty::TyStruct(def_b, _)) |
+                (&ty::TyEnum(def_a, _), &ty::TyEnum(def_b, _)) =>
+                    def_a == def_b,
+                _ => cat_a == cat_b
+            },
+            // infer and error can be equated to all types
+            _ => true
+        }
+    }
+
+    fn impl_similar_to(&self,
+                       trait_ref: ty::PolyTraitRef<'tcx>,
+                       obligation: &PredicateObligation<'tcx>)
+                       -> Option<DefId>
     {
         let tcx = self.tcx;
-        let mut result = None;
-        let mut ambiguous = false;
 
-        let trait_self_ty = tcx.erase_late_bound_regions(&trait_ref).self_ty();
+        let trait_ref = tcx.erase_late_bound_regions(&trait_ref);
+        let trait_self_ty = trait_ref.self_ty();
 
-        if trait_self_ty.is_ty_var() {
-            return None;
-        }
+        let mut self_match_impls = vec![];
+        let mut fuzzy_match_impls = vec![];
 
-        self.tcx.lookup_trait_def(trait_ref.def_id())
+        self.tcx.lookup_trait_def(trait_ref.def_id)
             .for_each_relevant_impl(self.tcx, trait_self_ty, |def_id| {
-                let impl_self_ty = tcx
+                let impl_trait_ref = tcx
                     .impl_trait_ref(def_id)
                     .unwrap()
-                    .self_ty()
                     .subst(tcx, &self.impl_substs(def_id, obligation.clone()));
 
-                if !tcx.has_attr(def_id, "rustc_on_unimplemented") {
-                    return;
-                }
+                let impl_self_ty = impl_trait_ref.self_ty();
 
                 if let Ok(..) = self.can_equate(&trait_self_ty, &impl_self_ty) {
-                    ambiguous = result.is_some();
-                    result = Some(def_id);
+                    self_match_impls.push(def_id);
+
+                    if trait_ref.substs.types.get_slice(TypeSpace).iter()
+                        .zip(impl_trait_ref.substs.types.get_slice(TypeSpace))
+                        .all(|(u,v)| self.fuzzy_match_tys(u, v))
+                    {
+                        fuzzy_match_impls.push(def_id);
+                    }
                 }
             });
 
-        if ambiguous {
-            None
+        let impl_def_id = if self_match_impls.len() == 1 {
+            self_match_impls[0]
+        } else if fuzzy_match_impls.len() == 1 {
+            fuzzy_match_impls[0]
         } else {
-            result
+            return None
+        };
+
+        if tcx.has_attr(impl_def_id, "rustc_on_unimplemented") {
+            Some(impl_def_id)
+        } else {
+            None
         }
     }
 
     fn on_unimplemented_note(&self,
                              trait_ref: ty::PolyTraitRef<'tcx>,
                              obligation: &PredicateObligation<'tcx>) -> Option<String> {
-        let def_id = self.impl_with_self_type_of(trait_ref, obligation)
+        let def_id = self.impl_similar_to(trait_ref, obligation)
             .unwrap_or(trait_ref.def_id());
         let trait_ref = trait_ref.skip_binder();
 
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 65df056fd42..c5db2a8a780 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -38,6 +38,7 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache};
 pub use self::select::{MethodMatchResult, MethodMatched, MethodAmbiguous, MethodDidNotMatch};
 pub use self::select::{MethodMatchedData}; // intentionally don't export variants
 pub use self::specialize::{OverlapError, specialization_graph, specializes, translate_substs};
+pub use self::specialize::{SpecializesCache};
 pub use self::util::elaborate_predicates;
 pub use self::util::supertraits;
 pub use self::util::Supertraits;
diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs
index 9abb179f288..5c7095beb79 100644
--- a/src/librustc/traits/project.rs
+++ b/src/librustc/traits/project.rs
@@ -152,14 +152,8 @@ enum ProjectionTyCandidate<'tcx> {
     // from the definition of `Trait` when you have something like <<A as Trait>::B as Trait2>::C
     TraitDef(ty::PolyProjectionPredicate<'tcx>),
 
-    // defined in an impl
-    Impl(VtableImplData<'tcx, PredicateObligation<'tcx>>),
-
-    // closure return type
-    Closure(VtableClosureData<'tcx, PredicateObligation<'tcx>>),
-
-    // fn pointer return type
-    FnPointer(VtableFnPointerData<'tcx, PredicateObligation<'tcx>>),
+    // from a "impl" (or a "pseudo-impl" returned by select)
+    Select,
 }
 
 struct ProjectionTyCandidateSet<'tcx> {
@@ -599,10 +593,8 @@ fn project_type<'cx, 'gcx, 'tcx>(
         debug!("retaining param-env candidates only from {:?}", candidates.vec);
         candidates.vec.retain(|c| match *c {
             ProjectionTyCandidate::ParamEnv(..) => true,
-            ProjectionTyCandidate::Impl(..) |
-            ProjectionTyCandidate::Closure(..) |
             ProjectionTyCandidate::TraitDef(..) |
-            ProjectionTyCandidate::FnPointer(..) => false,
+            ProjectionTyCandidate::Select => false,
         });
         debug!("resulting candidate set: {:?}", candidates.vec);
         if candidates.vec.len() != 1 {
@@ -612,78 +604,12 @@ fn project_type<'cx, 'gcx, 'tcx>(
 
     assert!(candidates.vec.len() <= 1);
 
-    let possible_candidate = candidates.vec.pop().and_then(|candidate| {
-        // In Any (i.e. trans) mode, all projections succeed;
-        // otherwise, we need to be sensitive to `default` and
-        // specialization.
-        if !selcx.projection_mode().is_any() {
-            if let ProjectionTyCandidate::Impl(ref impl_data) = candidate {
-                if let Some(node_item) = assoc_ty_def(selcx,
-                                                      impl_data.impl_def_id,
-                                                      obligation.predicate.item_name) {
-                    if node_item.node.is_from_trait() {
-                        if node_item.item.ty.is_some() {
-                            // If the associated type has a default from the
-                            // trait, that should be considered `default` and
-                            // hence not projected.
-                            //
-                            // Note, however, that we allow a projection from
-                            // the trait specifically in the case that the trait
-                            // does *not* give a default. This is purely to
-                            // avoid spurious errors: the situation can only
-                            // arise when *no* impl in the specialization chain
-                            // has provided a definition for the type. When we
-                            // confirm the candidate, we'll turn the projection
-                            // into a TyError, since the actual error will be
-                            // reported in `check_impl_items_against_trait`.
-                            return None;
-                        }
-                    } else if node_item.item.defaultness.is_default() {
-                        return None;
-                    }
-                } else {
-                    // Normally this situation could only arise througha
-                    // compiler bug, but at coherence-checking time we only look
-                    // at the topmost impl (we don't even consider the trait
-                    // itself) for the definition -- so we can fail to find a
-                    // definition of the type even if it exists.
-
-                    // For now, we just unconditionally ICE, because otherwise,
-                    // examples like the following will succeed:
-                    //
-                    // ```
-                    // trait Assoc {
-                    //     type Output;
-                    // }
-                    //
-                    // impl<T> Assoc for T {
-                    //     default type Output = bool;
-                    // }
-                    //
-                    // impl Assoc for u8 {}
-                    // impl Assoc for u16 {}
-                    //
-                    // trait Foo {}
-                    // impl Foo for <u8 as Assoc>::Output {}
-                    // impl Foo for <u16 as Assoc>::Output {}
-                    //     return None;
-                    // }
-                    // ```
-                    //
-                    // The essential problem here is that the projection fails,
-                    // leaving two unnormalized types, which appear not to unify
-                    // -- so the overlap check succeeds, when it should fail.
-                    bug!("Tried to project an inherited associated type during \
-                          coherence checking, which is currently not supported.");
-                }
-            }
-        }
-        Some(candidate)
-    });
-
-    match possible_candidate {
+    match candidates.vec.pop() {
         Some(candidate) => {
-            let (ty, obligations) = confirm_candidate(selcx, obligation, candidate);
+            let (ty, obligations) = confirm_candidate(selcx,
+                                                      obligation,
+                                                      &obligation_trait_ref,
+                                                      candidate);
             Ok(ProjectedTy::Progress(ty, obligations))
         }
         None => {
@@ -802,38 +728,6 @@ fn assemble_candidates_from_predicates<'cx, 'gcx, 'tcx, I>(
     }
 }
 
-fn assemble_candidates_from_object_type<'cx, 'gcx, 'tcx>(
-    selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
-    obligation:  &ProjectionTyObligation<'tcx>,
-    obligation_trait_ref: &ty::TraitRef<'tcx>,
-    candidate_set: &mut ProjectionTyCandidateSet<'tcx>)
-{
-    let self_ty = obligation_trait_ref.self_ty();
-    let object_ty = selcx.infcx().shallow_resolve(self_ty);
-    debug!("assemble_candidates_from_object_type(object_ty={:?})",
-           object_ty);
-    let data = match object_ty.sty {
-        ty::TyTrait(ref data) => data,
-        _ => {
-            span_bug!(
-                obligation.cause.span,
-                "assemble_candidates_from_object_type called with non-object: {:?}",
-                object_ty);
-        }
-    };
-    let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty);
-    let env_predicates = projection_bounds.iter()
-                                          .map(|p| p.to_predicate())
-                                          .collect();
-    let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
-    assemble_candidates_from_predicates(selcx,
-                                        obligation,
-                                        obligation_trait_ref,
-                                        candidate_set,
-                                        ProjectionTyCandidate::ParamEnv,
-                                        env_predicates)
-}
-
 fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
@@ -845,82 +739,183 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>(
     // start out by selecting the predicate `T as TraitRef<...>`:
     let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
     let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
-    let vtable = match selcx.select(&trait_obligation) {
-        Ok(Some(vtable)) => vtable,
-        Ok(None) => {
-            candidate_set.ambiguous = true;
-            return Ok(());
-        }
-        Err(e) => {
-            debug!("assemble_candidates_from_impls: selection error {:?}",
-                   e);
-            return Err(e);
-        }
-    };
+    selcx.infcx().probe(|_| {
+        let vtable = match selcx.select(&trait_obligation) {
+            Ok(Some(vtable)) => vtable,
+            Ok(None) => {
+                candidate_set.ambiguous = true;
+                return Ok(());
+            }
+            Err(e) => {
+                debug!("assemble_candidates_from_impls: selection error {:?}",
+                       e);
+                return Err(e);
+            }
+        };
 
-    match vtable {
-        super::VtableImpl(data) => {
-            debug!("assemble_candidates_from_impls: impl candidate {:?}",
-                   data);
+        match vtable {
+            super::VtableClosure(_) |
+            super::VtableFnPointer(_) |
+            super::VtableObject(_) => {
+                debug!("assemble_candidates_from_impls: vtable={:?}",
+                       vtable);
 
-            candidate_set.vec.push(
-                ProjectionTyCandidate::Impl(data));
-        }
-        super::VtableObject(_) => {
-            assemble_candidates_from_object_type(
-                selcx, obligation, obligation_trait_ref, candidate_set);
-        }
-        super::VtableClosure(data) => {
-            candidate_set.vec.push(
-                ProjectionTyCandidate::Closure(data));
-        }
-        super::VtableFnPointer(data) => {
-            candidate_set.vec.push(
-                ProjectionTyCandidate::FnPointer(data));
-        }
-        super::VtableParam(..) => {
-            // This case tell us nothing about the value of an
-            // associated type. Consider:
-            //
-            // ```
-            // trait SomeTrait { type Foo; }
-            // fn foo<T:SomeTrait>(...) { }
-            // ```
-            //
-            // If the user writes `<T as SomeTrait>::Foo`, then the `T
-            // : SomeTrait` binding does not help us decide what the
-            // type `Foo` is (at least, not more specifically than
-            // what we already knew).
-            //
-            // But wait, you say! What about an example like this:
-            //
-            // ```
-            // fn bar<T:SomeTrait<Foo=usize>>(...) { ... }
-            // ```
-            //
-            // Doesn't the `T : Sometrait<Foo=usize>` predicate help
-            // resolve `T::Foo`? And of course it does, but in fact
-            // that single predicate is desugared into two predicates
-            // in the compiler: a trait predicate (`T : SomeTrait`) and a
-            // projection. And the projection where clause is handled
-            // in `assemble_candidates_from_param_env`.
-        }
-        super::VtableDefaultImpl(..) |
-        super::VtableBuiltin(..) => {
-            // These traits have no associated types.
-            span_bug!(
-                obligation.cause.span,
-                "Cannot project an associated type from `{:?}`",
-                vtable);
+                candidate_set.vec.push(ProjectionTyCandidate::Select);
+            }
+            super::VtableImpl(ref impl_data) if !selcx.projection_mode().is_any() => {
+                // We have to be careful when projecting out of an
+                // impl because of specialization. If we are not in
+                // trans (i.e., projection mode is not "any"), and the
+                // impl's type is declared as default, then we disable
+                // projection (even if the trait ref is fully
+                // monomorphic). In the case where trait ref is not
+                // fully monomorphic (i.e., includes type parameters),
+                // this is because those type parameters may
+                // ultimately be bound to types from other crates that
+                // may have specialized impls we can't see. In the
+                // case where the trait ref IS fully monomorphic, this
+                // is a policy decision that we made in the RFC in
+                // order to preserve flexibility for the crate that
+                // defined the specializable impl to specialize later
+                // for existing types.
+                //
+                // In either case, we handle this by not adding a
+                // candidate for an impl if it contains a `default`
+                // type.
+                let opt_node_item = assoc_ty_def(selcx,
+                                                 impl_data.impl_def_id,
+                                                 obligation.predicate.item_name);
+                let new_candidate = if let Some(node_item) = opt_node_item {
+                    if node_item.node.is_from_trait() {
+                        if node_item.item.ty.is_some() {
+                            // The impl inherited a `type Foo =
+                            // Bar` given in the trait, which is
+                            // implicitly default. No candidate.
+                            None
+                        } else {
+                            // The impl did not specify `type` and neither
+                            // did the trait:
+                            //
+                            // ```rust
+                            // trait Foo { type T; }
+                            // impl Foo for Bar { }
+                            // ```
+                            //
+                            // This is an error, but it will be
+                            // reported in `check_impl_items_against_trait`.
+                            // We accept it here but will flag it as
+                            // an error when we confirm the candidate
+                            // (which will ultimately lead to `normalize_to_error`
+                            // being invoked).
+                            Some(ProjectionTyCandidate::Select)
+                        }
+                    } else if node_item.item.defaultness.is_default() {
+                        // The impl specified `default type Foo =
+                        // Bar`. No candidate.
+                        None
+                    } else {
+                        // The impl specified `type Foo = Bar`
+                        // with no default. Add a candidate.
+                        Some(ProjectionTyCandidate::Select)
+                    }
+                } else {
+                    // This is saying that neither the trait nor
+                    // the impl contain a definition for this
+                    // associated type.  Normally this situation
+                    // could only arise through a compiler bug --
+                    // if the user wrote a bad item name, it
+                    // should have failed in astconv. **However**,
+                    // at coherence-checking time, we only look at
+                    // the topmost impl (we don't even consider
+                    // the trait itself) for the definition -- and
+                    // so in that case it may be that the trait
+                    // *DOES* have a declaration, but we don't see
+                    // it, and we end up in this branch.
+                    //
+                    // This is kind of tricky to handle actually.
+                    // For now, we just unconditionally ICE,
+                    // because otherwise, examples like the
+                    // following will succeed:
+                    //
+                    // ```
+                    // trait Assoc {
+                    //     type Output;
+                    // }
+                    //
+                    // impl<T> Assoc for T {
+                    //     default type Output = bool;
+                    // }
+                    //
+                    // impl Assoc for u8 {}
+                    // impl Assoc for u16 {}
+                    //
+                    // trait Foo {}
+                    // impl Foo for <u8 as Assoc>::Output {}
+                    // impl Foo for <u16 as Assoc>::Output {}
+                    //     return None;
+                    // }
+                    // ```
+                    //
+                    // The essential problem here is that the
+                    // projection fails, leaving two unnormalized
+                    // types, which appear not to unify -- so the
+                    // overlap check succeeds, when it should
+                    // fail.
+                    bug!("Tried to project an inherited associated type during \
+                          coherence checking, which is currently not supported.");
+                };
+                candidate_set.vec.extend(new_candidate);
+            }
+            super::VtableImpl(_) => {
+                // In trans mode, we can just project out of impls, no prob.
+                assert!(selcx.projection_mode().is_any());
+                candidate_set.vec.push(ProjectionTyCandidate::Select);
+            }
+            super::VtableParam(..) => {
+                // This case tell us nothing about the value of an
+                // associated type. Consider:
+                //
+                // ```
+                // trait SomeTrait { type Foo; }
+                // fn foo<T:SomeTrait>(...) { }
+                // ```
+                //
+                // If the user writes `<T as SomeTrait>::Foo`, then the `T
+                // : SomeTrait` binding does not help us decide what the
+                // type `Foo` is (at least, not more specifically than
+                // what we already knew).
+                //
+                // But wait, you say! What about an example like this:
+                //
+                // ```
+                // fn bar<T:SomeTrait<Foo=usize>>(...) { ... }
+                // ```
+                //
+                // Doesn't the `T : Sometrait<Foo=usize>` predicate help
+                // resolve `T::Foo`? And of course it does, but in fact
+                // that single predicate is desugared into two predicates
+                // in the compiler: a trait predicate (`T : SomeTrait`) and a
+                // projection. And the projection where clause is handled
+                // in `assemble_candidates_from_param_env`.
+            }
+            super::VtableDefaultImpl(..) |
+            super::VtableBuiltin(..) => {
+                // These traits have no associated types.
+                span_bug!(
+                    obligation.cause.span,
+                    "Cannot project an associated type from `{:?}`",
+                    vtable);
+            }
         }
-    }
 
-    Ok(())
+        Ok(())
+    })
 }
 
 fn confirm_candidate<'cx, 'gcx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
     obligation: &ProjectionTyObligation<'tcx>,
+    obligation_trait_ref: &ty::TraitRef<'tcx>,
     candidate: ProjectionTyCandidate<'tcx>)
     -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
 {
@@ -934,18 +929,116 @@ fn confirm_candidate<'cx, 'gcx, 'tcx>(
             confirm_param_env_candidate(selcx, obligation, poly_projection)
         }
 
-        ProjectionTyCandidate::Impl(impl_vtable) => {
-            confirm_impl_candidate(selcx, obligation, impl_vtable)
+        ProjectionTyCandidate::Select => {
+            confirm_select_candidate(selcx, obligation, obligation_trait_ref)
+        }
+    }
+}
+
+fn confirm_select_candidate<'cx, 'gcx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
+    obligation: &ProjectionTyObligation<'tcx>,
+    obligation_trait_ref: &ty::TraitRef<'tcx>)
+    -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
+{
+    let poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
+    let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
+    let vtable = match selcx.select(&trait_obligation) {
+        Ok(Some(vtable)) => vtable,
+        _ => {
+            span_bug!(
+                obligation.cause.span,
+                "Failed to select `{:?}`",
+                trait_obligation);
         }
+    };
+
+    match vtable {
+        super::VtableImpl(data) =>
+            confirm_impl_candidate(selcx, obligation, data),
+        super::VtableClosure(data) =>
+            confirm_closure_candidate(selcx, obligation, data),
+        super::VtableFnPointer(data) =>
+            confirm_fn_pointer_candidate(selcx, obligation, data),
+        super::VtableObject(_) =>
+            confirm_object_candidate(selcx, obligation, obligation_trait_ref),
+        super::VtableDefaultImpl(..) |
+        super::VtableParam(..) |
+        super::VtableBuiltin(..) =>
+            // we don't create Select candidates with this kind of resolution
+            span_bug!(
+                obligation.cause.span,
+                "Cannot project an associated type from `{:?}`",
+                vtable),
+    }
+}
 
-        ProjectionTyCandidate::Closure(closure_vtable) => {
-            confirm_closure_candidate(selcx, obligation, closure_vtable)
+fn confirm_object_candidate<'cx, 'gcx, 'tcx>(
+    selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
+    obligation:  &ProjectionTyObligation<'tcx>,
+    obligation_trait_ref: &ty::TraitRef<'tcx>)
+    -> (Ty<'tcx>, Vec<PredicateObligation<'tcx>>)
+{
+    let self_ty = obligation_trait_ref.self_ty();
+    let object_ty = selcx.infcx().shallow_resolve(self_ty);
+    debug!("confirm_object_candidate(object_ty={:?})",
+           object_ty);
+    let data = match object_ty.sty {
+        ty::TyTrait(ref data) => data,
+        _ => {
+            span_bug!(
+                obligation.cause.span,
+                "confirm_object_candidate called with non-object: {:?}",
+                object_ty);
         }
+    };
+    let projection_bounds = data.projection_bounds_with_self_ty(selcx.tcx(), object_ty);
+    let env_predicates = projection_bounds.iter()
+                                          .map(|p| p.to_predicate())
+                                          .collect();
+    let env_predicate = {
+        let env_predicates = elaborate_predicates(selcx.tcx(), env_predicates);
+
+        // select only those projections that are actually projecting an
+        // item with the correct name
+        let env_predicates = env_predicates.filter_map(|p| match p {
+            ty::Predicate::Projection(data) =>
+                if data.item_name() == obligation.predicate.item_name {
+                    Some(data)
+                } else {
+                    None
+                },
+            _ => None
+        });
 
-        ProjectionTyCandidate::FnPointer(fn_pointer_vtable) => {
-            confirm_fn_pointer_candidate(selcx, obligation, fn_pointer_vtable)
+        // select those with a relevant trait-ref
+        let mut env_predicates = env_predicates.filter(|data| {
+            let origin = TypeOrigin::RelateOutputImplTypes(obligation.cause.span);
+            let data_poly_trait_ref = data.to_poly_trait_ref();
+            let obligation_poly_trait_ref = obligation_trait_ref.to_poly_trait_ref();
+            selcx.infcx().probe(|_| {
+                selcx.infcx().sub_poly_trait_refs(false,
+                                                  origin,
+                                                  data_poly_trait_ref,
+                                                  obligation_poly_trait_ref).is_ok()
+            })
+        });
+
+        // select the first matching one; there really ought to be one or
+        // else the object type is not WF, since an object type should
+        // include all of its projections explicitly
+        match env_predicates.next() {
+            Some(env_predicate) => env_predicate,
+            None => {
+                debug!("confirm_object_candidate: no env-predicate \
+                        found in object type `{:?}`; ill-formed",
+                       object_ty);
+                return (selcx.tcx().types.err, vec!());
+            }
         }
-    }
+    };
+
+    confirm_param_env_candidate(selcx, obligation, env_predicate)
 }
 
 fn confirm_fn_pointer_candidate<'cx, 'gcx, 'tcx>(
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index d43d2de1f1f..b2d14dab9a0 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -20,6 +20,7 @@
 use super::{SelectionContext, FulfillmentContext};
 use super::util::{fresh_type_vars_for_impl, impl_trait_ref_and_oblig};
 
+use rustc_data_structures::fnv::FnvHashMap;
 use hir::def_id::DefId;
 use infer::{InferCtxt, TypeOrigin};
 use middle::region;
@@ -111,6 +112,10 @@ pub fn translate_substs<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
 pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              impl1_def_id: DefId,
                              impl2_def_id: DefId) -> bool {
+    if let Some(r) = tcx.specializes_cache.borrow().check(impl1_def_id, impl2_def_id) {
+        return r;
+    }
+
     // The feature gate should prevent introducing new specializations, but not
     // taking advantage of upstream ones.
     if !tcx.sess.features.borrow().specialization &&
@@ -146,7 +151,7 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              .unwrap()
                              .subst(tcx, &penv.free_substs);
 
-    tcx.normalizing_infer_ctxt(ProjectionMode::Topmost).enter(|mut infcx| {
+    let result = tcx.normalizing_infer_ctxt(ProjectionMode::Topmost).enter(|mut infcx| {
         // Normalize the trait reference, adding any obligations
         // that arise into the impl1 assumptions.
         let Normalized { value: impl1_trait_ref, obligations: normalization_obligations } = {
@@ -167,7 +172,10 @@ pub fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         // Attempt to prove that impl2 applies, given all of the above.
         fulfill_implication(&infcx, impl1_trait_ref, impl2_def_id).is_ok()
-    })
+    });
+
+    tcx.specializes_cache.borrow_mut().insert(impl1_def_id, impl2_def_id, result);
+    result
 }
 
 /// Attempt to fulfill all obligations of `target_impl` after unification with
@@ -225,3 +233,23 @@ fn fulfill_implication<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
         }
     })
 }
+
+pub struct SpecializesCache {
+    map: FnvHashMap<(DefId, DefId), bool>
+}
+
+impl SpecializesCache {
+    pub fn new() -> Self {
+        SpecializesCache {
+            map: FnvHashMap()
+        }
+    }
+
+    pub fn check(&self, a: DefId, b: DefId) -> Option<bool> {
+        self.map.get(&(a, b)).cloned()
+    }
+
+    pub fn insert(&mut self, a: DefId, b: DefId, result: bool) {
+        self.map.insert((a, b), result);
+    }
+}
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index 39fe744c67d..45aa6f881e8 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -11,13 +11,14 @@
 //! type context book-keeping
 
 use dep_graph::{DepGraph, DepTrackingMap};
-use hir::map as ast_map;
 use session::Session;
 use lint;
 use middle;
 use middle::cstore::LOCAL_CRATE;
 use hir::def::DefMap;
-use hir::def_id::DefId;
+use hir::def_id::{DefId, DefIndex};
+use hir::map as ast_map;
+use hir::map::{DefKey, DefPath, DefPathData, DisambiguatedDefPathData};
 use middle::free_region::FreeRegionMap;
 use middle::region::RegionMaps;
 use middle::resolve_lifetime;
@@ -291,6 +292,8 @@ impl<'a, 'gcx, 'tcx> Deref for TyCtxt<'a, 'gcx, 'tcx> {
 pub struct GlobalCtxt<'tcx> {
     global_interners: CtxtInterners<'tcx>,
 
+    pub specializes_cache: RefCell<traits::SpecializesCache>,
+
     pub dep_graph: DepGraph,
 
     /// Common types, pre-interned for your convenience.
@@ -511,6 +514,49 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    /// Given a def-key `key` and a crate `krate`, finds the def-index
+    /// that `krate` assigned to `key`. This `DefIndex` will always be
+    /// relative to `krate`.
+    ///
+    /// Returns `None` if there is no `DefIndex` with that key.
+    pub fn def_index_for_def_key(self, krate: ast::CrateNum, key: DefKey)
+                                 -> Option<DefIndex> {
+        if krate == LOCAL_CRATE {
+            self.map.def_index_for_def_key(key)
+        } else {
+            self.sess.cstore.def_index_for_def_key(krate, key)
+        }
+    }
+
+    pub fn retrace_path(self, path: &DefPath) -> Option<DefId> {
+        debug!("retrace_path(path={:?})", path);
+
+        let root_key = DefKey {
+            parent: None,
+            disambiguated_data: DisambiguatedDefPathData {
+                data: DefPathData::CrateRoot,
+                disambiguator: 0,
+            },
+        };
+
+        let root_index = self.def_index_for_def_key(path.krate, root_key)
+                             .expect("no root key?");
+
+        debug!("retrace_path: root_index={:?}", root_index);
+
+        let mut index = root_index;
+        for data in &path.data {
+            let key = DefKey { parent: Some(index), disambiguated_data: data.clone() };
+            debug!("retrace_path: key={:?}", key);
+            match self.def_index_for_def_key(path.krate, key) {
+                Some(i) => index = i,
+                None => return None,
+            }
+        }
+
+        Some(DefId { krate: path.krate, index: index })
+    }
+
     pub fn type_parameter_def(self,
                               node_id: NodeId)
                               -> ty::TypeParameterDef<'tcx>
@@ -637,6 +683,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         let dep_graph = map.dep_graph.clone();
         let fulfilled_predicates = traits::GlobalFulfilledPredicates::new(dep_graph.clone());
         tls::enter_global(GlobalCtxt {
+            specializes_cache: RefCell::new(traits::SpecializesCache::new()),
             global_interners: interners,
             dep_graph: dep_graph.clone(),
             types: common_types,
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 14b369f244d..4a14185b6e3 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -382,6 +382,35 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
+    /// Returns a set of all late-bound regions that are constrained
+    /// by `value`, meaning that if we instantiate those LBR with
+    /// variables and equate `value` with something else, those
+    /// variables will also be equated.
+    pub fn collect_constrained_late_bound_regions<T>(&self, value: &Binder<T>)
+                                                     -> FnvHashSet<ty::BoundRegion>
+        where T : TypeFoldable<'tcx>
+    {
+        self.collect_late_bound_regions(value, true)
+    }
+
+    /// Returns a set of all late-bound regions that appear in `value` anywhere.
+    pub fn collect_referenced_late_bound_regions<T>(&self, value: &Binder<T>)
+                                                    -> FnvHashSet<ty::BoundRegion>
+        where T : TypeFoldable<'tcx>
+    {
+        self.collect_late_bound_regions(value, false)
+    }
+
+    fn collect_late_bound_regions<T>(&self, value: &Binder<T>, just_constraint: bool)
+                                     -> FnvHashSet<ty::BoundRegion>
+        where T : TypeFoldable<'tcx>
+    {
+        let mut collector = LateBoundRegionsCollector::new(just_constraint);
+        let result = value.skip_binder().visit_with(&mut collector);
+        assert!(!result); // should never have stopped early
+        collector.regions
+    }
+
     /// Replace any late-bound regions bound in `value` with `'static`. Useful in trans but also
     /// method lookup and a few other places where precise region relationships are not required.
     pub fn erase_late_bound_regions<T>(self, value: &Binder<T>) -> T
@@ -625,3 +654,54 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
         false
     }
 }
+
+/// Collects all the late-bound regions it finds into a hash set.
+struct LateBoundRegionsCollector {
+    current_depth: u32,
+    regions: FnvHashSet<ty::BoundRegion>,
+    just_constrained: bool,
+}
+
+impl LateBoundRegionsCollector {
+    fn new(just_constrained: bool) -> Self {
+        LateBoundRegionsCollector {
+            current_depth: 1,
+            regions: FnvHashSet(),
+            just_constrained: just_constrained,
+        }
+    }
+}
+
+impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector {
+    fn visit_binder<T: TypeFoldable<'tcx>>(&mut self, t: &Binder<T>) -> bool {
+        self.current_depth += 1;
+        let result = t.super_visit_with(self);
+        self.current_depth -= 1;
+        result
+    }
+
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+        // if we are only looking for "constrained" region, we have to
+        // ignore the inputs to a projection, as they may not appear
+        // in the normalized form
+        if self.just_constrained {
+            match t.sty {
+                ty::TyProjection(..) => { return false; }
+                _ => { }
+            }
+        }
+
+        t.super_visit_with(self)
+    }
+
+    fn visit_region(&mut self, r: ty::Region) -> bool {
+        match r {
+            ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
+                self.regions.insert(br);
+            }
+            _ => { }
+        }
+        false
+    }
+}
+
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 114e81721ab..dfb4ec73924 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2216,7 +2216,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         match self.map.find(id) {
             Some(ast_map::NodeLocal(pat)) => {
                 match pat.node {
-                    PatKind::Ident(_, ref path1, _) => path1.node.name.as_str(),
+                    PatKind::Ident(_, ref path1, _) => path1.node.as_str(),
                     _ => {
                         bug!("Variable id {} maps to {:?}, not local", id, pat);
                     },
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 08909861d3f..4f6188ea3c5 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -368,7 +368,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 } else {
                     tcx.sess.cstore.crate_hash(did.krate)
                 };
-                h.as_str().hash(state);
+                h.hash(state);
                 did.index.hash(state);
             };
             let mt = |state: &mut SipHasher, mt: TypeAndMut| {
diff --git a/src/librustc_back/target/i686_linux_android.rs b/src/librustc_back/target/i686_linux_android.rs
index df746965a92..2376de12398 100644
--- a/src/librustc_back/target/i686_linux_android.rs
+++ b/src/librustc_back/target/i686_linux_android.rs
@@ -12,9 +12,13 @@ use target::Target;
 
 pub fn target() -> Target {
     let mut base = super::android_base::opts();
-    base.cpu = "pentium4".to_string();
+
     base.max_atomic_width = 64;
 
+    // http://developer.android.com/ndk/guides/abis.html#x86
+    base.cpu = "pentiumpro".to_string();
+    base.features = "+mmx,+sse,+sse2,+sse3,+ssse3".to_string();
+
     Target {
         llvm_target: "i686-linux-android".to_string(),
         target_endian: "little".to_string(),
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index fcfab96b9df..36f95f62d06 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -872,7 +872,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
                        &format!("borrow of `{}` occurs here",
                                self.bccx.loan_path_to_string(loan_path)))
             .span_label(span,
-                       &format!("assignment to `{}` occurs here",
+                       &format!("assignment to borrowed `{}` occurs here",
                                self.bccx.loan_path_to_string(loan_path)))
             .emit();
     }
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index c85d69fa8a6..83322215e30 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -100,7 +100,7 @@ pub fn gather_move_from_pat<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
     let pat_span_path_opt = match move_pat.node {
         PatKind::Ident(_, ref path1, _) => {
             Some(MoveSpanAndPath{span: move_pat.span,
-                                 name: path1.node.name})
+                                 name: path1.node})
         },
         _ => None,
     };
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index cdc68edbf30..c1e83588570 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -126,7 +126,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                              move_from.descriptive_string(bccx.tcx));
             err.span_label(
                 move_from.span,
-                &format!("move occurs here")
+                &format!("cannot move out of {}", move_from.descriptive_string(bccx.tcx))
                 );
             err
         }
@@ -138,7 +138,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                                                "cannot move out of type `{}`, \
                                                a non-copy fixed-size array",
                                                b.ty);
-                err.span_label(move_from.span, &format!("can not move out of here"));
+                err.span_label(move_from.span, &format!("cannot move out of here"));
                 err
             } else {
                 span_bug!(move_from.span, "this path should not cause illegal move");
@@ -152,9 +152,9 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
                 ty::TyEnum(def, _) if def.has_dtor() => {
                     let mut err = struct_span_err!(bccx, move_from.span, E0509,
                                                    "cannot move out of type `{}`, \
-                                                   which defines the `Drop` trait",
+                                                   which implements the `Drop` trait",
                                                    b.ty);
-                    err.span_label(move_from.span, &format!("can not move out of here"));
+                    err.span_label(move_from.span, &format!("cannot move out of here"));
                     err
                 },
                 _ => {
@@ -175,16 +175,12 @@ fn note_move_destination(mut err: DiagnosticBuilder,
     if is_first_note {
         err.span_label(
             move_to_span,
-            &format!("attempting to move value to here"));
-        err.help(
-            &format!("to prevent the move, \
-                      use `ref {0}` or `ref mut {0}` to capture value by \
-                      reference",
+            &format!("hint: to prevent move, use `ref {0}` or `ref mut {0}`",
                      pat_name));
         err
     } else {
-        err.span_note(move_to_span,
-                      &format!("and here (use `ref {0}` or `ref mut {0}`)",
+        err.span_label(move_to_span,
+                      &format!("...and here (use `ref {0}` or `ref mut {0}`)",
                                pat_name));
         err
     }
diff --git a/src/librustc_borrowck/diagnostics.rs b/src/librustc_borrowck/diagnostics.rs
index cdbad685008..116e3476897 100644
--- a/src/librustc_borrowck/diagnostics.rs
+++ b/src/librustc_borrowck/diagnostics.rs
@@ -391,6 +391,7 @@ fn you_know_nothing(jon_snow: &mut i32) {
                        //        but it is already borrowed
     };
 }
+```
 
 In here, `jon_snow` is already borrowed by the `nights_watch` closure, so it
 cannot be borrowed by the `starks` closure at the same time. To fix this issue,
@@ -501,6 +502,33 @@ fn foo(a: &mut i32) {
 ```
 "##,
 
+E0502: r##"
+This error indicates that you are trying to borrow a variable as mutable when it
+has already been borrowed as immutable.
+
+Example of erroneous code:
+
+```compile_fail
+fn bar(x: &mut i32) {}
+fn foo(a: &mut i32) {
+    let ref y = a; // a is borrowed as immutable.
+    bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed
+            //        as immutable
+}
+```
+To fix this error, ensure that you don't have any other references to the
+variable before trying to access it mutably:
+```
+fn bar(x: &mut i32) {}
+fn foo(a: &mut i32) {
+    bar(a);
+    let ref y = a; // ok!
+}
+```
+For more information on the rust ownership system, take a look at
+https://doc.rust-lang.org/stable/book/references-and-borrowing.html.
+"##,
+
 E0504: r##"
 This error occurs when an attempt is made to move a borrowed variable into a
 closure.
@@ -983,7 +1011,6 @@ fn main() {
 register_diagnostics! {
     E0385, // {} in an aliasable location
     E0388, // {} in a static location
-    E0502, // cannot borrow `..`.. as .. because .. is also borrowed as ...
     E0503, // cannot use `..` because it was mutably borrowed
     E0508, // cannot move out of type `..`, a non-copy fixed-size array
     E0524, // two closures require unique access to `..` at the same time
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 61d2408d5bf..2fb5d796589 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -240,24 +240,24 @@ fn check_expr(cx: &mut MatchCheckCtxt, ex: &hir::Expr) {
 fn check_for_bindings_named_the_same_as_variants(cx: &MatchCheckCtxt, pat: &Pat) {
     pat.walk(|p| {
         match p.node {
-            PatKind::Ident(hir::BindByValue(hir::MutImmutable), ident, None) => {
+            PatKind::Ident(hir::BindByValue(hir::MutImmutable), name, None) => {
                 let pat_ty = cx.tcx.pat_ty(p);
                 if let ty::TyEnum(edef, _) = pat_ty.sty {
                     let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
                     if let Some(Def::Local(..)) = def {
                         if edef.variants.iter().any(|variant|
-                            variant.name == ident.node.unhygienic_name
+                            variant.name == name.node.unhygienize()
                                 && variant.kind() == VariantKind::Unit
                         ) {
                             let ty_path = cx.tcx.item_path_str(edef.did);
                             let mut err = struct_span_warn!(cx.tcx.sess, p.span, E0170,
                                 "pattern binding `{}` is named the same as one \
                                  of the variants of the type `{}`",
-                                ident.node, ty_path);
+                                name.node, ty_path);
                             help!(err,
                                 "if you meant to match on a variant, \
                                  consider making the path in the pattern qualified: `{}::{}`",
-                                ty_path, ident.node);
+                                ty_path, name.node);
                             err.emit();
                         }
                     }
diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs
index 99a87d1e760..731471b0600 100644
--- a/src/librustc_data_structures/graph/mod.rs
+++ b/src/librustc_data_structures/graph/mod.rs
@@ -292,11 +292,15 @@ impl<N: Debug, E: Debug> Graph<N, E> {
         }
     }
 
-    pub fn depth_traverse<'a>(&'a self, start: NodeIndex) -> DepthFirstTraversal<'a, N, E> {
+    pub fn depth_traverse<'a>(&'a self,
+                              start: NodeIndex,
+                              direction: Direction)
+                              -> DepthFirstTraversal<'a, N, E> {
         DepthFirstTraversal {
             graph: self,
             stack: vec![start],
             visited: BitVector::new(self.nodes.len()),
+            direction: direction,
         }
     }
 }
@@ -371,6 +375,7 @@ pub struct DepthFirstTraversal<'g, N: 'g, E: 'g> {
     graph: &'g Graph<N, E>,
     stack: Vec<NodeIndex>,
     visited: BitVector,
+    direction: Direction,
 }
 
 impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> {
@@ -382,9 +387,10 @@ impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> {
                 continue;
             }
 
-            for (_, edge) in self.graph.outgoing_edges(idx) {
-                if !self.visited.contains(edge.target().node_id()) {
-                    self.stack.push(edge.target());
+            for (_, edge) in self.graph.adjacent_edges(idx, self.direction) {
+                let target = edge.source_or_target(self.direction);
+                if !self.visited.contains(target.node_id()) {
+                    self.stack.push(target);
                 }
             }
 
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 46356add8c6..1f3df1ff6f2 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -152,7 +152,6 @@ pub fn compile_input(sess: &Session,
                                 Ok(()));
 
         let expanded_crate = assign_node_ids(sess, expanded_crate);
-        let dep_graph = DepGraph::new(sess.opts.build_dep_graph());
 
         // Collect defintions for def ids.
         let mut defs = time(sess.time_passes(),
@@ -161,15 +160,15 @@ pub fn compile_input(sess: &Session,
 
         time(sess.time_passes(),
              "external crate/lib resolution",
-             || read_local_crates(sess, &cstore, &defs, &expanded_crate, &id, &dep_graph));
+             || read_local_crates(sess, &cstore, &defs, &expanded_crate, &id, &sess.dep_graph));
 
         time(sess.time_passes(),
              "early lint checks",
              || lint::check_ast_crate(sess, &expanded_crate));
 
         let (analysis, resolutions, mut hir_forest) = {
-            lower_and_resolve(sess, &id, &mut defs, &expanded_crate, dep_graph,
-                              control.make_glob_map)
+            lower_and_resolve(sess, &id, &mut defs, &expanded_crate,
+                              &sess.dep_graph, control.make_glob_map)
         };
 
         // Discard MTWT tables that aren't required past lowering to HIR.
@@ -805,7 +804,7 @@ pub fn lower_and_resolve<'a>(sess: &Session,
                              id: &'a str,
                              defs: &mut hir_map::Definitions,
                              krate: &ast::Crate,
-                             dep_graph: DepGraph,
+                             dep_graph: &DepGraph,
                              make_glob_map: resolve::MakeGlobMap)
                              -> (ty::CrateAnalysis<'a>, Resolutions, hir_map::Forest) {
     resolve::with_resolver(sess, defs, make_glob_map, |mut resolver| {
@@ -815,7 +814,7 @@ pub fn lower_and_resolve<'a>(sess: &Session,
 
         // Lower ast -> hir.
         let hir_forest = time(sess.time_passes(), "lowering ast -> hir", || {
-            hir_map::Forest::new(lower_crate(krate, sess, &mut resolver), dep_graph)
+            hir_map::Forest::new(lower_crate(sess, krate, sess, &mut resolver), dep_graph)
         });
 
         (ty::CrateAnalysis {
@@ -1175,6 +1174,9 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<c
                          Some(ref n) if *n == "dylib" => {
                              Some(config::CrateTypeDylib)
                          }
+                         Some(ref n) if *n == "cdylib" => {
+                             Some(config::CrateTypeCdylib)
+                         }
                          Some(ref n) if *n == "lib" => {
                              Some(config::default_lib_output())
                          }
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 2a4b30e016f..06133c508d9 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -67,6 +67,7 @@ use pretty::{PpMode, UserIdentifiedItem};
 use rustc_resolve as resolve;
 use rustc_save_analysis as save;
 use rustc_trans::back::link;
+use rustc::dep_graph::DepGraph;
 use rustc::session::{self, config, Session, build_session, CompileResult};
 use rustc::session::config::{Input, PrintRequest, OutputType, ErrorOutputType};
 use rustc::session::config::{get_unstable_features_setting, nightly_options};
@@ -196,9 +197,11 @@ pub fn run_compiler_with_file_loader<'a, L>(args: &[String],
         },
     };
 
-    let cstore = Rc::new(CStore::new(token::get_ident_interner()));
+    let dep_graph = DepGraph::new(sopts.build_dep_graph());
+    let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
     let codemap = Rc::new(CodeMap::with_file_loader(loader));
     let sess = session::build_session_with_codemap(sopts,
+                                                   &dep_graph,
                                                    input_file_path,
                                                    descriptions,
                                                    cstore.clone(),
@@ -425,9 +428,13 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
                     describe_lints(&ls, false);
                     return None;
                 }
-                let cstore = Rc::new(CStore::new(token::get_ident_interner()));
-                let sess = build_session(sopts.clone(), None, descriptions.clone(),
-                                         cstore.clone());
+                let dep_graph = DepGraph::new(sopts.build_dep_graph());
+                let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
+                let sess = build_session(sopts.clone(),
+                    &dep_graph,
+                    None,
+                    descriptions.clone(),
+                    cstore.clone());
                 rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
                 let should_stop = RustcDefaultCalls::print_crate_info(&sess, None, odir, ofile);
                 if should_stop == Compilation::Stop {
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 9aae9f04c92..8c84e561e31 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -18,10 +18,10 @@ use self::NodesMatchingUII::*;
 use abort_on_err;
 use driver::{self, Resolutions};
 
-use rustc::dep_graph::DepGraph;
 use rustc::ty::{self, TyCtxt};
 use rustc::cfg;
 use rustc::cfg::graphviz::LabelledCFG;
+use rustc::dep_graph::DepGraph;
 use rustc::session::Session;
 use rustc::session::config::Input;
 use rustc_borrowck as borrowck;
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index bbda1965c7f..e0d693c4230 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -104,8 +104,10 @@ fn test_env<F>(source_string: &str,
     options.unstable_features = UnstableFeatures::Allow;
     let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter);
 
-    let cstore = Rc::new(CStore::new(token::get_ident_interner()));
-    let sess = session::build_session_(options, None, diagnostic_handler,
+    let dep_graph = DepGraph::new(false);
+    let _ignore = dep_graph.in_ignore();
+    let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
+    let sess = session::build_session_(options, &dep_graph, None, diagnostic_handler,
                                        Rc::new(CodeMap::new()), cstore.clone());
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     let krate_config = Vec::new();
@@ -117,15 +119,14 @@ fn test_env<F>(source_string: &str,
     let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, "test", None)
                     .expect("phase 2 aborted");
 
-    let dep_graph = DepGraph::new(false);
     let krate = driver::assign_node_ids(&sess, krate);
     let mut defs = hir_map::collect_definitions(&krate);
     read_local_crates(&sess, &cstore, &defs, &krate, "test_crate", &dep_graph);
     let _ignore = dep_graph.in_ignore();
 
     let (_, resolutions, mut hir_forest) = {
-        driver::lower_and_resolve(&sess, "test-crate", &mut defs, &krate, dep_graph.clone(),
-                                  MakeGlobMap::No)
+        driver::lower_and_resolve(&sess, "test-crate", &mut defs, &krate,
+                                  &sess.dep_graph, MakeGlobMap::No)
     };
 
     let arenas = ty::CtxtArenas::new();
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index b74e7e21226..9dc50a63064 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -44,6 +44,7 @@
 
 use graphviz as dot;
 use rustc::dep_graph::{DepGraphQuery, DepNode};
+use rustc::dep_graph::debug::{DepNodeFilter, EdgeFilter};
 use rustc::hir::def_id::DefId;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fnv::{FnvHashMap, FnvHashSet};
@@ -195,7 +196,7 @@ fn check_paths<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         };
 
         for &(_, source_def_id, source_dep_node) in sources {
-            let dependents = query.transitive_dependents(source_dep_node);
+            let dependents = query.transitive_successors(source_dep_node);
             for &(target_span, ref target_pass, _, ref target_dep_node) in targets {
                 if !dependents.contains(&target_dep_node) {
                     tcx.sess.span_err(
@@ -220,12 +221,11 @@ fn dump_graph(tcx: TyCtxt) {
     let nodes = match env::var("RUST_DEP_GRAPH_FILTER") {
         Ok(string) => {
             // Expect one of: "-> target", "source -> target", or "source ->".
-            let parts: Vec<_> = string.split("->").collect();
-            if parts.len() > 2 {
-                bug!("Invalid RUST_DEP_GRAPH_FILTER: expected '[source] -> [target]'");
-            }
-            let sources = node_set(&query, &parts[0]);
-            let targets = node_set(&query, &parts[1]);
+            let edge_filter = EdgeFilter::new(&string).unwrap_or_else(|e| {
+                bug!("invalid filter: {}", e)
+            });
+            let sources = node_set(&query, &edge_filter.source);
+            let targets = node_set(&query, &edge_filter.target);
             filter_nodes(&query, &sources, &targets)
         }
         Err(_) => {
@@ -295,26 +295,16 @@ impl<'a, 'tcx> dot::Labeller<'a> for GraphvizDepGraph {
 // Given an optional filter like `"x,y,z"`, returns either `None` (no
 // filter) or the set of nodes whose labels contain all of those
 // substrings.
-fn node_set(query: &DepGraphQuery<DefId>, filter: &str)
+fn node_set(query: &DepGraphQuery<DefId>, filter: &DepNodeFilter)
             -> Option<FnvHashSet<DepNode<DefId>>>
 {
     debug!("node_set(filter={:?})", filter);
 
-    if filter.trim().is_empty() {
+    if filter.accepts_all() {
         return None;
     }
 
-    let filters: Vec<&str> = filter.split("&").map(|s| s.trim()).collect();
-
-    debug!("node_set: filters={:?}", filters);
-
-    Some(query.nodes()
-         .into_iter()
-         .filter(|n| {
-             let s = format!("{:?}", n);
-             filters.iter().all(|f| s.contains(f))
-         })
-        .collect())
+    Some(query.nodes().into_iter().filter(|n| filter.test(n)).collect())
 }
 
 fn filter_nodes(query: &DepGraphQuery<DefId>,
diff --git a/src/librustc_incremental/calculate_svh.rs b/src/librustc_incremental/calculate_svh.rs
index e914c38963c..24ecce11487 100644
--- a/src/librustc_incremental/calculate_svh.rs
+++ b/src/librustc_incremental/calculate_svh.rs
@@ -72,12 +72,14 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> {
             attr.node.value.hash(&mut state);
         }
 
-        Svh::from_hash(state.finish())
+        Svh::new(state.finish())
     }
 
     fn calculate_item_hash(self, def_id: DefId) -> u64 {
         assert!(def_id.is_local());
 
+        debug!("calculate_item_hash(def_id={:?})", def_id);
+
         let mut state = SipHasher::new();
 
         {
@@ -89,11 +91,16 @@ impl<'a, 'tcx> SvhCalculate for TyCtxt<'a, 'tcx, 'tcx> {
                 intravisit::walk_crate(&mut visit, krate);
             } else {
                 let node_id = self.map.as_local_node_id(def_id).unwrap();
-                visit.visit_item(self.map.expect_item(node_id));
+                let item = self.map.expect_item(node_id);
+                visit.visit_item(item);
             }
         }
 
-        state.finish()
+        let hash = state.finish();
+
+        debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, hash);
+
+        hash
     }
 }
 
@@ -244,7 +251,7 @@ mod svh_visitor {
             ExprType(..)             => SawExprType,
             ExprIf(..)               => SawExprIf,
             ExprWhile(..)            => SawExprWhile,
-            ExprLoop(_, id)          => SawExprLoop(id.map(|id| id.name.as_str())),
+            ExprLoop(_, id)          => SawExprLoop(id.map(|id| id.as_str())),
             ExprMatch(..)            => SawExprMatch,
             ExprClosure(..)          => SawExprClosure,
             ExprBlock(..)            => SawExprBlock,
@@ -255,8 +262,8 @@ mod svh_visitor {
             ExprIndex(..)            => SawExprIndex,
             ExprPath(ref qself, _)   => SawExprPath(qself.as_ref().map(|q| q.position)),
             ExprAddrOf(m, _)         => SawExprAddrOf(m),
-            ExprBreak(id)            => SawExprBreak(id.map(|id| id.node.name.as_str())),
-            ExprAgain(id)            => SawExprAgain(id.map(|id| id.node.name.as_str())),
+            ExprBreak(id)            => SawExprBreak(id.map(|id| id.node.as_str())),
+            ExprAgain(id)            => SawExprAgain(id.map(|id| id.node.as_str())),
             ExprRet(..)              => SawExprRet,
             ExprInlineAsm(ref a,_,_) => SawExprInlineAsm(a),
             ExprStruct(..)           => SawExprStruct,
diff --git a/src/librustc_incremental/persist/data.rs b/src/librustc_incremental/persist/data.rs
index 37d5f8937f1..f57ab19a525 100644
--- a/src/librustc_incremental/persist/data.rs
+++ b/src/librustc_incremental/persist/data.rs
@@ -11,13 +11,35 @@
 //! The data that we will serialize and deserialize.
 
 use rustc::dep_graph::DepNode;
+use rustc::hir::def_id::DefIndex;
 
 use super::directory::DefPathIndex;
 
+/// Data for use when recompiling the **current crate**.
 #[derive(Debug, RustcEncodable, RustcDecodable)]
 pub struct SerializedDepGraph {
     pub nodes: Vec<DepNode<DefPathIndex>>,
     pub edges: Vec<SerializedEdge>,
+
+    /// These are hashes of two things:
+    /// - the HIR nodes in this crate
+    /// - the metadata nodes from dependent crates we use
+    ///
+    /// In each case, we store a hash summarizing the contents of
+    /// those items as they were at the time we did this compilation.
+    /// In the case of HIR nodes, this hash is derived by walking the
+    /// HIR itself. In the case of metadata nodes, the hash is loaded
+    /// from saved state.
+    ///
+    /// When we do the next compile, we will load these back up and
+    /// compare them against the hashes we see at that time, which
+    /// will tell us what has changed, either in this crate or in some
+    /// crate that we depend on.
+    ///
+    /// Because they will be reloaded, we don't store the DefId (which
+    /// will be different when we next compile) related to each node,
+    /// but rather the `DefPathIndex`. This can then be retraced
+    /// to find the current def-id.
     pub hashes: Vec<SerializedHash>,
 }
 
@@ -25,7 +47,44 @@ pub type SerializedEdge = (DepNode<DefPathIndex>, DepNode<DefPathIndex>);
 
 #[derive(Debug, RustcEncodable, RustcDecodable)]
 pub struct SerializedHash {
-    pub index: DefPathIndex,
+    /// node being hashed; either a Hir or MetaData variant, in
+    /// practice
+    pub node: DepNode<DefPathIndex>,
+
+    /// the hash itself, computed by `calculate_item_hash`
+    pub hash: u64,
+}
+
+/// Data for use when downstream crates get recompiled.
+#[derive(Debug, RustcEncodable, RustcDecodable)]
+pub struct SerializedMetadataHashes {
+    /// For each def-id defined in this crate that appears in the
+    /// metadata, we hash all the inputs that were used when producing
+    /// the metadata. We save this after compilation is done. Then,
+    /// when some downstream crate is being recompiled, it can compare
+    /// the hashes we saved against the hashes that it saw from
+    /// before; this will tell it which of the items in this crate
+    /// changed, which in turn implies what items in the downstream
+    /// crate need to be recompiled.
+    ///
+    /// Note that we store the def-ids here. This is because we don't
+    /// reload this file when we recompile this crate, we will just
+    /// regenerate it completely with the current hashes and new def-ids.
+    ///
+    /// Then downstream creates will load up their
+    /// `SerializedDepGraph`, which may contain `MetaData(X)` nodes
+    /// where `X` refers to some item in this crate. That `X` will be
+    /// a `DefPathIndex` that gets retracted to the current `DefId`
+    /// (matching the one found in this structure).
+    pub hashes: Vec<SerializedMetadataHash>,
+}
+
+/// The hash for some metadata that (when saving) will be exported
+/// from this crate, or which (when importing) was exported by an
+/// upstream crate.
+#[derive(Debug, RustcEncodable, RustcDecodable)]
+pub struct SerializedMetadataHash {
+    pub def_index: DefIndex,
 
     /// the hash itself, computed by `calculate_item_hash`
     pub hash: u64,
diff --git a/src/librustc_incremental/persist/directory.rs b/src/librustc_incremental/persist/directory.rs
index e256b7cf7d0..f9e90f39321 100644
--- a/src/librustc_incremental/persist/directory.rs
+++ b/src/librustc_incremental/persist/directory.rs
@@ -41,7 +41,7 @@ impl DefIdDirectory {
 
     pub fn retrace(&self, tcx: TyCtxt) -> RetracedDefIdDirectory {
         let ids = self.paths.iter()
-                            .map(|path| tcx.map.retrace_path(path))
+                            .map(|path| tcx.retrace_path(path))
                             .collect();
         RetracedDefIdDirectory { ids: ids }
     }
@@ -64,7 +64,7 @@ impl RetracedDefIdDirectory {
 
 pub struct DefIdDirectoryBuilder<'a,'tcx:'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    hash: DefIdMap<Option<DefPathIndex>>,
+    hash: DefIdMap<DefPathIndex>,
     directory: DefIdDirectory,
 }
 
@@ -77,29 +77,22 @@ impl<'a,'tcx> DefIdDirectoryBuilder<'a,'tcx> {
         }
     }
 
-    pub fn add(&mut self, def_id: DefId) -> Option<DefPathIndex> {
-        if !def_id.is_local() {
-            // FIXME(#32015) clarify story about cross-crate dep tracking
-            return None;
-        }
-
+    pub fn add(&mut self, def_id: DefId) -> DefPathIndex {
+        debug!("DefIdDirectoryBuilder: def_id={:?}", def_id);
         let tcx = self.tcx;
         let paths = &mut self.directory.paths;
         self.hash.entry(def_id)
                  .or_insert_with(|| {
                      let def_path = tcx.def_path(def_id);
-                     if !def_path.is_local() {
-                         return None;
-                     }
                      let index = paths.len() as u32;
                      paths.push(def_path);
-                     Some(DefPathIndex { index: index })
+                     DefPathIndex { index: index }
                  })
                  .clone()
     }
 
-    pub fn map(&mut self, node: DepNode<DefId>) -> Option<DepNode<DefPathIndex>> {
-        node.map_def(|&def_id| self.add(def_id))
+    pub fn map(&mut self, node: DepNode<DefId>) -> DepNode<DefPathIndex> {
+        node.map_def(|&def_id| Some(self.add(def_id))).unwrap()
     }
 
     pub fn into_directory(self) -> DefIdDirectory {
diff --git a/src/librustc_incremental/persist/hash.rs b/src/librustc_incremental/persist/hash.rs
new file mode 100644
index 00000000000..b729f25b873
--- /dev/null
+++ b/src/librustc_incremental/persist/hash.rs
@@ -0,0 +1,163 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use calculate_svh::SvhCalculate;
+use rbml::Error;
+use rbml::opaque::Decoder;
+use rustc::dep_graph::DepNode;
+use rustc::hir::def_id::DefId;
+use rustc::hir::svh::Svh;
+use rustc::ty::TyCtxt;
+use rustc_data_structures::fnv::FnvHashMap;
+use rustc_serialize::Decodable;
+use std::io::{ErrorKind, Read};
+use std::fs::File;
+use syntax::ast;
+
+use super::data::*;
+use super::util::*;
+
+pub struct HashContext<'a, 'tcx: 'a> {
+    pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    item_metadata_hashes: FnvHashMap<DefId, u64>,
+    crate_hashes: FnvHashMap<ast::CrateNum, Svh>,
+}
+
+impl<'a, 'tcx> HashContext<'a, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+        HashContext {
+            tcx: tcx,
+            item_metadata_hashes: FnvHashMap(),
+            crate_hashes: FnvHashMap(),
+        }
+    }
+
+    pub fn hash(&mut self, dep_node: DepNode<DefId>) -> Option<u64> {
+        match dep_node {
+            // HIR nodes (which always come from our crate) are an input:
+            DepNode::Hir(def_id) => {
+                assert!(def_id.is_local());
+                Some(self.hir_hash(def_id))
+            }
+
+            // MetaData from other crates is an *input* to us.
+            // MetaData nodes from *our* crates are an *output*; we
+            // don't hash them, but we do compute a hash for them and
+            // save it for others to use.
+            DepNode::MetaData(def_id) if !def_id.is_local() => {
+                Some(self.metadata_hash(def_id))
+            }
+
+            _ => {
+                // Other kinds of nodes represent computed by-products
+                // that we don't hash directly; instead, they should
+                // have some transitive dependency on a Hir or
+                // MetaData node, so we'll just hash that
+                None
+            }
+        }
+    }
+
+    fn hir_hash(&mut self, def_id: DefId) -> u64 {
+        assert!(def_id.is_local());
+        // FIXME(#32753) -- should we use a distinct hash here
+        self.tcx.calculate_item_hash(def_id)
+    }
+
+    fn metadata_hash(&mut self, def_id: DefId) -> u64 {
+        debug!("metadata_hash(def_id={:?})", def_id);
+
+        assert!(!def_id.is_local());
+        loop {
+            // check whether we have a result cached for this def-id
+            if let Some(&hash) = self.item_metadata_hashes.get(&def_id) {
+                debug!("metadata_hash: def_id={:?} hash={:?}", def_id, hash);
+                return hash;
+            }
+
+            // check whether we did not find detailed metadata for this
+            // krate; in that case, we just use the krate's overall hash
+            if let Some(&hash) = self.crate_hashes.get(&def_id.krate) {
+                debug!("metadata_hash: def_id={:?} crate_hash={:?}", def_id, hash);
+
+                // micro-"optimization": avoid a cache miss if we ask
+                // for metadata from this particular def-id again.
+                self.item_metadata_hashes.insert(def_id, hash.as_u64());
+
+                return hash.as_u64();
+            }
+
+            // otherwise, load the data and repeat.
+            self.load_data(def_id.krate);
+            assert!(self.crate_hashes.contains_key(&def_id.krate));
+        }
+    }
+
+    fn load_data(&mut self, cnum: ast::CrateNum) {
+        debug!("load_data(cnum={})", cnum);
+
+        let svh = self.tcx.sess.cstore.crate_hash(cnum);
+        let old = self.crate_hashes.insert(cnum, svh);
+        debug!("load_data: svh={}", svh);
+        assert!(old.is_none(), "loaded data for crate {:?} twice", cnum);
+
+        if let Some(path) = metadata_hash_path(self.tcx, cnum) {
+            debug!("load_data: path={:?}", path);
+            let mut data = vec![];
+            match
+                File::open(&path)
+                .and_then(|mut file| file.read_to_end(&mut data))
+            {
+                Ok(_) => {
+                    match self.load_from_data(cnum, &data) {
+                        Ok(()) => { }
+                        Err(err) => {
+                            bug!("decoding error in dep-graph from `{}`: {}",
+                                 path.display(), err);
+                        }
+                    }
+                }
+                Err(err) => {
+                    match err.kind() {
+                        ErrorKind::NotFound => {
+                            // If the file is not found, that's ok.
+                        }
+                        _ => {
+                            self.tcx.sess.err(
+                                &format!("could not load dep information from `{}`: {}",
+                                         path.display(), err));
+                            return;
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    fn load_from_data(&mut self, cnum: ast::CrateNum, data: &[u8]) -> Result<(), Error> {
+        debug!("load_from_data(cnum={})", cnum);
+
+        // Load up the hashes for the def-ids from this crate.
+        let mut decoder = Decoder::new(data, 0);
+        let serialized_hashes = try!(SerializedMetadataHashes::decode(&mut decoder));
+        for serialized_hash in serialized_hashes.hashes {
+            // the hashes are stored with just a def-index, which is
+            // always relative to the old crate; convert that to use
+            // our internal crate number
+            let def_id = DefId { krate: cnum, index: serialized_hash.def_index };
+
+            // record the hash for this dep-node
+            let old = self.item_metadata_hashes.insert(def_id, serialized_hash.hash);
+            debug!("load_from_data: def_id={:?} hash={}", def_id, serialized_hash.hash);
+            assert!(old.is_none(), "already have hash for {:?}", def_id);
+        }
+        Ok(())
+    }
+}
diff --git a/src/librustc_incremental/persist/load.rs b/src/librustc_incremental/persist/load.rs
index f9e479745d1..e3fd290443c 100644
--- a/src/librustc_incremental/persist/load.rs
+++ b/src/librustc_incremental/persist/load.rs
@@ -10,7 +10,6 @@
 
 //! Code to save/load the dep-graph from files.
 
-use calculate_svh::SvhCalculate;
 use rbml::Error;
 use rbml::opaque::Decoder;
 use rustc::dep_graph::DepNode;
@@ -25,6 +24,7 @@ use std::path::Path;
 use super::data::*;
 use super::directory::*;
 use super::dirty_clean;
+use super::hash::*;
 use super::util::*;
 
 type DirtyNodes = FnvHashSet<DepNode<DefId>>;
@@ -131,20 +131,20 @@ pub fn decode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 fn initial_dirty_nodes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 hashed_items: &[SerializedHash],
+                                 hashes: &[SerializedHash],
                                  retraced: &RetracedDefIdDirectory)
                                  -> DirtyNodes {
+    let mut hcx = HashContext::new(tcx);
     let mut items_removed = false;
     let mut dirty_nodes = FnvHashSet();
-    for hashed_item in hashed_items {
-        match retraced.def_id(hashed_item.index) {
-            Some(def_id) => {
-                // FIXME(#32753) -- should we use a distinct hash here
-                let current_hash = tcx.calculate_item_hash(def_id);
+    for hash in hashes {
+        match hash.node.map_def(|&i| retraced.def_id(i)) {
+            Some(dep_node) => {
+                let current_hash = hcx.hash(dep_node).unwrap();
                 debug!("initial_dirty_nodes: hash of {:?} is {:?}, was {:?}",
-                       def_id, current_hash, hashed_item.hash);
-                if current_hash != hashed_item.hash {
-                    dirty_nodes.insert(DepNode::Hir(def_id));
+                       dep_node, current_hash, hash.hash);
+                if current_hash != hash.hash {
+                    dirty_nodes.insert(dep_node);
                 }
             }
             None => {
diff --git a/src/librustc_incremental/persist/mod.rs b/src/librustc_incremental/persist/mod.rs
index 8d04fd30a19..72ccc29c97b 100644
--- a/src/librustc_incremental/persist/mod.rs
+++ b/src/librustc_incremental/persist/mod.rs
@@ -15,6 +15,7 @@
 mod data;
 mod directory;
 mod dirty_clean;
+mod hash;
 mod load;
 mod save;
 mod util;
diff --git a/src/librustc_incremental/persist/save.rs b/src/librustc_incremental/persist/save.rs
index cbb3464f3ef..7deb1ca36db 100644
--- a/src/librustc_incremental/persist/save.rs
+++ b/src/librustc_incremental/persist/save.rs
@@ -8,116 +8,115 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use calculate_svh::SvhCalculate;
 use rbml::opaque::Encoder;
 use rustc::dep_graph::DepNode;
+use rustc::middle::cstore::LOCAL_CRATE;
 use rustc::ty::TyCtxt;
 use rustc_serialize::{Encodable as RustcEncodable};
+use std::hash::{Hasher, SipHasher};
 use std::io::{self, Cursor, Write};
 use std::fs::{self, File};
+use std::path::PathBuf;
 
 use super::data::*;
 use super::directory::*;
+use super::hash::*;
 use super::util::*;
 
 pub fn save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     let _ignore = tcx.dep_graph.in_ignore();
+    let mut hcx = HashContext::new(tcx);
+    save_in(&mut hcx, dep_graph_path(tcx), encode_dep_graph);
+    save_in(&mut hcx, metadata_hash_path(tcx, LOCAL_CRATE), encode_metadata_hashes);
+}
 
-    if let Some(dep_graph) = dep_graph_path(tcx) {
-        // FIXME(#32754) lock file?
-
-        // delete the old dep-graph, if any
-        if dep_graph.exists() {
-            match fs::remove_file(&dep_graph) {
-                Ok(()) => { }
-                Err(err) => {
-                    tcx.sess.err(
-                        &format!("unable to delete old dep-graph at `{}`: {}",
-                                 dep_graph.display(), err));
-                    return;
-                }
-            }
-        }
+fn save_in<'a, 'tcx, F>(hcx: &mut HashContext<'a, 'tcx>,
+                        opt_path_buf: Option<PathBuf>,
+                        encode: F)
+    where F: FnOnce(&mut HashContext<'a, 'tcx>, &mut Encoder) -> io::Result<()>
+{
+    let tcx = hcx.tcx;
+
+    let path_buf = match opt_path_buf {
+        Some(p) => p,
+        None => return
+    };
+
+    // FIXME(#32754) lock file?
 
-        // generate the data in a memory buffer
-        let mut wr = Cursor::new(Vec::new());
-        match encode_dep_graph(tcx, &mut Encoder::new(&mut wr)) {
+    // delete the old dep-graph, if any
+    if path_buf.exists() {
+        match fs::remove_file(&path_buf) {
             Ok(()) => { }
             Err(err) => {
                 tcx.sess.err(
-                    &format!("could not encode dep-graph to `{}`: {}",
-                             dep_graph.display(), err));
+                    &format!("unable to delete old dep-graph at `{}`: {}",
+                             path_buf.display(), err));
                 return;
             }
         }
+    }
 
-        // write the data out
-        let data = wr.into_inner();
-        match
-            File::create(&dep_graph)
-            .and_then(|mut file| file.write_all(&data))
-        {
-            Ok(_) => { }
-            Err(err) => {
-                tcx.sess.err(
-                    &format!("failed to write dep-graph to `{}`: {}",
-                             dep_graph.display(), err));
-                return;
-            }
+    // generate the data in a memory buffer
+    let mut wr = Cursor::new(Vec::new());
+    match encode(hcx, &mut Encoder::new(&mut wr)) {
+        Ok(()) => { }
+        Err(err) => {
+            tcx.sess.err(
+                &format!("could not encode dep-graph to `{}`: {}",
+                         path_buf.display(), err));
+            return;
+        }
+    }
+
+    // write the data out
+    let data = wr.into_inner();
+    match
+        File::create(&path_buf)
+        .and_then(|mut file| file.write_all(&data))
+    {
+        Ok(_) => { }
+        Err(err) => {
+            tcx.sess.err(
+                &format!("failed to write dep-graph to `{}`: {}",
+                         path_buf.display(), err));
+            return;
         }
     }
 }
 
-pub fn encode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+pub fn encode_dep_graph<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
                                   encoder: &mut Encoder)
-                                  -> io::Result<()> {
-    // Here we take advantage of how RBML allows us to skip around
-    // and encode the depgraph as a two-part structure:
-    //
-    // ```
-    // <dep-graph>[SerializedDepGraph]</dep-graph> // tag 0
-    // <directory>[DefIdDirectory]</directory>     // tag 1
-    // ```
-    //
-    // Then later we can load the directory by skipping to find tag 1.
-
+                                  -> io::Result<()>
+{
+    let tcx = hcx.tcx;
     let query = tcx.dep_graph.query();
 
     let mut builder = DefIdDirectoryBuilder::new(tcx);
 
-    // Create hashes for things we can persist.
+    // Create hashes for inputs.
     let hashes =
         query.nodes()
              .into_iter()
-             .filter_map(|dep_node| match dep_node {
-                 DepNode::Hir(def_id) => {
-                     assert!(def_id.is_local());
-                     builder.add(def_id)
-                            .map(|index| {
-                                // FIXME(#32753) -- should we use a distinct hash here
-                                let hash = tcx.calculate_item_hash(def_id);
-                                SerializedHash { index: index, hash: hash }
-                            })
-                 }
-                 _ => None
+             .filter_map(|dep_node| {
+                 hcx.hash(dep_node)
+                    .map(|hash| {
+                        let node = builder.map(dep_node);
+                        SerializedHash { node: node, hash: hash }
+                    })
              })
              .collect();
 
-    // Create the serialized dep-graph, dropping nodes that are
-    // from other crates or from inlined items.
-    //
-    // FIXME(#32015) fix handling of other crates
+    // Create the serialized dep-graph.
     let graph = SerializedDepGraph {
         nodes: query.nodes().into_iter()
-                            .flat_map(|node| builder.map(node))
+                            .map(|node| builder.map(node))
                             .collect(),
         edges: query.edges().into_iter()
-                            .flat_map(|(source_node, target_node)| {
-                                builder.map(source_node)
-                                       .and_then(|source| {
-                                           builder.map(target_node)
-                                                  .map(|target| (source, target))
-                                       })
+                            .map(|(source_node, target_node)| {
+                                let source = builder.map(source_node);
+                                let target = builder.map(target_node);
+                                (source, target)
                             })
                             .collect(),
         hashes: hashes,
@@ -133,3 +132,63 @@ pub fn encode_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     Ok(())
 }
 
+pub fn encode_metadata_hashes<'a, 'tcx>(hcx: &mut HashContext<'a, 'tcx>,
+                                        encoder: &mut Encoder)
+                                        -> io::Result<()>
+{
+    let tcx = hcx.tcx;
+    let query = tcx.dep_graph.query();
+
+    let serialized_hashes = {
+        // Identify the `MetaData(X)` nodes where `X` is local. These are
+        // the metadata items we export. Downstream crates will want to
+        // see a hash that tells them whether we might have changed the
+        // metadata for a given item since they last compiled.
+        let meta_data_def_ids =
+            query.nodes()
+                 .into_iter()
+                 .filter_map(|dep_node| match dep_node {
+                     DepNode::MetaData(def_id) if def_id.is_local() => Some(def_id),
+                     _ => None,
+                 });
+
+        // To create the hash for each item `X`, we don't hash the raw
+        // bytes of the metadata (though in principle we
+        // could). Instead, we walk the predecessors of `MetaData(X)`
+        // from the dep-graph. This corresponds to all the inputs that
+        // were read to construct the metadata. To create the hash for
+        // the metadata, we hash (the hash of) all of those inputs.
+        let hashes =
+            meta_data_def_ids
+            .map(|def_id| {
+                assert!(def_id.is_local());
+                let dep_node = DepNode::MetaData(def_id);
+                let mut state = SipHasher::new();
+                debug!("save: computing metadata hash for {:?}", dep_node);
+                for node in query.transitive_predecessors(dep_node) {
+                    if let Some(hash) = hcx.hash(node) {
+                        debug!("save: predecessor {:?} has hash {}", node, hash);
+                        state.write_u64(hash.to_le());
+                    } else {
+                        debug!("save: predecessor {:?} cannot be hashed", node);
+                    }
+                }
+                let hash = state.finish();
+                debug!("save: metadata hash for {:?} is {}", dep_node, hash);
+                SerializedMetadataHash {
+                    def_index: def_id.index,
+                    hash: hash,
+                }
+            });
+
+        // Collect these up into a vector.
+        SerializedMetadataHashes {
+            hashes: hashes.collect()
+        }
+    };
+
+    // Encode everything.
+    try!(serialized_hashes.encode(encoder));
+
+    Ok(())
+}
diff --git a/src/librustc_incremental/persist/util.rs b/src/librustc_incremental/persist/util.rs
index 8ebcbc0466f..a77a9607e77 100644
--- a/src/librustc_incremental/persist/util.rs
+++ b/src/librustc_incremental/persist/util.rs
@@ -8,13 +8,23 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use rustc::middle::cstore::LOCAL_CRATE;
 use rustc::ty::TyCtxt;
 
 use std::fs;
 use std::io;
-use std::path::{PathBuf, Path};
+use std::path::{Path, PathBuf};
+use syntax::ast;
 
 pub fn dep_graph_path(tcx: TyCtxt) -> Option<PathBuf> {
+    path(tcx, LOCAL_CRATE, "local")
+}
+
+pub fn metadata_hash_path(tcx: TyCtxt, cnum: ast::CrateNum) -> Option<PathBuf> {
+    path(tcx, cnum, "metadata")
+}
+
+fn path(tcx: TyCtxt, cnum: ast::CrateNum, suffix: &str) -> Option<PathBuf> {
     // For now, just save/load dep-graph from
     // directory/dep_graph.rbml
     tcx.sess.opts.incremental.as_ref().and_then(|incr_dir| {
@@ -28,7 +38,13 @@ pub fn dep_graph_path(tcx: TyCtxt) -> Option<PathBuf> {
             }
         }
 
-        Some(incr_dir.join("dep_graph.rbml"))
+        let crate_name = tcx.crate_name(cnum);
+        let crate_disambiguator = tcx.crate_disambiguator(cnum);
+        let file_name = format!("{}-{}.{}.bin",
+                                crate_name,
+                                crate_disambiguator,
+                                suffix);
+        Some(incr_dir.join(file_name))
     })
 }
 
@@ -52,3 +68,4 @@ fn create_dir_racy(path: &Path) -> io::Result<()> {
         Err(e) => Err(e),
     }
 }
+
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index f4fb226d352..27a6e433c73 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -277,7 +277,7 @@ impl LateLintPass for NonSnakeCase {
         if let &PatKind::Ident(_, ref path1, _) = &p.node {
             let def = cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def());
             if let Some(Def::Local(..)) = def {
-                self.check_snake_case(cx, "variable", &path1.node.name.as_str(), Some(p.span));
+                self.check_snake_case(cx, "variable", &path1.node.as_str(), Some(p.span));
             }
         }
     }
@@ -363,7 +363,7 @@ impl LateLintPass for NonUpperCaseGlobals {
         match (&p.node, cx.tcx.def_map.borrow().get(&p.id).map(|d| d.full_def())) {
             (&PatKind::Ident(_, ref path1, _), Some(Def::Const(..))) => {
                 NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
-                                                      path1.node.name, p.span);
+                                                      path1.node, p.span);
             }
             _ => {}
         }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index d1eba5b3f4a..49b59aea46e 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -172,7 +172,7 @@ impl LateLintPass for NonShorthandFieldPatterns {
             });
             for fieldpat in field_pats {
                 if let PatKind::Ident(_, ident, None) = fieldpat.node.pat.node {
-                    if ident.node.unhygienic_name == fieldpat.node.name {
+                    if ident.node.unhygienize() == fieldpat.node.name {
                         cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span,
                                      &format!("the `{}:` in this pattern is redundant and can \
                                               be removed", ident.node))
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index e0abe1aebd2..9fca6d3d201 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -197,7 +197,11 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
         FutureIncompatibleInfo {
             id: LintId::of(OBJECT_UNSAFE_FRAGMENT),
             reference: "issue #33243 <https://github.com/rust-lang/rust/issues/33243>",
-        }
+        },
+        FutureIncompatibleInfo {
+            id: LintId::of(HR_LIFETIME_IN_ASSOC_TYPE),
+            reference: "issue #33685 <https://github.com/rust-lang/rust/issues/33685>",
+        },
         ]);
 
     // We have one lint pass defined specially
diff --git a/src/librustc_metadata/common.rs b/src/librustc_metadata/common.rs
index 4bf428ef46d..2b972af07ff 100644
--- a/src/librustc_metadata/common.rs
+++ b/src/librustc_metadata/common.rs
@@ -247,8 +247,7 @@ pub const tag_rustc_version: usize = 0x10f;
 pub fn rustc_version() -> String {
     format!(
         "rustc {}",
-//        option_env!("CFG_VERSION").unwrap_or("unknown version")
-        "nightly edition"
+        option_env!("CFG_VERSION").unwrap_or("unknown version")
     )
 }
 
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 63c6af704bb..aac68cc09bc 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -319,6 +319,7 @@ impl<'a> CrateReader<'a> {
             extern_crate: Cell::new(None),
             index: decoder::load_index(metadata.as_slice()),
             xref_index: decoder::load_xrefs(metadata.as_slice()),
+            key_map: decoder::load_key_map(metadata.as_slice()),
             data: metadata,
             cnum_map: RefCell::new(cnum_map),
             cnum: cnum,
@@ -743,6 +744,7 @@ impl<'a> CrateReader<'a> {
             match *ct {
                 config::CrateTypeExecutable => need_exe_alloc = true,
                 config::CrateTypeDylib |
+                config::CrateTypeCdylib |
                 config::CrateTypeStaticlib => need_lib_alloc = true,
                 config::CrateTypeRlib => {}
             }
diff --git a/src/librustc_metadata/csearch.rs b/src/librustc_metadata/csearch.rs
index 8d464099783..b87b5492f04 100644
--- a/src/librustc_metadata/csearch.rs
+++ b/src/librustc_metadata/csearch.rs
@@ -20,7 +20,9 @@ use middle::lang_items;
 use rustc::ty::{self, Ty, TyCtxt, VariantKind};
 use rustc::hir::def_id::{DefId, DefIndex, CRATE_DEF_INDEX};
 
+use rustc::dep_graph::DepNode;
 use rustc::hir::map as hir_map;
+use rustc::hir::map::DefKey;
 use rustc::mir::repr::Mir;
 use rustc::mir::mir_map::MirMap;
 use rustc::util::nodemap::{FnvHashMap, NodeMap, NodeSet, DefIdMap};
@@ -37,19 +39,20 @@ use rustc_back::target::Target;
 use rustc::hir;
 
 impl<'tcx> CrateStore<'tcx> for cstore::CStore {
-    fn stability(&self, def: DefId) -> Option<attr::Stability>
-    {
+    fn stability(&self, def: DefId) -> Option<attr::Stability> {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_stability(&cdata, def.index)
     }
 
-    fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>
-    {
+    fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_deprecation(&cdata, def.index)
     }
 
     fn visibility(&self, def: DefId) -> ty::Visibility {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_visibility(&cdata, def.index)
     }
@@ -57,23 +60,26 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind
     {
         assert!(!def_id.is_local());
+        self.dep_graph.read(DepNode::MetaData(def_id));
         let cdata = self.get_crate_data(def_id.krate);
         decoder::closure_kind(&cdata, def_id.index)
     }
 
-    fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx>
-    {
+    fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> {
         assert!(!def_id.is_local());
+        self.dep_graph.read(DepNode::MetaData(def_id));
         let cdata = self.get_crate_data(def_id.krate);
         decoder::closure_ty(&cdata, def_id.index, tcx)
     }
 
     fn item_variances(&self, def: DefId) -> ty::ItemVariances {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_item_variances(&cdata, def.index)
     }
 
     fn repr_attrs(&self, def: DefId) -> Vec<attr::ReprAttr> {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_repr_attrs(&cdata, def.index)
     }
@@ -81,6 +87,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                      -> ty::TypeScheme<'tcx>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_type(&cdata, def.index, tcx)
     }
@@ -88,6 +95,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                            -> ty::GenericPredicates<'tcx>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_predicates(&cdata, def.index, tcx)
     }
@@ -95,41 +103,48 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                                  -> ty::GenericPredicates<'tcx>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_super_predicates(&cdata, def.index, tcx)
     }
 
     fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
     {
+        self.dep_graph.read(DepNode::MetaData(def_id));
         let cdata = self.get_crate_data(def_id.krate);
         decoder::get_item_attrs(&cdata, def_id.index)
     }
 
     fn item_symbol(&self, def: DefId) -> String
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_symbol(&cdata, def.index)
     }
 
     fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TraitDef<'tcx>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_trait_def(&cdata, def.index, tcx)
     }
 
     fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::AdtDefMaster<'tcx>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_adt_def(&self.intr, &cdata, def.index, tcx)
     }
 
     fn method_arg_names(&self, did: DefId) -> Vec<String>
     {
+        self.dep_graph.read(DepNode::MetaData(did));
         let cdata = self.get_crate_data(did.krate);
         decoder::get_method_arg_names(&cdata, did.index)
     }
 
     fn item_name(&self, def: DefId) -> ast::Name {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_item_name(&self.intr, &cdata, def.index)
     }
@@ -137,6 +152,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
 
     fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId>
     {
+        self.dep_graph.read(DepNode::MetaData(def_id));
         let mut result = vec![];
         let cdata = self.get_crate_data(def_id.krate);
         decoder::each_inherent_implementation_for_type(&cdata, def_id.index,
@@ -146,6 +162,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
 
     fn implementations_of_trait(&self, def_id: DefId) -> Vec<DefId>
     {
+        self.dep_graph.read(DepNode::MetaData(def_id));
         let mut result = vec![];
         self.iter_crate_data(|_, cdata| {
             decoder::each_implementation_for_trait(cdata, def_id, &mut |iid| {
@@ -158,6 +175,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     fn provided_trait_methods<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                                   -> Vec<Rc<ty::Method<'tcx>>>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_provided_trait_methods(self.intr.clone(), &cdata, def.index, tcx)
     }
@@ -165,18 +183,21 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     fn trait_item_def_ids(&self, def: DefId)
                           -> Vec<ty::ImplOrTraitItemId>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_trait_item_def_ids(&cdata, def.index)
     }
 
     fn impl_items(&self, impl_def_id: DefId) -> Vec<ty::ImplOrTraitItemId>
     {
+        self.dep_graph.read(DepNode::MetaData(impl_def_id));
         let cdata = self.get_crate_data(impl_def_id.krate);
         decoder::get_impl_items(&cdata, impl_def_id.index)
     }
 
     fn impl_polarity(&self, def: DefId) -> Option<hir::ImplPolarity>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_impl_polarity(&cdata, def.index)
     }
@@ -184,6 +205,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                           -> Option<ty::TraitRef<'tcx>>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_impl_trait(&cdata, def.index, tcx)
     }
@@ -191,6 +213,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     fn custom_coerce_unsized_kind(&self, def: DefId)
                                   -> Option<ty::adjustment::CustomCoerceUnsized>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_custom_coerce_unsized_kind(&cdata, def.index)
     }
@@ -198,17 +221,20 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     // FIXME: killme
     fn associated_consts<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                              -> Vec<Rc<ty::AssociatedConst<'tcx>>> {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_associated_consts(self.intr.clone(), &cdata, def.index, tcx)
     }
 
     fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
+        self.dep_graph.read(DepNode::MetaData(impl_def));
         let cdata = self.get_crate_data(impl_def.krate);
         decoder::get_parent_impl(&*cdata, impl_def.index)
     }
 
     fn trait_of_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option<DefId>
     {
+        self.dep_graph.read(DepNode::MetaData(def_id));
         let cdata = self.get_crate_data(def_id.krate);
         decoder::get_trait_of_item(&cdata, def_id.index, tcx)
     }
@@ -216,6 +242,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     fn impl_or_trait_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                               -> Option<ty::ImplOrTraitItem<'tcx>>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_impl_or_trait_item(
             self.intr.clone(),
@@ -226,34 +253,40 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
 
     fn is_const_fn(&self, did: DefId) -> bool
     {
+        self.dep_graph.read(DepNode::MetaData(did));
         let cdata = self.get_crate_data(did.krate);
         decoder::is_const_fn(&cdata, did.index)
     }
 
     fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool
     {
+        self.dep_graph.read(DepNode::MetaData(trait_def_id));
         let cdata = self.get_crate_data(trait_def_id.krate);
         decoder::is_defaulted_trait(&cdata, trait_def_id.index)
     }
 
     fn is_impl(&self, did: DefId) -> bool
     {
+        self.dep_graph.read(DepNode::MetaData(did));
         let cdata = self.get_crate_data(did.krate);
         decoder::is_impl(&cdata, did.index)
     }
 
     fn is_default_impl(&self, impl_did: DefId) -> bool {
+        self.dep_graph.read(DepNode::MetaData(impl_did));
         let cdata = self.get_crate_data(impl_did.krate);
         decoder::is_default_impl(&cdata, impl_did.index)
     }
 
     fn is_extern_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, did: DefId) -> bool {
+        self.dep_graph.read(DepNode::MetaData(did));
         let cdata = self.get_crate_data(did.krate);
         decoder::is_extern_item(&cdata, did.index, tcx)
     }
 
     fn is_static_method(&self, def: DefId) -> bool
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::is_static_method(&cdata, def.index)
     }
@@ -264,6 +297,7 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     }
 
     fn is_typedef(&self, did: DefId) -> bool {
+        self.dep_graph.read(DepNode::MetaData(did));
         let cdata = self.get_crate_data(did.krate);
         decoder::is_typedef(&cdata, did.index)
     }
@@ -375,44 +409,59 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
         decoder::get_reachable_ids(&cdata)
     }
 
+    fn def_index_for_def_key(&self,
+                             cnum: ast::CrateNum,
+                             def: DefKey)
+                             -> Option<DefIndex> {
+        let cdata = self.get_crate_data(cnum);
+        cdata.key_map.get(&def).cloned()
+    }
+
     /// Returns the `DefKey` for a given `DefId`. This indicates the
     /// parent `DefId` as well as some idea of what kind of data the
     /// `DefId` refers to.
     fn def_key(&self, def: DefId) -> hir_map::DefKey {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::def_key(&cdata, def.index)
     }
 
     fn relative_def_path(&self, def: DefId) -> hir_map::DefPath {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::def_path(&cdata, def.index)
     }
 
     fn variant_kind(&self, def_id: DefId) -> Option<VariantKind> {
+        self.dep_graph.read(DepNode::MetaData(def_id));
         let cdata = self.get_crate_data(def_id.krate);
         decoder::get_variant_kind(&cdata, def_id.index)
     }
 
     fn struct_ctor_def_id(&self, struct_def_id: DefId) -> Option<DefId>
     {
+        self.dep_graph.read(DepNode::MetaData(struct_def_id));
         let cdata = self.get_crate_data(struct_def_id.krate);
         decoder::get_struct_ctor_def_id(&cdata, struct_def_id.index)
     }
 
     fn tuple_struct_definition_if_ctor(&self, did: DefId) -> Option<DefId>
     {
+        self.dep_graph.read(DepNode::MetaData(did));
         let cdata = self.get_crate_data(did.krate);
         decoder::get_tuple_struct_definition_if_ctor(&cdata, did.index)
     }
 
     fn struct_field_names(&self, def: DefId) -> Vec<ast::Name>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::get_struct_field_names(&self.intr, &cdata, def.index)
     }
 
     fn item_children(&self, def_id: DefId) -> Vec<ChildItem>
     {
+        self.dep_graph.read(DepNode::MetaData(def_id));
         let mut result = vec![];
         let crate_data = self.get_crate_data(def_id.krate);
         let get_crate_data = |cnum| self.get_crate_data(cnum);
@@ -445,17 +494,20 @@ impl<'tcx> CrateStore<'tcx> for cstore::CStore {
     fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                               -> FoundAst<'tcx>
     {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::maybe_get_item_ast(&cdata, tcx, def.index)
     }
 
     fn maybe_get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
                               -> Option<Mir<'tcx>> {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::maybe_get_item_mir(&cdata, tcx, def.index)
     }
 
     fn is_item_mir_available(&self, def: DefId) -> bool {
+        self.dep_graph.read(DepNode::MetaData(def));
         let cdata = self.get_crate_data(def.krate);
         decoder::is_item_mir_available(&cdata, def.index)
     }
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 04b6e1c42b9..2e1bdf21c9a 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -20,7 +20,9 @@ use decoder;
 use index;
 use loader;
 
-use rustc::hir::def_id::DefId;
+use rustc::dep_graph::DepGraph;
+use rustc::hir::def_id::{DefIndex, DefId};
+use rustc::hir::map::DefKey;
 use rustc::hir::svh::Svh;
 use rustc::middle::cstore::{ExternCrate};
 use rustc::session::config::PanicStrategy;
@@ -78,6 +80,13 @@ pub struct crate_metadata {
     pub index: index::Index,
     pub xref_index: index::DenseIndex,
 
+    /// For each public item in this crate, we encode a key.  When the
+    /// crate is loaded, we read all the keys and put them in this
+    /// hashmap, which gives the reverse mapping.  This allows us to
+    /// quickly retrace a `DefPath`, which is needed for incremental
+    /// compilation support.
+    pub key_map: FnvHashMap<DefKey, DefIndex>,
+
     /// Flag if this crate is required by an rlib version of this crate, or in
     /// other words whether it was explicitly linked to. An example of a crate
     /// where this is false is when an allocator crate is injected into the
@@ -86,6 +95,7 @@ pub struct crate_metadata {
 }
 
 pub struct CStore {
+    pub dep_graph: DepGraph,
     metas: RefCell<FnvHashMap<ast::CrateNum, Rc<crate_metadata>>>,
     /// Map from NodeId's of local extern crate statements to crate numbers
     extern_mod_crate_map: RefCell<NodeMap<ast::CrateNum>>,
@@ -98,8 +108,10 @@ pub struct CStore {
 }
 
 impl CStore {
-    pub fn new(intr: Rc<IdentInterner>) -> CStore {
+    pub fn new(dep_graph: &DepGraph,
+               intr: Rc<IdentInterner>) -> CStore {
         CStore {
+            dep_graph: dep_graph.clone(),
             metas: RefCell::new(FnvHashMap()),
             extern_mod_crate_map: RefCell::new(FnvHashMap()),
             used_crate_sources: RefCell::new(Vec::new()),
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index e233dda7e91..b6f35074b7d 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -25,6 +25,7 @@ use tydecode::TyDecoder;
 
 use rustc::hir::svh::Svh;
 use rustc::hir::map as hir_map;
+use rustc::hir::map::DefKey;
 use rustc::util::nodemap::FnvHashMap;
 use rustc::hir;
 use rustc::session::config::PanicStrategy;
@@ -71,7 +72,10 @@ impl crate_metadata {
 
     fn lookup_item(&self, item_id: DefIndex) -> rbml::Doc {
         match self.get_item(item_id) {
-            None => bug!("lookup_item: id not found: {:?}", item_id),
+            None => bug!("lookup_item: id not found: {:?} in crate {:?} with number {}",
+                         item_id,
+                         self.name,
+                         self.cnum),
             Some(d) => d
         }
     }
@@ -92,6 +96,29 @@ pub fn load_xrefs(data: &[u8]) -> index::DenseIndex {
     index::DenseIndex::from_buf(index.data, index.start, index.end)
 }
 
+// Go through each item in the metadata and create a map from that
+// item's def-key to the item's DefIndex.
+pub fn load_key_map(data: &[u8]) -> FnvHashMap<DefKey, DefIndex> {
+    let root_doc = rbml::Doc::new(data);
+    let items_doc = reader::get_doc(root_doc, tag_items);
+    let items_data_doc = reader::get_doc(items_doc, tag_items_data);
+    reader::docs(items_data_doc)
+        .filter(|&(tag, _)| tag == tag_items_data_item)
+        .map(|(_, item_doc)| {
+            // load def-key from item
+            let key = item_def_key(item_doc);
+
+            // load def-index from item; we only encode the full def-id,
+            // so just pull out the index
+            let def_id_doc = reader::get_doc(item_doc, tag_def_id);
+            let def_id = untranslated_def_id(def_id_doc);
+            assert!(def_id.is_local()); // local to the crate we are decoding, that is
+
+            (key, def_id.index)
+        })
+        .collect()
+}
+
 #[derive(Clone, Copy, Debug, PartialEq)]
 enum Family {
     ImmStatic,             // c
@@ -190,10 +217,14 @@ fn item_symbol(item: rbml::Doc) -> String {
     reader::get_doc(item, tag_items_data_item_symbol).as_str().to_string()
 }
 
-fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId {
+fn untranslated_def_id(d: rbml::Doc) -> DefId {
     let id = reader::doc_as_u64(d);
     let index = DefIndex::new((id & 0xFFFF_FFFF) as usize);
-    let def_id = DefId { krate: (id >> 32) as u32, index: index };
+    DefId { krate: (id >> 32) as u32, index: index }
+}
+
+fn translated_def_id(cdata: Cmd, d: rbml::Doc) -> DefId {
+    let def_id = untranslated_def_id(d);
     translate_def_id(cdata, def_id)
 }
 
@@ -1248,7 +1279,7 @@ pub fn get_crate_deps(data: &[u8]) -> Vec<CrateDep> {
 
     reader::tagged_docs(depsdoc, tag_crate_dep).enumerate().map(|(crate_num, depdoc)| {
         let name = docstr(depdoc, tag_crate_dep_crate_name);
-        let hash = Svh::new(docstr(depdoc, tag_crate_dep_hash));
+        let hash = Svh::new(reader::doc_as_u64(reader::get_doc(depdoc, tag_crate_dep_hash)));
         let doc = reader::get_doc(depdoc, tag_crate_dep_explicitly_linked);
         let explicitly_linked = reader::doc_as_u8(doc) != 0;
         CrateDep {
@@ -1272,14 +1303,14 @@ fn list_crate_deps(data: &[u8], out: &mut io::Write) -> io::Result<()> {
 pub fn maybe_get_crate_hash(data: &[u8]) -> Option<Svh> {
     let cratedoc = rbml::Doc::new(data);
     reader::maybe_get_doc(cratedoc, tag_crate_hash).map(|doc| {
-        Svh::new(doc.as_str_slice().to_string())
+        Svh::new(reader::doc_as_u64(doc))
     })
 }
 
 pub fn get_crate_hash(data: &[u8]) -> Svh {
     let cratedoc = rbml::Doc::new(data);
     let hashdoc = reader::get_doc(cratedoc, tag_crate_hash);
-    Svh::new(hashdoc.as_str_slice().to_string())
+    Svh::new(reader::doc_as_u64(hashdoc))
 }
 
 pub fn maybe_get_crate_name(data: &[u8]) -> Option<&str> {
@@ -1747,6 +1778,10 @@ pub fn closure_ty<'a, 'tcx>(cdata: Cmd, closure_id: DefIndex, tcx: TyCtxt<'a, 't
 pub fn def_key(cdata: Cmd, id: DefIndex) -> hir_map::DefKey {
     debug!("def_key: id={:?}", id);
     let item_doc = cdata.lookup_item(id);
+    item_def_key(item_doc)
+}
+
+fn item_def_key(item_doc: rbml::Doc) -> hir_map::DefKey {
     match reader::maybe_get_doc(item_doc, tag_def_key) {
         Some(def_key_doc) => {
             let mut decoder = reader::Decoder::new(def_key_doc);
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index 020f12d753e..928601095b0 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -25,6 +25,7 @@ use middle::cstore::{LOCAL_CRATE, InlinedItemRef, LinkMeta, tls};
 use rustc::hir::def;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use middle::dependency_format::Linkage;
+use rustc::dep_graph::{DepGraph, DepNode, DepTask};
 use rustc::ty::subst;
 use rustc::traits::specialization_graph;
 use rustc::ty::{self, Ty, TyCtxt};
@@ -76,15 +77,23 @@ impl<'a, 'tcx> EncodeContext<'a,'tcx> {
 #[derive(PartialEq, Eq, Hash)]
 pub enum XRef<'tcx> { Predicate(ty::Predicate<'tcx>) }
 
-struct CrateIndex<'tcx> {
+struct CrateIndex<'a, 'tcx> {
+    dep_graph: &'a DepGraph,
     items: IndexData,
     xrefs: FnvHashMap<XRef<'tcx>, u32>, // sequentially-assigned
 }
 
-impl<'tcx> CrateIndex<'tcx> {
-    fn record(&mut self, id: DefId, rbml_w: &mut Encoder) {
+impl<'a, 'tcx> CrateIndex<'a, 'tcx> {
+    /// Records that `id` is being emitted at the current offset.
+    /// This data is later used to construct the item index in the
+    /// metadata so we can quickly find the data for a given item.
+    ///
+    /// Returns a dep-graph task that you should keep live as long as
+    /// the data for this item is being emitted.
+    fn record(&mut self, id: DefId, rbml_w: &mut Encoder) -> DepTask<'a> {
         let position = rbml_w.mark_stable_position();
         self.items.record(id, position);
+        self.dep_graph.in_task(DepNode::MetaData(id))
     }
 
     fn add_xref(&mut self, xref: XRef<'tcx>) -> u32 {
@@ -154,7 +163,7 @@ fn encode_item_variances(rbml_w: &mut Encoder,
 
 fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder,
                                              ecx: &EncodeContext<'a, 'tcx>,
-                                             index: &mut CrateIndex<'tcx>,
+                                             index: &mut CrateIndex<'a, 'tcx>,
                                              id: NodeId) {
     encode_bounds_and_type(rbml_w,
                            ecx,
@@ -165,7 +174,7 @@ fn encode_bounds_and_type_for_item<'a, 'tcx>(rbml_w: &mut Encoder,
 
 fn encode_bounds_and_type<'a, 'tcx>(rbml_w: &mut Encoder,
                                     ecx: &EncodeContext<'a, 'tcx>,
-                                    index: &mut CrateIndex<'tcx>,
+                                    index: &mut CrateIndex<'a, 'tcx>,
                                     scheme: &ty::TypeScheme<'tcx>,
                                     predicates: &ty::GenericPredicates<'tcx>) {
     encode_generics(rbml_w, ecx, index,
@@ -248,7 +257,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                       rbml_w: &mut Encoder,
                                       did: DefId,
                                       vis: &hir::Visibility,
-                                      index: &mut CrateIndex<'tcx>) {
+                                      index: &mut CrateIndex<'a, 'tcx>) {
     debug!("encode_enum_variant_info(did={:?})", did);
     let repr_hints = ecx.tcx.lookup_repr_hints(did);
     let repr_type = ecx.tcx.enum_repr_type(repr_hints.get(0));
@@ -258,15 +267,11 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         let vid = variant.did;
         let variant_node_id = ecx.local_id(vid);
 
-        if let ty::VariantKind::Struct = variant.kind() {
-            // tuple-like enum variant fields aren't really items so
-            // don't try to encode them.
-            for field in &variant.fields {
-                encode_field(ecx, rbml_w, field, index);
-            }
+        for field in &variant.fields {
+            encode_field(ecx, rbml_w, field, index);
         }
 
-        index.record(vid, rbml_w);
+        let _task = index.record(vid, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id_and_key(ecx, rbml_w, vid);
         encode_family(rbml_w, match variant.kind() {
@@ -297,6 +302,7 @@ fn encode_enum_variant_info<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         encode_bounds_and_type_for_item(rbml_w, ecx, index, variant_node_id);
 
         rbml_w.end_tag();
+
         disr_val = disr_val.wrap_incr();
     }
 }
@@ -471,11 +477,11 @@ fn encode_item_sort(rbml_w: &mut Encoder, sort: char) {
 fn encode_field<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                           rbml_w: &mut Encoder,
                           field: ty::FieldDef<'tcx>,
-                          index: &mut CrateIndex<'tcx>) {
+                          index: &mut CrateIndex<'a, 'tcx>) {
     let nm = field.name;
     let id = ecx.local_id(field.did);
 
-    index.record(field.did, rbml_w);
+    let _task = index.record(field.did, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
     debug!("encode_field: encoding {} {}", nm, id);
     encode_struct_field_family(rbml_w, field.vis);
@@ -495,12 +501,12 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                          rbml_w: &mut Encoder,
                                          name: Name,
                                          struct_def: &hir::VariantData,
-                                         index: &mut CrateIndex<'tcx>,
+                                         index: &mut CrateIndex<'a, 'tcx>,
                                          struct_id: NodeId) {
     let ctor_id = struct_def.id();
     let ctor_def_id = ecx.tcx.map.local_def_id(ctor_id);
 
-    index.record(ctor_def_id, rbml_w);
+    let _task = index.record(ctor_def_id, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
     encode_def_id_and_key(ecx, rbml_w, ctor_def_id);
     encode_family(rbml_w, match *struct_def {
@@ -531,7 +537,7 @@ fn encode_info_for_struct_ctor<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
 fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
                              ecx: &EncodeContext<'a, 'tcx>,
-                             index: &mut CrateIndex<'tcx>,
+                             index: &mut CrateIndex<'a, 'tcx>,
                              generics: &ty::Generics<'tcx>,
                              predicates: &ty::GenericPredicates<'tcx>,
                              tag: usize)
@@ -576,7 +582,7 @@ fn encode_generics<'a, 'tcx>(rbml_w: &mut Encoder,
 
 fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder,
                                              _ecx: &EncodeContext<'a,'tcx>,
-                                             index: &mut CrateIndex<'tcx>,
+                                             index: &mut CrateIndex<'a, 'tcx>,
                                              predicates: &ty::GenericPredicates<'tcx>)
 {
     for (space, _, predicate) in predicates.predicates.iter_enumerated() {
@@ -593,7 +599,7 @@ fn encode_predicates_in_current_doc<'a,'tcx>(rbml_w: &mut Encoder,
 
 fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder,
                               ecx: &EncodeContext<'a,'tcx>,
-                              index: &mut CrateIndex<'tcx>,
+                              index: &mut CrateIndex<'a, 'tcx>,
                               predicates: &ty::GenericPredicates<'tcx>,
                               tag: usize)
 {
@@ -604,7 +610,7 @@ fn encode_predicates<'a,'tcx>(rbml_w: &mut Encoder,
 
 fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                      rbml_w: &mut Encoder,
-                                     index: &mut CrateIndex<'tcx>,
+                                     index: &mut CrateIndex<'a, 'tcx>,
                                      method_ty: &ty::Method<'tcx>) {
     encode_def_id_and_key(ecx, rbml_w, method_ty.def_id);
     encode_name(rbml_w, method_ty.name);
@@ -623,7 +629,7 @@ fn encode_method_ty_fields<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
 fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                               rbml_w: &mut Encoder,
-                                              index: &mut CrateIndex<'tcx>,
+                                              index: &mut CrateIndex<'a, 'tcx>,
                                               associated_const: &ty::AssociatedConst,
                                               parent_id: NodeId,
                                               impl_item_opt: Option<&hir::ImplItem>) {
@@ -631,7 +637,7 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
            associated_const.def_id,
            associated_const.name);
 
-    index.record(associated_const.def_id, rbml_w);
+    let _task = index.record(associated_const.def_id, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
 
     encode_def_id_and_key(ecx, rbml_w, associated_const.def_id);
@@ -665,7 +671,7 @@ fn encode_info_for_associated_const<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
 fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                     rbml_w: &mut Encoder,
-                                    index: &mut CrateIndex<'tcx>,
+                                    index: &mut CrateIndex<'a, 'tcx>,
                                     m: &ty::Method<'tcx>,
                                     is_default_impl: bool,
                                     parent_id: NodeId,
@@ -673,7 +679,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
     debug!("encode_info_for_method: {:?} {:?}", m.def_id,
            m.name);
-    index.record(m.def_id, rbml_w);
+    let _task = index.record(m.def_id, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
 
     encode_method_ty_fields(ecx, rbml_w, index, m);
@@ -717,7 +723,7 @@ fn encode_info_for_method<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
 fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                              rbml_w: &mut Encoder,
-                                             index: &mut CrateIndex<'tcx>,
+                                             index: &mut CrateIndex<'a, 'tcx>,
                                              associated_type: &ty::AssociatedType<'tcx>,
                                              parent_id: NodeId,
                                              impl_item_opt: Option<&hir::ImplItem>) {
@@ -725,7 +731,7 @@ fn encode_info_for_associated_type<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
            associated_type.def_id,
            associated_type.name);
 
-    index.record(associated_type.def_id, rbml_w);
+    let _task = index.record(associated_type.def_id, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
 
     encode_def_id_and_key(ecx, rbml_w, associated_type.def_id);
@@ -762,7 +768,7 @@ fn encode_method_argument_names(rbml_w: &mut Encoder,
     for arg in &decl.inputs {
         let tag = tag_method_argument_name;
         if let PatKind::Ident(_, ref path1, _) = arg.pat.node {
-            let name = path1.node.name.as_str();
+            let name = path1.node.as_str();
             rbml_w.wr_tagged_bytes(tag, name.as_bytes());
         } else {
             rbml_w.wr_tagged_bytes(tag, &[]);
@@ -863,7 +869,7 @@ fn encode_xrefs<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                   rbml_w: &mut Encoder,
                                   item: &hir::Item,
-                                  index: &mut CrateIndex<'tcx>) {
+                                  index: &mut CrateIndex<'a, 'tcx>) {
     let tcx = ecx.tcx;
 
     debug!("encoding info for item at {}",
@@ -871,12 +877,15 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 
     let vis = &item.vis;
     let def_id = ecx.tcx.map.local_def_id(item.id);
-    let stab = tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id));
-    let depr = tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id));
+
+    let (stab, depr) = tcx.dep_graph.with_task(DepNode::MetaData(def_id), || {
+        (tcx.lookup_stability(ecx.tcx.map.local_def_id(item.id)),
+         tcx.lookup_deprecation(ecx.tcx.map.local_def_id(item.id)))
+    });
 
     match item.node {
       hir::ItemStatic(_, m, _) => {
-        index.record(def_id, rbml_w);
+        let _task = index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id_and_key(ecx, rbml_w, def_id);
         if m == hir::MutMutable {
@@ -894,7 +903,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         rbml_w.end_tag();
       }
       hir::ItemConst(_, _) => {
-        index.record(def_id, rbml_w);
+        let _task = index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, 'C');
@@ -909,7 +918,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         rbml_w.end_tag();
       }
       hir::ItemFn(ref decl, _, constness, _, ref generics, _) => {
-        index.record(def_id, rbml_w);
+        let _task = index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, FN_FAMILY);
@@ -933,7 +942,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         rbml_w.end_tag();
       }
       hir::ItemMod(ref m) => {
-        index.record(def_id, rbml_w);
+        let _task = index.record(def_id, rbml_w);
         encode_info_for_mod(ecx,
                             rbml_w,
                             m,
@@ -943,7 +952,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                             &item.vis);
       }
       hir::ItemForeignMod(ref fm) => {
-        index.record(def_id, rbml_w);
+        let _task = index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, 'n');
@@ -960,7 +969,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         rbml_w.end_tag();
       }
       hir::ItemTy(..) => {
-        index.record(def_id, rbml_w);
+        let _task = index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, 'y');
@@ -972,7 +981,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         rbml_w.end_tag();
       }
       hir::ItemEnum(ref enum_definition, _) => {
-        index.record(def_id, rbml_w);
+        let _task = index.record(def_id, rbml_w);
 
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id_and_key(ecx, rbml_w, def_id);
@@ -1003,12 +1012,12 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                  index);
       }
       hir::ItemStruct(ref struct_def, _) => {
+        /* Index the class*/
+        let _task = index.record(def_id, rbml_w);
+
         let def = ecx.tcx.lookup_adt_def(def_id);
         let variant = def.struct_variant();
 
-        /* Index the class*/
-        index.record(def_id, rbml_w);
-
         /* Now, make an item for the class itself */
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id_and_key(ecx, rbml_w, def_id);
@@ -1056,7 +1065,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         }
       }
       hir::ItemDefaultImpl(unsafety, _) => {
-          index.record(def_id, rbml_w);
+          let _task = index.record(def_id, rbml_w);
           rbml_w.start_tag(tag_items_data_item);
           encode_def_id_and_key(ecx, rbml_w, def_id);
           encode_family(rbml_w, 'd');
@@ -1068,12 +1077,13 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
           rbml_w.end_tag();
       }
       hir::ItemImpl(unsafety, polarity, _, _, _, ref ast_items) => {
+        let _task = index.record(def_id, rbml_w);
+
         // We need to encode information about the default methods we
         // have inherited, so we drive this based on the impl structure.
         let impl_items = tcx.impl_items.borrow();
         let items = impl_items.get(&def_id).unwrap();
 
-        index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, 'i');
@@ -1170,7 +1180,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         }
       }
       hir::ItemTrait(_, _, _, ref ms) => {
-        index.record(def_id, rbml_w);
+        let _task = index.record(def_id, rbml_w);
         rbml_w.start_tag(tag_items_data_item);
         encode_def_id_and_key(ecx, rbml_w, def_id);
         encode_family(rbml_w, 'I');
@@ -1225,7 +1235,7 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
         for (i, &item_def_id) in r.iter().enumerate() {
             assert_eq!(item_def_id.def_id().krate, LOCAL_CRATE);
 
-            index.record(item_def_id.def_id(), rbml_w);
+            let _task = index.record(item_def_id.def_id(), rbml_w);
             rbml_w.start_tag(tag_items_data_item);
 
             encode_parent_item(rbml_w, def_id);
@@ -1336,12 +1346,12 @@ fn encode_info_for_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
 fn encode_info_for_foreign_item<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                           rbml_w: &mut Encoder,
                                           nitem: &hir::ForeignItem,
-                                          index: &mut CrateIndex<'tcx>) {
+                                          index: &mut CrateIndex<'a, 'tcx>) {
     debug!("writing foreign item {}", ecx.tcx.node_path_str(nitem.id));
     let def_id = ecx.tcx.map.local_def_id(nitem.id);
     let abi = ecx.tcx.map.get_foreign_abi(nitem.id);
 
-    index.record(def_id, rbml_w);
+    let _task = index.record(def_id, rbml_w);
     rbml_w.start_tag(tag_items_data_item);
     encode_def_id_and_key(ecx, rbml_w, def_id);
     encode_visibility(rbml_w, &nitem.vis);
@@ -1390,7 +1400,7 @@ fn my_visit_expr(expr: &hir::Expr,
         hir::ExprClosure(..) => {
             let def_id = ecx.tcx.map.local_def_id(expr.id);
 
-            index.record(def_id, rbml_w);
+            let _task = index.record(def_id, rbml_w);
 
             rbml_w.start_tag(tag_items_data_item);
             encode_def_id_and_key(ecx, rbml_w, def_id);
@@ -1414,8 +1424,8 @@ fn my_visit_expr(expr: &hir::Expr,
 
 struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> {
     rbml_w_for_visit_item: &'a mut Encoder<'b>,
-    ecx: &'a EncodeContext<'c,'tcx>,
-    index: &'a mut CrateIndex<'tcx>,
+    ecx: &'a EncodeContext<'c, 'tcx>,
+    index: &'a mut CrateIndex<'c, 'tcx>,
 }
 
 impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
@@ -1435,23 +1445,26 @@ impl<'a, 'b, 'c, 'tcx> Visitor<'tcx> for EncodeVisitor<'a, 'b, 'c, 'tcx> {
 
 fn encode_info_for_items<'a, 'tcx>(ecx: &EncodeContext<'a, 'tcx>,
                                    rbml_w: &mut Encoder)
-                                   -> CrateIndex<'tcx> {
+                                   -> CrateIndex<'a, 'tcx> {
     let krate = ecx.tcx.map.krate();
 
     let mut index = CrateIndex {
+        dep_graph: &ecx.tcx.dep_graph,
         items: IndexData::new(ecx.tcx.map.num_local_def_ids()),
         xrefs: FnvHashMap()
     };
     rbml_w.start_tag(tag_items_data);
 
-    index.record(DefId::local(CRATE_DEF_INDEX), rbml_w);
-    encode_info_for_mod(ecx,
-                        rbml_w,
-                        &krate.module,
-                        &[],
-                        CRATE_NODE_ID,
-                        syntax::parse::token::intern(&ecx.link_meta.crate_name),
-                        &hir::Public);
+    {
+        let _task = index.record(DefId::local(CRATE_DEF_INDEX), rbml_w);
+        encode_info_for_mod(ecx,
+                            rbml_w,
+                            &krate.module,
+                            &[],
+                            CRATE_NODE_ID,
+                            syntax::parse::token::intern(&ecx.link_meta.crate_name),
+                            &hir::Public);
+    }
 
     krate.visit_all_items(&mut EncodeVisitor {
         index: &mut index,
@@ -1780,14 +1793,14 @@ fn encode_crate_dep(rbml_w: &mut Encoder,
     rbml_w.start_tag(tag_crate_dep);
     rbml_w.wr_tagged_str(tag_crate_dep_crate_name, &dep.name());
     let hash = decoder::get_crate_hash(dep.data());
-    rbml_w.wr_tagged_str(tag_crate_dep_hash, hash.as_str());
+    rbml_w.wr_tagged_u64(tag_crate_dep_hash, hash.as_u64());
     rbml_w.wr_tagged_u8(tag_crate_dep_explicitly_linked,
                         dep.explicitly_linked.get() as u8);
     rbml_w.end_tag();
 }
 
 fn encode_hash(rbml_w: &mut Encoder, hash: &Svh) {
-    rbml_w.wr_tagged_str(tag_crate_hash, hash.as_str());
+    rbml_w.wr_tagged_u64(tag_crate_hash, hash.as_u64());
 }
 
 fn encode_rustc_version(rbml_w: &mut Encoder) {
diff --git a/src/librustc_metadata/index.rs b/src/librustc_metadata/index.rs
index 9c066f9f5f1..b850073462f 100644
--- a/src/librustc_metadata/index.rs
+++ b/src/librustc_metadata/index.rs
@@ -75,7 +75,7 @@ impl IndexData {
 
     pub fn record(&mut self, def_id: DefId, position: u64) {
         assert!(def_id.is_local());
-        self.record_index(def_id.index, position)
+        self.record_index(def_id.index, position);
     }
 
     pub fn record_index(&mut self, item: DefIndex, position: u64) {
diff --git a/src/librustc_metadata/loader.rs b/src/librustc_metadata/loader.rs
index 4ecb7a28ef7..a5b1c3d301b 100644
--- a/src/librustc_metadata/loader.rs
+++ b/src/librustc_metadata/loader.rs
@@ -620,7 +620,7 @@ impl<'a> Context<'a> {
                 info!("Rejecting via hash: expected {} got {}", *myhash, hash);
                 self.rejected_via_hash.push(CrateMismatch {
                     path: libpath.to_path_buf(),
-                    got: myhash.as_str().to_string()
+                    got: myhash.to_string()
                 });
                 return None;
             }
diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs
index 77499a0f96c..d75cf3b7587 100644
--- a/src/librustc_mir/build/mod.rs
+++ b/src/librustc_mir/build/mod.rs
@@ -222,7 +222,7 @@ pub fn construct_fn<'a, 'gcx, 'tcx, A>(hir: Cx<'a, 'gcx, 'tcx>,
             };
             if let Some(hir::map::NodeLocal(pat)) = tcx.map.find(fv.def.var_id()) {
                 if let hir::PatKind::Ident(_, ref ident, _) = pat.node {
-                    decl.debug_name = ident.node.name;
+                    decl.debug_name = ident.node;
                 }
             }
             decl
@@ -335,7 +335,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             if let Some(pat) = pattern {
                 if let hir::PatKind::Ident(_, ref ident, _) = pat.node {
                     if pat_is_binding(&self.hir.tcx().def_map.borrow(), pat) {
-                        name = ident.node.name;
+                        name = ident.node;
                     }
                 }
             }
diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs
index 9e08e7b62d3..0118b97dd7f 100644
--- a/src/librustc_mir/hair/cx/pattern.rs
+++ b/src/librustc_mir/hair/cx/pattern.rs
@@ -166,7 +166,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
             {
                 let id = match self.binding_map {
                     None => pat.id,
-                    Some(ref map) => map[&ident.node.name],
+                    Some(ref map) => map[&ident.node],
                 };
                 let var_ty = self.cx.tcx.node_id_to_type(pat.id);
                 let region = match var_ty.sty {
@@ -197,7 +197,7 @@ impl<'patcx, 'cx, 'gcx, 'tcx> PatCx<'patcx, 'cx, 'gcx, 'tcx> {
                 PatternKind::Binding {
                     mutability: mutability,
                     mode: mode,
-                    name: ident.node.name,
+                    name: ident.node,
                     var: id,
                     ty: var_ty,
                     subpattern: self.to_opt_pattern(sub),
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 5b447a1690f..61ed88ec173 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1102,6 +1102,10 @@ impl<'a> hir::lowering::Resolver for Resolver<'a> {
         }
     }
 
+    fn get_resolution(&mut self, id: NodeId) -> Option<PathResolution> {
+        self.def_map.get(&id).cloned()
+    }
+
     fn record_resolution(&mut self, id: NodeId, def: Def) {
         self.def_map.insert(id, PathResolution { base_def: def, depth: 0 });
     }
@@ -1123,7 +1127,7 @@ impl Named for ast::PathSegment {
 
 impl Named for hir::PathSegment {
     fn name(&self) -> Name {
-        self.identifier.name
+        self.name
     }
 }
 
@@ -3620,6 +3624,7 @@ pub fn resolve_crate<'a, 'b>(resolver: &'b mut Resolver<'a>, krate: &'b Crate) {
     // reflects not just its contents but the results of name
     // resolution on those contents. Hopefully we'll push this back at
     // some point.
+    let _ignore = resolver.session.dep_graph.in_ignore();
 
     resolver.build_reduced_graph(krate);
     resolve_imports::resolve_imports(resolver);
diff --git a/src/librustc_trans/_match.rs b/src/librustc_trans/_match.rs
index 6df308d5e62..dbc277f2432 100644
--- a/src/librustc_trans/_match.rs
+++ b/src/librustc_trans/_match.rs
@@ -482,7 +482,7 @@ fn expand_nested_bindings<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         loop {
             pat = match pat.node {
                 PatKind::Ident(_, ref path, Some(ref inner)) => {
-                    bound_ptrs.push((path.node.name, val.val));
+                    bound_ptrs.push((path.node, val.val));
                     &inner
                 },
                 _ => break
@@ -520,7 +520,7 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
             match this.node {
                 PatKind::Ident(_, ref path, None) => {
                     if pat_is_binding(&dm.borrow(), &this) {
-                        bound_ptrs.push((path.node.name, val.val));
+                        bound_ptrs.push((path.node, val.val));
                     }
                 }
                 PatKind::Vec(ref before, Some(ref slice), ref after) => {
@@ -528,7 +528,7 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
                         let subslice_val = bind_subslice_pat(
                             bcx, this.id, val,
                             before.len(), after.len());
-                        bound_ptrs.push((path.node.name, subslice_val));
+                        bound_ptrs.push((path.node, subslice_val));
                     }
                 }
                 _ => {}
@@ -1802,7 +1802,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 // binding will live and place it into the appropriate
                 // map.
                 bcx = mk_binding_alloca(
-                    bcx, pat.id, path1.node.name, cleanup_scope, (),
+                    bcx, pat.id, path1.node, cleanup_scope, (),
                     "_match::bind_irrefutable_pat",
                     |(), bcx, Datum { val: llval, ty, kind: _ }| {
                         match pat_binding_mode {
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 00d9658cb59..53cc0319829 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -25,6 +25,7 @@ use middle::dependency_format::Linkage;
 use CrateTranslation;
 use util::common::time;
 use util::fs::fix_windows_verbatim_for_gcc;
+use rustc::dep_graph::DepNode;
 use rustc::ty::TyCtxt;
 use rustc_back::tempdir::TempDir;
 
@@ -183,6 +184,8 @@ pub fn link_binary(sess: &Session,
                    trans: &CrateTranslation,
                    outputs: &OutputFilenames,
                    crate_name: &str) -> Vec<PathBuf> {
+    let _task = sess.dep_graph.in_task(DepNode::LinkBinary);
+
     let mut out_filenames = Vec::new();
     for &crate_type in sess.crate_types.borrow().iter() {
         if invalid_output_for_target(sess, crate_type) {
@@ -228,6 +231,7 @@ pub fn invalid_output_for_target(sess: &Session,
                                  crate_type: config::CrateType) -> bool {
     match (sess.target.target.options.dynamic_linking,
            sess.target.target.options.executables, crate_type) {
+        (false, _, config::CrateTypeCdylib) |
         (false, _, config::CrateTypeDylib) => true,
         (_, false, config::CrateTypeExecutable) => true,
         _ => false
@@ -250,6 +254,7 @@ pub fn filename_for_input(sess: &Session,
         config::CrateTypeRlib => {
             outputs.out_directory.join(&format!("lib{}.rlib", libname))
         }
+        config::CrateTypeCdylib |
         config::CrateTypeDylib => {
             let (prefix, suffix) = (&sess.target.target.options.dll_prefix,
                                     &sess.target.target.options.dll_suffix);
@@ -278,9 +283,10 @@ pub fn each_linked_rlib(sess: &Session,
                         f: &mut FnMut(ast::CrateNum, &Path)) {
     let crates = sess.cstore.used_crates(LinkagePreference::RequireStatic).into_iter();
     let fmts = sess.dependency_formats.borrow();
-    let fmts = fmts.get(&config::CrateTypeExecutable).or_else(|| {
-        fmts.get(&config::CrateTypeStaticlib)
-    }).unwrap_or_else(|| {
+    let fmts = fmts.get(&config::CrateTypeExecutable)
+                   .or_else(|| fmts.get(&config::CrateTypeStaticlib))
+                   .or_else(|| fmts.get(&config::CrateTypeCdylib));
+    let fmts = fmts.unwrap_or_else(|| {
         bug!("could not find formats for rlibs")
     });
     for (cnum, path) in crates {
@@ -335,13 +341,9 @@ fn link_binary_output(sess: &Session,
         config::CrateTypeStaticlib => {
             link_staticlib(sess, &objects, &out_filename, tmpdir.path());
         }
-        config::CrateTypeExecutable => {
-            link_natively(sess, false, &objects, &out_filename, trans, outputs,
-                          tmpdir.path());
-        }
-        config::CrateTypeDylib => {
-            link_natively(sess, true, &objects, &out_filename, trans, outputs,
-                          tmpdir.path());
+        _ => {
+            link_natively(sess, crate_type, &objects, &out_filename, trans,
+                          outputs, tmpdir.path());
         }
     }
 
@@ -609,13 +611,14 @@ fn link_staticlib(sess: &Session, objects: &[PathBuf], out_filename: &Path,
 //
 // This will invoke the system linker/cc to create the resulting file. This
 // links to all upstream files as well.
-fn link_natively(sess: &Session, dylib: bool,
-                 objects: &[PathBuf], out_filename: &Path,
+fn link_natively(sess: &Session,
+                 crate_type: config::CrateType,
+                 objects: &[PathBuf],
+                 out_filename: &Path,
                  trans: &CrateTranslation,
                  outputs: &OutputFilenames,
                  tmpdir: &Path) {
-    info!("preparing dylib? ({}) from {:?} to {:?}", dylib, objects,
-          out_filename);
+    info!("preparing {:?} from {:?} to {:?}", crate_type, objects, out_filename);
 
     // The invocations of cc share some flags across platforms
     let (pname, mut cmd) = get_linker(sess);
@@ -624,10 +627,10 @@ fn link_natively(sess: &Session, dylib: bool,
     let root = sess.target_filesearch(PathKind::Native).get_lib_path();
     cmd.args(&sess.target.target.options.pre_link_args);
 
-    let pre_link_objects = if dylib {
-        &sess.target.target.options.pre_link_objects_dll
-    } else {
+    let pre_link_objects = if crate_type == config::CrateTypeExecutable {
         &sess.target.target.options.pre_link_objects_exe
+    } else {
+        &sess.target.target.options.pre_link_objects_dll
     };
     for obj in pre_link_objects {
         cmd.arg(root.join(obj));
@@ -639,7 +642,7 @@ fn link_natively(sess: &Session, dylib: bool,
         } else {
             Box::new(GnuLinker { cmd: &mut cmd, sess: &sess }) as Box<Linker>
         };
-        link_args(&mut *linker, sess, dylib, tmpdir,
+        link_args(&mut *linker, sess, crate_type, tmpdir,
                   objects, out_filename, trans, outputs);
         if !sess.target.target.options.no_compiler_rt {
             linker.link_staticlib("compiler-rt");
@@ -705,7 +708,7 @@ fn link_natively(sess: &Session, dylib: bool,
 
 fn link_args(cmd: &mut Linker,
              sess: &Session,
-             dylib: bool,
+             crate_type: config::CrateType,
              tmpdir: &Path,
              objects: &[PathBuf],
              out_filename: &Path,
@@ -727,26 +730,28 @@ fn link_args(cmd: &mut Linker,
 
     // If we're building a dynamic library then some platforms need to make sure
     // that all symbols are exported correctly from the dynamic library.
-    if dylib {
-        cmd.export_symbols(sess, trans, tmpdir);
+    if crate_type != config::CrateTypeExecutable {
+        cmd.export_symbols(sess, trans, tmpdir, crate_type);
     }
 
     // When linking a dynamic library, we put the metadata into a section of the
     // executable. This metadata is in a separate object file from the main
     // object file, so we link that in here.
-    if dylib {
+    if crate_type == config::CrateTypeDylib {
         cmd.add_object(&outputs.with_extension("metadata.o"));
     }
 
     // Try to strip as much out of the generated object by removing unused
     // sections if possible. See more comments in linker.rs
     if !sess.opts.cg.link_dead_code {
-        cmd.gc_sections(dylib);
+        let keep_metadata = crate_type == config::CrateTypeDylib;
+        cmd.gc_sections(keep_metadata);
     }
 
     let used_link_args = sess.cstore.used_link_args();
 
-    if !dylib && t.options.position_independent_executables {
+    if crate_type == config::CrateTypeExecutable &&
+       t.options.position_independent_executables {
         let empty_vec = Vec::new();
         let empty_str = String::new();
         let args = sess.opts.cg.link_args.as_ref().unwrap_or(&empty_vec);
@@ -801,12 +806,12 @@ fn link_args(cmd: &mut Linker,
     // in this DAG so far because they're only dylibs and dylibs can only depend
     // on other dylibs (e.g. other native deps).
     add_local_native_libraries(cmd, sess);
-    add_upstream_rust_crates(cmd, sess, dylib, tmpdir);
+    add_upstream_rust_crates(cmd, sess, crate_type, tmpdir);
     add_upstream_native_libraries(cmd, sess);
 
     // # Telling the linker what we're doing
 
-    if dylib {
+    if crate_type != config::CrateTypeExecutable {
         cmd.build_dylib(out_filename);
     }
 
@@ -904,8 +909,10 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) {
 // Rust crates are not considered at all when creating an rlib output. All
 // dependencies will be linked when producing the final output (instead of
 // the intermediate rlib version)
-fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
-                            dylib: bool, tmpdir: &Path) {
+fn add_upstream_rust_crates(cmd: &mut Linker,
+                            sess: &Session,
+                            crate_type: config::CrateType,
+                            tmpdir: &Path) {
     // All of the heavy lifting has previously been accomplished by the
     // dependency_format module of the compiler. This is just crawling the
     // output of that module, adding crates as necessary.
@@ -915,11 +922,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
     // involves just passing the right -l flag.
 
     let formats = sess.dependency_formats.borrow();
-    let data = if dylib {
-        formats.get(&config::CrateTypeDylib).unwrap()
-    } else {
-        formats.get(&config::CrateTypeExecutable).unwrap()
-    };
+    let data = formats.get(&crate_type).unwrap();
 
     // Invoke get_used_crates to ensure that we get a topological sorting of
     // crates.
@@ -934,7 +937,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
             Linkage::NotLinked |
             Linkage::IncludedFromDylib => {}
             Linkage::Static => {
-                add_static_crate(cmd, sess, tmpdir, dylib, &src.rlib.unwrap().0)
+                add_static_crate(cmd, sess, tmpdir, crate_type,
+                                 &src.rlib.unwrap().0)
             }
             Linkage::Dynamic => {
                 add_dynamic_crate(cmd, sess, &src.dylib.unwrap().0)
@@ -979,9 +983,12 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
     // (aka we're making an executable), we can just pass the rlib blindly to
     // the linker (fast) because it's fine if it's not actually included as
     // we're at the end of the dependency chain.
-    fn add_static_crate(cmd: &mut Linker, sess: &Session, tmpdir: &Path,
-                        dylib: bool, cratepath: &Path) {
-        if !sess.lto() && !dylib {
+    fn add_static_crate(cmd: &mut Linker,
+                        sess: &Session,
+                        tmpdir: &Path,
+                        crate_type: config::CrateType,
+                        cratepath: &Path) {
+        if !sess.lto() && crate_type != config::CrateTypeDylib {
             cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
             return
         }
@@ -1017,7 +1024,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, sess: &Session,
 
             if any_objects {
                 archive.build();
-                if dylib {
+                if crate_type == config::CrateTypeDylib {
                     cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst));
                 } else {
                     cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst));
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index 8055e97034e..50f6366e85c 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -18,7 +18,7 @@ use std::process::Command;
 use back::archive;
 use middle::dependency_format::Linkage;
 use session::Session;
-use session::config::CrateTypeDylib;
+use session::config::CrateType;
 use session::config;
 use syntax::ast;
 use CrateTranslation;
@@ -42,7 +42,7 @@ pub trait Linker {
     fn framework_path(&mut self, path: &Path);
     fn output_filename(&mut self, path: &Path);
     fn add_object(&mut self, path: &Path);
-    fn gc_sections(&mut self, is_dylib: bool);
+    fn gc_sections(&mut self, keep_metadata: bool);
     fn position_independent_executable(&mut self);
     fn optimize(&mut self);
     fn debuginfo(&mut self);
@@ -53,8 +53,11 @@ pub trait Linker {
     fn hint_dynamic(&mut self);
     fn whole_archives(&mut self);
     fn no_whole_archives(&mut self);
-    fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation,
-                      tmpdir: &Path);
+    fn export_symbols(&mut self,
+                      sess: &Session,
+                      trans: &CrateTranslation,
+                      tmpdir: &Path,
+                      crate_type: CrateType);
 }
 
 pub struct GnuLinker<'a> {
@@ -113,7 +116,7 @@ impl<'a> Linker for GnuLinker<'a> {
         }
     }
 
-    fn gc_sections(&mut self, is_dylib: bool) {
+    fn gc_sections(&mut self, keep_metadata: bool) {
         // The dead_strip option to the linker specifies that functions and data
         // unreachable by the entry point will be removed. This is quite useful
         // with Rust's compilation model of compiling libraries at a time into
@@ -139,7 +142,7 @@ impl<'a> Linker for GnuLinker<'a> {
         // eliminate the metadata. If we're building an executable, however,
         // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67%
         // reduction.
-        } else if !is_dylib {
+        } else if !keep_metadata {
             self.cmd.arg("-Wl,--gc-sections");
         }
     }
@@ -198,8 +201,46 @@ impl<'a> Linker for GnuLinker<'a> {
         self.cmd.arg("-Wl,-Bdynamic");
     }
 
-    fn export_symbols(&mut self, _: &Session, _: &CrateTranslation, _: &Path) {
-        // noop, visibility in object files takes care of this
+    fn export_symbols(&mut self,
+                      sess: &Session,
+                      trans: &CrateTranslation,
+                      tmpdir: &Path,
+                      crate_type: CrateType) {
+        // If we're compiling a dylib, then we let symbol visibility in object
+        // files to take care of whether they're exported or not.
+        //
+        // If we're compiling a cdylib, however, we manually create a list of
+        // exported symbols to ensure we don't expose any more. The object files
+        // have far more public symbols than we actually want to export, so we
+        // hide them all here.
+        if crate_type == CrateType::CrateTypeDylib {
+            return
+        }
+
+        let path = tmpdir.join("list");
+        let prefix = if self.sess.target.target.options.is_like_osx {
+            "_"
+        } else {
+            ""
+        };
+        let res = (|| -> io::Result<()> {
+            let mut f = BufWriter::new(File::create(&path)?);
+            for sym in exported_symbols(sess, trans, crate_type) {
+                writeln!(f, "{}{}", prefix, sym)?;
+            }
+            Ok(())
+        })();
+        if let Err(e) = res {
+            sess.fatal(&format!("failed to write lib.def file: {}", e));
+        }
+        let mut arg = OsString::new();
+        if self.sess.target.target.options.is_like_osx {
+            arg.push("-Wl,-exported_symbols_list,");
+        } else {
+            arg.push("-Wl,--retain-symbols-file=");
+        }
+        arg.push(&path);
+        self.cmd.arg(arg);
     }
 }
 
@@ -220,7 +261,9 @@ impl<'a> Linker for MsvcLinker<'a> {
         self.cmd.arg(arg);
     }
 
-    fn gc_sections(&mut self, _is_dylib: bool) { self.cmd.arg("/OPT:REF,ICF"); }
+    fn gc_sections(&mut self, _keep_metadata: bool) {
+        self.cmd.arg("/OPT:REF,ICF");
+    }
 
     fn link_dylib(&mut self, lib: &str) {
         self.cmd.arg(&format!("{}.lib", lib));
@@ -322,8 +365,11 @@ impl<'a> Linker for MsvcLinker<'a> {
     // crates. Upstream rlibs may be linked statically to this dynamic library,
     // in which case they may continue to transitively be used and hence need
     // their symbols exported.
-    fn export_symbols(&mut self, sess: &Session, trans: &CrateTranslation,
-                      tmpdir: &Path) {
+    fn export_symbols(&mut self,
+                      sess: &Session,
+                      trans: &CrateTranslation,
+                      tmpdir: &Path,
+                      crate_type: CrateType) {
         let path = tmpdir.join("lib.def");
         let res = (|| -> io::Result<()> {
             let mut f = BufWriter::new(File::create(&path)?);
@@ -333,32 +379,10 @@ impl<'a> Linker for MsvcLinker<'a> {
             writeln!(f, "LIBRARY")?;
             writeln!(f, "EXPORTS")?;
 
-            // Write out all our local symbols
-            for sym in trans.reachable.iter() {
+            for sym in exported_symbols(sess, trans, crate_type) {
                 writeln!(f, "  {}", sym)?;
             }
 
-            // Take a look at how all upstream crates are linked into this
-            // dynamic library. For all statically linked libraries we take all
-            // their reachable symbols and emit them as well.
-            let cstore = &sess.cstore;
-            let formats = sess.dependency_formats.borrow();
-            let symbols = formats[&CrateTypeDylib].iter();
-            let symbols = symbols.enumerate().filter_map(|(i, f)| {
-                if *f == Linkage::Static {
-                    Some((i + 1) as ast::CrateNum)
-                } else {
-                    None
-                }
-            }).flat_map(|cnum| {
-                cstore.reachable_ids(cnum)
-            }).map(|did| {
-                cstore.item_symbol(did)
-            });
-            for symbol in symbols {
-                writeln!(f, "  {}", symbol)?;
-            }
-
             Ok(())
         })();
         if let Err(e) = res {
@@ -369,3 +393,36 @@ impl<'a> Linker for MsvcLinker<'a> {
         self.cmd.arg(&arg);
     }
 }
+
+fn exported_symbols(sess: &Session,
+                    trans: &CrateTranslation,
+                    crate_type: CrateType) -> Vec<String> {
+    let mut symbols = trans.reachable.iter().cloned().collect::<Vec<_>>();
+
+    // If we're producing anything other than a dylib then the `reachable` array
+    // above is the exhaustive set of symbols we should be exporting.
+    //
+    // For dylibs, however, we need to take a look at how all upstream crates
+    // are linked into this dynamic library. For all statically linked
+    // libraries we take all their reachable symbols and emit them as well.
+    if crate_type != CrateType::CrateTypeDylib {
+        return symbols
+    }
+
+    let cstore = &sess.cstore;
+    let formats = sess.dependency_formats.borrow();
+    let upstream_symbols = formats[&crate_type].iter();
+    symbols.extend(upstream_symbols.enumerate().filter_map(|(i, f)| {
+        if *f == Linkage::Static {
+            Some((i + 1) as ast::CrateNum)
+        } else {
+            None
+        }
+    }).flat_map(|cnum| {
+        cstore.reachable_ids(cnum)
+    }).map(|did| {
+        cstore.item_symbol(did)
+    }));
+
+    return symbols
+}
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs
index 649d37e802d..31bc11fb215 100644
--- a/src/librustc_trans/back/lto.rs
+++ b/src/librustc_trans/back/lto.rs
@@ -30,7 +30,8 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
            output_names: &config::OutputFilenames) {
     if sess.opts.cg.prefer_dynamic {
         sess.struct_err("cannot prefer dynamic linking when performing LTO")
-            .note("only 'staticlib' and 'bin' outputs are supported with LTO")
+            .note("only 'staticlib', 'bin', and 'cdylib' outputs are \
+                   supported with LTO")
             .emit();
         sess.abort_if_errors();
     }
@@ -38,7 +39,9 @@ pub fn run(sess: &session::Session, llmod: ModuleRef,
     // Make sure we actually can run LTO
     for crate_type in sess.crate_types.borrow().iter() {
         match *crate_type {
-            config::CrateTypeExecutable | config::CrateTypeStaticlib => {}
+            config::CrateTypeExecutable |
+            config::CrateTypeCdylib |
+            config::CrateTypeStaticlib => {}
             _ => {
                 sess.fatal("lto can only be run for executables and \
                             static library outputs");
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 65c3aa12ba6..d68998927da 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -47,6 +47,7 @@ use rustc::dep_graph::DepNode;
 use rustc::hir::map as hir_map;
 use rustc::util::common::time;
 use rustc::mir::mir_map::MirMap;
+use rustc_data_structures::graph::OUTGOING;
 use session::config::{self, NoDebugInfo, FullDebugInfo};
 use session::Session;
 use _match;
@@ -1368,7 +1369,7 @@ fn build_cfg<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 // return slot alloca. This can cause errors related to clean-up due to
 // the clobbering of the existing value in the return slot.
 fn has_nested_returns(tcx: TyCtxt, cfg: &cfg::CFG, blk_id: ast::NodeId) -> bool {
-    for index in cfg.graph.depth_traverse(cfg.entry) {
+    for index in cfg.graph.depth_traverse(cfg.entry, OUTGOING) {
         let n = cfg.graph.node_data(index);
         match tcx.map.find(n.id()) {
             Some(hir_map::NodeExpr(ex)) => {
@@ -2508,9 +2509,7 @@ pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>,
 
     let llmeta = C_bytes_in_context(cx.metadata_llcx(), &compressed[..]);
     let llconst = C_struct_in_context(cx.metadata_llcx(), &[llmeta], false);
-    let name = format!("rust_metadata_{}_{}",
-                       cx.link_meta().crate_name,
-                       cx.link_meta().crate_hash);
+    let name = cx.metadata_symbol_name();
     let buf = CString::new(name).unwrap();
     let llglobal = unsafe {
         llvm::LLVMAddGlobal(cx.metadata_llmod(), val_ty(llconst).to_ref(), buf.as_ptr())
@@ -2812,18 +2811,25 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         reachable_symbols.push("main".to_string());
     }
 
-    // For the purposes of LTO, we add to the reachable set all of the upstream
-    // reachable extern fns. These functions are all part of the public ABI of
-    // the final product, so LTO needs to preserve them.
-    if sess.lto() {
-        for cnum in sess.cstore.crates() {
-            let syms = sess.cstore.reachable_ids(cnum);
-            reachable_symbols.extend(syms.into_iter().filter(|did| {
-                sess.cstore.is_extern_item(shared_ccx.tcx(), *did)
-            }).map(|did| {
-                sess.cstore.item_symbol(did)
-            }));
-        }
+    if sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
+        reachable_symbols.push(shared_ccx.metadata_symbol_name());
+    }
+
+    // For the purposes of LTO or when creating a cdylib, we add to the
+    // reachable set all of the upstream reachable extern fns. These functions
+    // are all part of the public ABI of the final product, so we need to
+    // preserve them.
+    //
+    // Note that this happens even if LTO isn't requested or we're not creating
+    // a cdylib. In those cases, though, we're not even reading the
+    // `reachable_symbols` list later on so it should be ok.
+    for cnum in sess.cstore.crates() {
+        let syms = sess.cstore.reachable_ids(cnum);
+        reachable_symbols.extend(syms.into_iter().filter(|did| {
+            sess.cstore.is_extern_item(shared_ccx.tcx(), *did)
+        }).map(|did| {
+            sess.cstore.item_symbol(did)
+        }));
     }
 
     if codegen_unit_count > 1 {
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 60c6af84ebb..4d6c4cdcc6b 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -503,6 +503,12 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
             Substs::new(VecPerParamSpace::empty(),
                         scheme.generics.regions.map(|_| ty::ReStatic)))
     }
+
+    pub fn metadata_symbol_name(&self) -> String {
+        format!("rust_metadata_{}_{}",
+                self.link_meta().crate_name,
+                self.link_meta().crate_hash)
+    }
 }
 
 impl<'tcx> LocalCrateContext<'tcx> {
diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_trans/debuginfo/create_scope_map.rs
index 3a8974c2aca..ba592382d1a 100644
--- a/src/librustc_trans/debuginfo/create_scope_map.rs
+++ b/src/librustc_trans/debuginfo/create_scope_map.rs
@@ -51,9 +51,9 @@ pub fn create_scope_map(cx: &CrateContext,
     // Push argument identifiers onto the stack so arguments integrate nicely
     // with variable shadowing.
     for arg in args {
-        pat_util::pat_bindings_ident(def_map, &arg.pat, |_, node_id, _, path1| {
+        pat_util::pat_bindings(def_map, &arg.pat, |_, node_id, _, path1| {
             scope_stack.push(ScopeStackEntry { scope_metadata: fn_metadata,
-                                               name: Some(path1.node.unhygienic_name) });
+                                               name: Some(path1.node.unhygienize()) });
             scope_map.insert(node_id, fn_metadata);
         })
     }
@@ -248,7 +248,7 @@ fn walk_pattern(cx: &CrateContext,
             // scope stack and maybe introduce an artificial scope
             if pat_util::pat_is_binding(&def_map.borrow(), &pat) {
 
-                let name = path1.node.unhygienic_name;
+                let name = path1.node.unhygienize();
 
                 // LLVM does not properly generate 'DW_AT_start_scope' fields
                 // for variable DIEs. For this reason we have to introduce
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 7826693c827..ccb01789aa6 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -1946,7 +1946,7 @@ pub fn create_captured_var_metadata<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         Some(hir_map::NodeLocal(pat)) => {
             match pat.node {
                 PatKind::Ident(_, ref path1, _) => {
-                    path1.node.name
+                    path1.node
                 }
                 _ => {
                     span_bug!(span,
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index db4a82c7b0b..6c1bd715f13 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -14,8 +14,7 @@ mod doc;
 use self::VariableAccess::*;
 use self::VariableKind::*;
 
-use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit,
-                  get_namespace_and_span_for_item};
+use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
 use self::namespace::mangled_name_of_item;
 use self::type_names::compute_debuginfo_type_name;
 use self::metadata::{type_metadata, diverging_type_metadata};
@@ -33,7 +32,7 @@ use rustc::hir;
 
 use abi::Abi;
 use common::{NodeIdAndSpan, CrateContext, FunctionContext, Block, BlockAndBuilder};
-use monomorphize::Instance;
+use monomorphize::{self, Instance};
 use rustc::ty::{self, Ty};
 use session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo};
 use util::nodemap::{DefIdMap, NodeMap, FnvHashMap, FnvHashSet};
@@ -240,8 +239,9 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     // Do this here already, in case we do an early exit from this function.
     source_loc::set_debug_location(cx, None, UnknownLocation);
 
+    let (containing_scope, span) = get_containing_scope_and_span(cx, instance);
+
     // This can be the case for functions inlined from another crate
-    let (containing_scope, span) = get_namespace_and_span_for_item(cx, instance.def);
     if span == codemap::DUMMY_SP {
         return FunctionDebugContext::FunctionWithoutDebugInfo;
     }
@@ -283,6 +283,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
     let function_name = CString::new(name).unwrap();
     let linkage_name = CString::new(linkage_name).unwrap();
+
     let fn_metadata = unsafe {
         llvm::LLVMDIBuilderCreateFunction(
             DIB(cx),
@@ -404,6 +405,47 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
         return create_DIArray(DIB(cx), &template_params[..]);
     }
+
+    fn get_containing_scope_and_span<'ccx, 'tcx>(cx: &CrateContext<'ccx, 'tcx>,
+                                                 instance: Instance<'tcx>)
+                                                 -> (DIScope, Span) {
+        // First, let's see if this is a method within an inherent impl. Because
+        // if yes, we want to make the result subroutine DIE a child of the
+        // subroutine's self-type.
+        let self_type = cx.tcx().impl_of_method(instance.def).and_then(|impl_def_id| {
+            // If the method does *not* belong to a trait, proceed
+            if cx.tcx().trait_id_of_impl(impl_def_id).is_none() {
+                let impl_self_ty = cx.tcx().lookup_item_type(impl_def_id).ty;
+                let impl_self_ty = cx.tcx().erase_regions(&impl_self_ty);
+                let impl_self_ty = monomorphize::apply_param_substs(cx.tcx(),
+                                                                    instance.substs,
+                                                                    &impl_self_ty);
+                Some(type_metadata(cx, impl_self_ty, codemap::DUMMY_SP))
+            } else {
+                // For trait method impls we still use the "parallel namespace"
+                // strategy
+                None
+            }
+        });
+
+        let containing_scope = self_type.unwrap_or_else(|| {
+            namespace::item_namespace(cx, DefId {
+                krate: instance.def.krate,
+                index: cx.tcx()
+                         .def_key(instance.def)
+                         .parent
+                         .expect("get_containing_scope_and_span: missing parent?")
+            })
+        });
+
+        // Try to get some span information, if we have an inlined item.
+        let definition_span = match cx.external().borrow().get(&instance.def) {
+            Some(&Some(node_id)) => cx.tcx().map.span(node_id),
+            _ => cx.tcx().map.def_id_span(instance.def, codemap::DUMMY_SP)
+        };
+
+        (containing_scope, definition_span)
+    }
 }
 
 /// Computes the scope map for a function given its declaration and body.
diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs
index 186781547f9..36a593a546b 100644
--- a/src/librustc_trans/expr.rs
+++ b/src/librustc_trans/expr.rs
@@ -928,13 +928,13 @@ fn trans_rvalue_stmt_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     match expr.node {
         hir::ExprBreak(label_opt) => {
-            controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node.name))
+            controlflow::trans_break(bcx, expr, label_opt.map(|l| l.node))
         }
         hir::ExprType(ref e, _) => {
             trans_into(bcx, &e, Ignore)
         }
         hir::ExprAgain(label_opt) => {
-            controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node.name))
+            controlflow::trans_cont(bcx, expr, label_opt.map(|l| l.node))
         }
         hir::ExprRet(ref ex) => {
             // Check to see if the return expression itself is reachable.
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 4faefb61056..1df12b63e0a 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -52,13 +52,17 @@ use middle::const_val::ConstVal;
 use rustc_const_eval::{eval_const_expr_partial, ConstEvalErr};
 use rustc_const_eval::EvalHint::UncheckedExprHint;
 use rustc_const_eval::ErrKind::ErroneousReferencedConstant;
+use hir::{self, SelfKind};
 use hir::def::{self, Def};
 use hir::def_id::DefId;
+use hir::print as pprust;
 use middle::resolve_lifetime as rl;
+use rustc::lint;
 use rustc::ty::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs, ParamSpace};
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
 use rustc::ty::wf::object_region_bounds;
+use rustc_back::slice;
 use require_c_abi_if_variadic;
 use rscope::{self, UnelidableRscope, RegionScope, ElidableRscope,
              ObjectLifetimeDefaultRscope, ShiftedRscope, BindingRscope,
@@ -74,10 +78,6 @@ use syntax::errors::DiagnosticBuilder;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
 use syntax::parse::token::{self, keywords};
 
-use rustc::hir::print as pprust;
-use rustc::hir::{self, SelfKind};
-use rustc_back::slice;
-
 pub trait AstConv<'gcx, 'tcx> {
     fn tcx<'a>(&'a self) -> TyCtxt<'a, 'gcx, 'tcx>;
 
@@ -215,15 +215,18 @@ fn report_elision_failure(
 {
     let mut m = String::new();
     let len = params.len();
-    let mut any_lifetimes = false;
 
-    for (i, info) in params.into_iter().enumerate() {
+    let elided_params: Vec<_> = params.into_iter()
+                                       .filter(|info| info.lifetime_count > 0)
+                                       .collect();
+
+    let elided_len = elided_params.len();
+
+    for (i, info) in elided_params.into_iter().enumerate() {
         let ElisionFailureInfo {
             name, lifetime_count: n, have_bound_regions
         } = info;
 
-        any_lifetimes = any_lifetimes || (n > 0);
-
         let help_name = if name.is_empty() {
             format!("argument {}", i + 1)
         } else {
@@ -237,13 +240,14 @@ fn report_elision_failure(
                     if have_bound_regions { "free " } else { "" } )
         })[..]);
 
-        if len == 2 && i == 0 {
+        if elided_len == 2 && i == 0 {
             m.push_str(" or ");
-        } else if i + 2 == len {
+        } else if i + 2 == elided_len {
             m.push_str(", or ");
-        } else if i + 1 != len {
+        } else if i != elided_len - 1 {
             m.push_str(", ");
         }
+
     }
 
     if len == 0 {
@@ -252,7 +256,7 @@ fn report_elision_failure(
                     there is no value for it to be borrowed from");
         help!(db,
                    "consider giving it a 'static lifetime");
-    } else if !any_lifetimes {
+    } else if elided_len == 0 {
         help!(db,
                    "this function's return type contains a borrowed value with \
                     an elided lifetime, but the lifetime cannot be derived from \
@@ -260,7 +264,7 @@ fn report_elision_failure(
         help!(db,
                    "consider giving it an explicit bounded or 'static \
                     lifetime");
-    } else if len == 1 {
+    } else if elided_len == 1 {
         help!(db,
                    "this function's return type contains a borrowed value, but \
                     the signature does not say which {} it is borrowed from",
@@ -679,6 +683,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                         PathParamMode::Explicit,
                                         trait_def_id,
                                         self_ty,
+                                        trait_ref.ref_id,
                                         trait_ref.path.segments.last().unwrap(),
                                         poly_projections)
     }
@@ -723,6 +728,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         span: Span,
         param_mode: PathParamMode,
         trait_def_id: DefId,
+        trait_path_ref_id: ast::NodeId,
         trait_segment: &hir::PathSegment,
         mut projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
         -> ty::PolyTraitRef<'tcx>
@@ -732,6 +738,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                         param_mode,
                                         trait_def_id,
                                         None,
+                                        trait_path_ref_id,
                                         trait_segment,
                                         projections)
     }
@@ -742,6 +749,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         param_mode: PathParamMode,
         trait_def_id: DefId,
         self_ty: Option<Ty<'tcx>>,
+        path_id: ast::NodeId,
         trait_segment: &hir::PathSegment,
         poly_projections: &mut Vec<ty::PolyProjectionPredicate<'tcx>>)
         -> ty::PolyTraitRef<'tcx>
@@ -770,7 +778,8 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                 .filter_map(|binding| {
                     // specify type to assert that error was already reported in Err case:
                     let predicate: Result<_, ErrorReported> =
-                        self.ast_type_binding_to_poly_projection_predicate(poly_trait_ref.clone(),
+                        self.ast_type_binding_to_poly_projection_predicate(path_id,
+                                                                           poly_trait_ref.clone(),
                                                                            self_ty,
                                                                            binding);
                     predicate.ok() // ok to ignore Err() because ErrorReported (see above)
@@ -863,7 +872,9 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         (self.tcx().mk_substs(substs), assoc_bindings)
     }
 
-    fn ast_type_binding_to_poly_projection_predicate(&self,
+    fn ast_type_binding_to_poly_projection_predicate(
+        &self,
+        path_id: ast::NodeId,
         mut trait_ref: ty::PolyTraitRef<'tcx>,
         self_ty: Option<Ty<'tcx>>,
         binding: &ConvertedBinding<'tcx>)
@@ -887,6 +898,36 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
         //
         // We want to produce `<B as SuperTrait<int>>::T == foo`.
 
+        // Find any late-bound regions declared in `ty` that are not
+        // declared in the trait-ref. These are not wellformed.
+        //
+        // Example:
+        //
+        //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
+        //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
+        let late_bound_in_trait_ref = tcx.collect_constrained_late_bound_regions(&trait_ref);
+        let late_bound_in_ty = tcx.collect_referenced_late_bound_regions(&ty::Binder(binding.ty));
+        debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
+        debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
+        for br in late_bound_in_ty.difference(&late_bound_in_trait_ref) {
+            let br_name = match *br {
+                ty::BrNamed(_, name) => name,
+                _ => {
+                    span_bug!(
+                        binding.span,
+                        "anonymous bound region {:?} in binding but not trait ref",
+                        br);
+                }
+            };
+            tcx.sess.add_lint(
+                lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
+                path_id,
+                binding.span,
+                format!("binding for associated type `{}` references lifetime `{}`, \
+                         which does not appear in the trait input types",
+                        binding.item_name, br_name));
+        }
+
         // Simple case: X is defined in the current trait.
         if self.trait_defines_associated_type_named(trait_ref.def_id(), binding.item_name) {
             return Ok(ty::Binder(ty::ProjectionPredicate {      // <-------------------+
@@ -1012,6 +1053,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                                                path.span,
                                                                PathParamMode::Explicit,
                                                                trait_def_id,
+                                                               ty.id,
                                                                path.segments.last().unwrap(),
                                                                &mut projection_bounds);
                         Ok((trait_ref, projection_bounds))
@@ -1245,7 +1287,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                  -> (Ty<'tcx>, Def)
     {
         let tcx = self.tcx();
-        let assoc_name = item_segment.identifier.name;
+        let assoc_name = item_segment.name;
 
         debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);
 
@@ -1356,7 +1398,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             self.report_ambiguous_associated_type(span,
                                                   "Type",
                                                   &path_str,
-                                                  &item_segment.identifier.name.as_str());
+                                                  &item_segment.name.as_str());
             return tcx.types.err;
         };
 
@@ -1371,7 +1413,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         debug!("qpath_to_ty: trait_ref={:?}", trait_ref);
 
-        self.projected_ty(span, trait_ref, item_segment.identifier.name)
+        self.projected_ty(span, trait_ref, item_segment.name)
     }
 
     /// Convert a type supplied as value for a type argument from AST into our
@@ -1416,6 +1458,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                       param_mode: PathParamMode,
                       def: Def,
                       opt_self_ty: Option<Ty<'tcx>>,
+                      base_path_ref_id: ast::NodeId,
                       base_segments: &[hir::PathSegment])
                       -> Ty<'tcx> {
         let tcx = self.tcx();
@@ -1434,6 +1477,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                                        span,
                                                        param_mode,
                                                        trait_def_id,
+                                                       base_path_ref_id,
                                                        base_segments.last().unwrap(),
                                                        &mut projection_bounds);
 
@@ -1518,6 +1562,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                       param_mode: PathParamMode,
                                       mut def: Def,
                                       opt_self_ty: Option<Ty<'tcx>>,
+                                      base_path_ref_id: ast::NodeId,
                                       base_segments: &[hir::PathSegment],
                                       assoc_segments: &[hir::PathSegment])
                                       -> (Ty<'tcx>, Def) {
@@ -1532,6 +1577,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                          param_mode,
                                          def,
                                          opt_self_ty,
+                                         base_path_ref_id,
                                          base_segments);
         debug!("finish_resolving_def_to_ty: base_def_to_ty returned {:?}", ty);
         // If any associated type segments remain, attempt to resolve them.
@@ -1607,7 +1653,45 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
             }
             hir::TyBareFn(ref bf) => {
                 require_c_abi_if_variadic(tcx, &bf.decl, bf.abi, ast_ty.span);
-                tcx.mk_fn_ptr(self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl))
+                let bare_fn_ty = self.ty_of_bare_fn(bf.unsafety, bf.abi, &bf.decl);
+
+                // Find any late-bound regions declared in return type that do
+                // not appear in the arguments. These are not wellformed.
+                //
+                // Example:
+                //
+                //     for<'a> fn() -> &'a str <-- 'a is bad
+                //     for<'a> fn(&'a String) -> &'a str <-- 'a is ok
+                //
+                // Note that we do this check **here** and not in
+                // `ty_of_bare_fn` because the latter is also used to make
+                // the types for fn items, and we do not want to issue a
+                // warning then. (Once we fix #32330, the regions we are
+                // checking for here would be considered early bound
+                // anyway.)
+                let inputs = bare_fn_ty.sig.inputs();
+                let late_bound_in_args = tcx.collect_constrained_late_bound_regions(&inputs);
+                let output = bare_fn_ty.sig.output();
+                let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
+                for br in late_bound_in_ret.difference(&late_bound_in_args) {
+                    let br_name = match *br {
+                        ty::BrNamed(_, name) => name,
+                        _ => {
+                            span_bug!(
+                                bf.decl.output.span(),
+                                "anonymous bound region {:?} in return but not args",
+                                br);
+                        }
+                    };
+                    tcx.sess.add_lint(
+                        lint::builtin::HR_LIFETIME_IN_ASSOC_TYPE,
+                        ast_ty.id,
+                        ast_ty.span,
+                        format!("return type references lifetime `{}`, \
+                                 which does not appear in the trait input types",
+                                br_name));
+                }
+                tcx.mk_fn_ptr(bare_fn_ty)
             }
             hir::TyPolyTraitRef(ref bounds) => {
                 self.conv_ty_poly_trait_ref(rscope, ast_ty.span, bounds)
@@ -1635,6 +1719,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
                                                                  PathParamMode::Explicit,
                                                                  def,
                                                                  opt_self_ty,
+                                                                 ast_ty.id,
                                                                  &path.segments[..base_ty_end],
                                                                  &path.segments[base_ty_end..]);
 
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index d55ca803c64..10c8ea84bfd 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -200,7 +200,7 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
 
                 // if there are multiple arms, make sure they all agree on
                 // what the type of the binding `x` ought to be
-                if let Some(&canon_id) = self.map.get(&path.node.name) {
+                if let Some(&canon_id) = self.map.get(&path.node) {
                     if canon_id != pat.id {
                         let ct = self.local_ty(pat.span, canon_id);
                         self.demand_eqtype(pat.span, ct, typ);
@@ -212,7 +212,7 @@ impl<'a, 'gcx, 'tcx> PatCtxt<'a, 'gcx, 'tcx> {
                 }
             }
             PatKind::Ident(_, ref path, _) => {
-                let path = hir::Path::from_ident(path.span, path.node);
+                let path = hir::Path::from_name(path.span, path.node);
                 self.check_pat_enum(pat, &path, Some(&[]), expected, false);
             }
             PatKind::TupleStruct(ref path, ref subpats) => {
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index be329ec11af..2cd60d20251 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -216,7 +216,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         }
                         else if let Expr_::ExprPath(_, path) = expr.node.clone() {
                             if let Some(segment) = path.segments.last() {
-                                report_function!(expr.span, segment.identifier.name);
+                                report_function!(expr.span, segment.name);
                             }
                         }
                     }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index ed2edc30c9d..264003bb62b 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -732,17 +732,26 @@ pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
           let impl_def_id = ccx.tcx.map.local_def_id(it.id);
           match ccx.tcx.impl_trait_ref(impl_def_id) {
               Some(impl_trait_ref) => {
-                check_impl_items_against_trait(ccx,
-                                               it.span,
-                                               impl_def_id,
-                                               &impl_trait_ref,
-                                               impl_items);
+                  let trait_def_id = impl_trait_ref.def_id;
+
+                  check_impl_items_against_trait(ccx,
+                                                 it.span,
+                                                 impl_def_id,
+                                                 &impl_trait_ref,
+                                                 impl_items);
+                  check_on_unimplemented(
+                      ccx,
+                      &ccx.tcx.lookup_trait_def(trait_def_id).generics,
+                      it,
+                      ccx.tcx.item_name(trait_def_id));
               }
               None => { }
           }
       }
-      hir::ItemTrait(_, ref generics, _, _) => {
-        check_trait_on_unimplemented(ccx, generics, it);
+      hir::ItemTrait(..) => {
+        let def_id = ccx.tcx.map.local_def_id(it.id);
+        let generics = &ccx.tcx.lookup_trait_def(def_id).generics;
+        check_on_unimplemented(ccx, generics, it, it.name);
       }
       hir::ItemStruct(..) => {
         check_struct(ccx, it.id, it.span);
@@ -854,15 +863,16 @@ fn check_trait_fn_not_const<'a,'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
     }
 }
 
-fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
-                               generics: &hir::Generics,
-                               item: &hir::Item) {
+fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+                                    generics: &ty::Generics,
+                                    item: &hir::Item,
+                                    name: ast::Name) {
     if let Some(ref attr) = item.attrs.iter().find(|a| {
         a.check_name("rustc_on_unimplemented")
     }) {
         if let Some(ref istring) = attr.value_str() {
             let parser = Parser::new(&istring);
-            let types = &generics.ty_params;
+            let types = &generics.types;
             for token in parser {
                 match token {
                     Piece::String(_) => (), // Normal string, no need to check it
@@ -878,7 +888,7 @@ fn check_trait_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
                                 span_err!(ccx.tcx.sess, attr.span, E0230,
                                                  "there is no type parameter \
                                                           {} on trait {}",
-                                                           s, item.name);
+                                                           s, name);
                             }
                         },
                         // `{:1}` and `{}` are not to be used
@@ -3866,10 +3876,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                                                                  PathParamMode::Optional,
                                                                  def,
                                                                  opt_self_ty,
+                                                                 node_id,
                                                                  &ty_segments[..base_ty_end],
                                                                  &ty_segments[base_ty_end..]);
             let item_segment = path.segments.last().unwrap();
-            let item_name = item_segment.identifier.name;
+            let item_name = item_segment.name;
             let def = match self.resolve_ufcs(span, item_name, ty, node_id) {
                 Ok(def) => Some(def),
                 Err(error) => {
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index f9a22e2a577..5896a34b0d1 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -568,7 +568,8 @@ fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
 
     let (fty, explicit_self_category) =
         AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
-                              sig, untransformed_rcvr_ty);
+                              sig,
+                              untransformed_rcvr_ty);
 
     let def_id = ccx.tcx.map.local_def_id(id);
     let substs = mk_item_substs(ccx, &ty_generics);
diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs
index af21c7148ef..5f2997a86a9 100644
--- a/src/librustc_typeck/diagnostics.rs
+++ b/src/librustc_typeck/diagnostics.rs
@@ -45,16 +45,16 @@ Matching with the wrong number of fields has no sensible interpretation:
 
 ```compile_fail
 enum Fruit {
-    Fruit::Apple(String, String),
-    Fruit::Pear(u32),
+    Apple(String, String),
+    Pear(u32),
 }
 
 let x = Fruit::Apple(String::new(), String::new());
 
 // Incorrect.
 match x {
-    Apple(a) => {},
-    Apple(a, b, c) => {},
+    Fruit::Apple(a) => {},
+    Fruit::Apple(a, b, c) => {},
 }
 ```
 
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index ce83c4a258c..ca138168b29 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -795,7 +795,17 @@ impl Clean<Lifetime> for hir::Lifetime {
 
 impl Clean<Lifetime> for hir::LifetimeDef {
     fn clean(&self, _: &DocContext) -> Lifetime {
-        Lifetime(self.lifetime.name.to_string())
+        if self.bounds.len() > 0 {
+            let mut s = format!("{}: {}",
+                                self.lifetime.name.to_string(),
+                                self.bounds[0].name.to_string());
+            for bound in self.bounds.iter().skip(1) {
+                s.push_str(&format!(" + {}", bound.name.to_string()));
+            }
+            Lifetime(s)
+        } else {
+            Lifetime(self.lifetime.name.to_string())
+        }
     }
 }
 
@@ -1626,7 +1636,7 @@ impl Clean<Type> for hir::Ty {
                     segments: segments.into(),
                 };
                 Type::QPath {
-                    name: p.segments.last().unwrap().identifier.name.clean(cx),
+                    name: p.segments.last().unwrap().name.clean(cx),
                     self_type: box qself.ty.clean(cx),
                     trait_: box resolve_type(cx, trait_path.clean(cx), self.id)
                 }
@@ -2064,7 +2074,7 @@ pub struct PathSegment {
 impl Clean<PathSegment> for hir::PathSegment {
     fn clean(&self, cx: &DocContext) -> PathSegment {
         PathSegment {
-            name: self.identifier.name.clean(cx),
+            name: self.name.clean(cx),
             params: self.parameters.clean(cx)
         }
     }
@@ -2073,7 +2083,7 @@ impl Clean<PathSegment> for hir::PathSegment {
 fn path_to_string(p: &hir::Path) -> String {
     let mut s = String::new();
     let mut first = true;
-    for i in p.segments.iter().map(|x| x.identifier.name.as_str()) {
+    for i in p.segments.iter().map(|x| x.name.as_str()) {
         if !first || p.global {
             s.push_str("::");
         } else {
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 6d45980b45d..61985d39080 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -134,8 +134,10 @@ pub fn run_core(search_paths: SearchPaths,
                                                                false,
                                                                codemap.clone());
 
-    let cstore = Rc::new(CStore::new(token::get_ident_interner()));
-    let sess = session::build_session_(sessopts, cpath, diagnostic_handler,
+    let dep_graph = DepGraph::new(false);
+    let _ignore = dep_graph.in_ignore();
+    let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
+    let sess = session::build_session_(sessopts, &dep_graph, cpath, diagnostic_handler,
                                        codemap, cstore.clone());
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
 
@@ -151,15 +153,14 @@ pub fn run_core(search_paths: SearchPaths,
                     .expect("phase_2_configure_and_expand aborted in rustdoc!");
 
     let krate = driver::assign_node_ids(&sess, krate);
-    let dep_graph = DepGraph::new(false);
 
     let mut defs = hir_map::collect_definitions(&krate);
     read_local_crates(&sess, &cstore, &defs, &krate, &name, &dep_graph);
 
     // Lower ast -> hir and resolve.
     let (analysis, resolutions, mut hir_forest) = {
-        driver::lower_and_resolve(&sess, &name, &mut defs, &krate, dep_graph,
-                                  resolve::MakeGlobMap::No)
+        driver::lower_and_resolve(&sess, &name, &mut defs, &krate,
+                                  &sess.dep_graph, resolve::MakeGlobMap::No)
     };
 
     let arenas = ty::CtxtArenas::new();
@@ -172,12 +173,10 @@ pub fn run_core(search_paths: SearchPaths,
                                                      &arenas,
                                                      &name,
                                                      |tcx, _, analysis, result| {
-        // Return if the driver hit an err (in `result`)
         if let Err(_) = result {
-            return None
+            sess.fatal("Compilation failed, aborting rustdoc");
         }
 
-        let _ignore = tcx.dep_graph.in_ignore();
         let ty::CrateAnalysis { access_levels, .. } = analysis;
 
         // Convert from a NodeId set to a DefId set since we don't always have easy access
@@ -206,6 +205,6 @@ pub fn run_core(search_paths: SearchPaths,
             v.clean(&ctxt)
         };
 
-        Some((krate, ctxt.renderinfo.into_inner()))
-    }), &sess).unwrap()
+        (krate, ctxt.renderinfo.into_inner())
+    }), &sess)
 }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index 005e25b07d4..a103acadcf6 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -1566,7 +1566,8 @@ impl<'a> fmt::Display for Item<'a> {
         write!(fmt, "</span>")?; // in-band
         write!(fmt, "<span class='out-of-band'>")?;
         if let Some(version) = self.item.stable_since() {
-            write!(fmt, "<span class='since'>{}</span>", version)?;
+            write!(fmt, "<span class='since' title='Stable since Rust version {0}'>{0}</span>",
+                   version)?;
         }
         write!(fmt,
                r##"<span id='render-detail'>
@@ -2136,7 +2137,7 @@ fn render_stability_since_raw<'a>(w: &mut fmt::Formatter,
                                   containing_ver: Option<&'a str>) -> fmt::Result {
     if let Some(v) = ver {
         if containing_ver != ver && v.len() > 0 {
-            write!(w, "<div class=\"since\">{}</div>",
+            write!(w, "<div class='since' title='Stable since Rust version {0}'>{0}</div>",
                    v)?
         }
     }
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index d256e939afc..a52a914fea6 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -640,6 +640,10 @@ span.since {
     margin-right: 5px;
 }
 
+:target > code {
+   background: #FDFFD3;
+}
+
 /* Media Queries */
 
 @media (max-width: 700px) {
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index e4fbdba77a4..2754f77444c 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -79,8 +79,11 @@ pub fn run(input: &str,
                                                                false,
                                                                codemap.clone());
 
-    let cstore = Rc::new(CStore::new(token::get_ident_interner()));
+    let dep_graph = DepGraph::new(false);
+    let _ignore = dep_graph.in_ignore();
+    let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
     let sess = session::build_session_(sessopts,
+                                       &dep_graph,
                                        Some(input_path.clone()),
                                        diagnostic_handler,
                                        codemap,
@@ -98,12 +101,12 @@ pub fn run(input: &str,
     let defs = hir_map::collect_definitions(&krate);
 
     let mut dummy_resolver = DummyResolver;
-    let krate = lower_crate(&krate, &sess, &mut dummy_resolver);
+    let krate = lower_crate(&sess, &krate, &sess, &mut dummy_resolver);
 
     let opts = scrape_test_config(&krate);
 
     let _ignore = dep_graph.in_ignore();
-    let mut forest = hir_map::Forest::new(krate, dep_graph.clone());
+    let mut forest = hir_map::Forest::new(krate, &dep_graph);
     let map = hir_map::map_crate(&mut forest, defs);
 
     let ctx = core::DocContext {
@@ -238,8 +241,10 @@ fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
     // Compile the code
     let diagnostic_handler = errors::Handler::with_emitter(true, false, box emitter);
 
-    let cstore = Rc::new(CStore::new(token::get_ident_interner()));
+    let dep_graph = DepGraph::new(false);
+    let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
     let sess = session::build_session_(sessopts,
+                                       &dep_graph,
                                        None,
                                        diagnostic_handler,
                                        codemap,
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 99e6ba8c770..dc26370590c 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -101,7 +101,9 @@
 //! ## Blocking support: park and unpark
 //!
 //! Every thread is equipped with some basic low-level blocking support, via the
-//! `park` and `unpark` functions.
+//! `thread::park()` function and `thread::Thread::unpark()` method. `park()`
+//! blocks the current thread, which can then be resumed from another thread by
+//! calling the `unpark()` method on the blocked thread's handle.
 //!
 //! Conceptually, each `Thread` handle has an associated token, which is
 //! initially not present:
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 0f3b9be3a7a..d9409d3bbd9 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -60,6 +60,10 @@ impl Name {
     pub fn as_str(self) -> token::InternedString {
         token::InternedString::new_from_name(self)
     }
+
+    pub fn unhygienize(self) -> Name {
+        token::intern(&self.as_str())
+    }
 }
 
 impl fmt::Debug for Name {
diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs
index e7007fb0568..7c9985d7d23 100644
--- a/src/libsyntax/errors/emitter.rs
+++ b/src/libsyntax/errors/emitter.rs
@@ -367,7 +367,8 @@ impl EmitterWriter {
             let mut output_vec = vec![];
 
             for span_label in msp.span_labels() {
-                let mut snippet_data = snippet_data.clone();
+                let mut snippet_data = SnippetData::new(self.cm.clone(),
+                                                        Some(span_label.span));
 
                 snippet_data.push(span_label.span,
                                   span_label.is_primary,
@@ -422,7 +423,7 @@ impl EmitterWriter {
                     &format!(" (defined in {})",
                         self.cm.span_to_filename(def_site_span)));
             }
-            let snippet = self.cm.span_to_string(sp);
+            let snippet = self.cm.span_to_string(trace.call_site);
             print_diagnostic(&mut self.dst, &snippet, Note, &diag_string, None)?;
         }
         Ok(())
@@ -524,6 +525,13 @@ impl Destination {
             }
             Style::Quotation => {
             }
+            Style::OldSkoolNote => {
+                self.start_attr(term::Attr::Bold)?;
+                self.start_attr(term::Attr::ForegroundColor(term::color::BRIGHT_GREEN))?;
+            }
+            Style::OldSkoolNoteText => {
+                self.start_attr(term::Attr::Bold)?;
+            }
             Style::UnderlinePrimary | Style::LabelPrimary => {
                 self.start_attr(term::Attr::Bold)?;
                 self.start_attr(term::Attr::ForegroundColor(lvl.color()))?;
diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs
index 7592214c0ab..f06672fe111 100644
--- a/src/libsyntax/errors/mod.rs
+++ b/src/libsyntax/errors/mod.rs
@@ -180,7 +180,7 @@ impl error::Error for ExplicitBug {
 #[must_use]
 #[derive(Clone)]
 pub struct DiagnosticBuilder<'a> {
-    emitter: &'a RefCell<Box<Emitter>>,
+    handler: &'a Handler,
     level: Level,
     message: String,
     code: Option<String>,
@@ -204,8 +204,9 @@ impl<'a> DiagnosticBuilder<'a> {
             return;
         }
 
-        self.emitter.borrow_mut().emit_struct(&self);
+        self.handler.emit.borrow_mut().emit_struct(&self);
         self.cancel();
+        self.handler.panic_if_treat_err_as_bug();
 
         // if self.is_fatal() {
         //     panic!(FatalError);
@@ -321,11 +322,11 @@ impl<'a> DiagnosticBuilder<'a> {
 
     /// Convenience function for internal use, clients should use one of the
     /// struct_* methods on Handler.
-    fn new(emitter: &'a RefCell<Box<Emitter>>,
+    fn new(handler: &'a Handler,
            level: Level,
            message: &str) -> DiagnosticBuilder<'a> {
         DiagnosticBuilder {
-            emitter: emitter,
+            handler: handler,
             level: level,
             message: message.to_owned(),
             code: None,
@@ -362,10 +363,10 @@ impl<'a> fmt::Debug for DiagnosticBuilder<'a> {
 impl<'a> Drop for DiagnosticBuilder<'a> {
     fn drop(&mut self) {
         if !panicking() && !self.cancelled() {
-            self.emitter.borrow_mut().emit(&MultiSpan::new(),
-                                           "Error constructed but not emitted",
-                                           None,
-                                           Bug);
+            self.handler.emit.borrow_mut().emit(&MultiSpan::new(),
+                                                "Error constructed but not emitted",
+                                                None,
+                                                Bug);
             panic!();
         }
     }
@@ -412,14 +413,14 @@ impl Handler {
     }
 
     pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
-        DiagnosticBuilder::new(&self.emit, Level::Cancelled, "")
+        DiagnosticBuilder::new(self, Level::Cancelled, "")
     }
 
     pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
                                                     sp: S,
                                                     msg: &str)
                                                     -> DiagnosticBuilder<'a> {
-        let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
+        let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
         result.set_span(sp);
         if !self.can_emit_warnings {
             result.cancel();
@@ -431,7 +432,7 @@ impl Handler {
                                                               msg: &str,
                                                               code: &str)
                                                               -> DiagnosticBuilder<'a> {
-        let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
+        let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
         result.set_span(sp);
         result.code(code.to_owned());
         if !self.can_emit_warnings {
@@ -440,7 +441,7 @@ impl Handler {
         result
     }
     pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
-        let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
+        let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
         if !self.can_emit_warnings {
             result.cancel();
         }
@@ -451,7 +452,7 @@ impl Handler {
                                                    msg: &str)
                                                    -> DiagnosticBuilder<'a> {
         self.bump_err_count();
-        let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg);
+        let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
         result.set_span(sp);
         result
     }
@@ -461,21 +462,21 @@ impl Handler {
                                                              code: &str)
                                                              -> DiagnosticBuilder<'a> {
         self.bump_err_count();
-        let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg);
+        let mut result = DiagnosticBuilder::new(self, Level::Error, msg);
         result.set_span(sp);
         result.code(code.to_owned());
         result
     }
     pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
         self.bump_err_count();
-        DiagnosticBuilder::new(&self.emit, Level::Error, msg)
+        DiagnosticBuilder::new(self, Level::Error, msg)
     }
     pub fn struct_span_fatal<'a, S: Into<MultiSpan>>(&'a self,
                                                      sp: S,
                                                      msg: &str)
                                                      -> DiagnosticBuilder<'a> {
         self.bump_err_count();
-        let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg);
+        let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
         result.set_span(sp);
         result
     }
@@ -485,14 +486,14 @@ impl Handler {
                                                                code: &str)
                                                                -> DiagnosticBuilder<'a> {
         self.bump_err_count();
-        let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg);
+        let mut result = DiagnosticBuilder::new(self, Level::Fatal, msg);
         result.set_span(sp);
         result.code(code.to_owned());
         result
     }
     pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
         self.bump_err_count();
-        DiagnosticBuilder::new(&self.emit, Level::Fatal, msg)
+        DiagnosticBuilder::new(self, Level::Fatal, msg)
     }
 
     pub fn cancel(&mut self, err: &mut DiagnosticBuilder) {
@@ -503,36 +504,35 @@ impl Handler {
         err.cancel();
     }
 
-    pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> FatalError {
+    fn panic_if_treat_err_as_bug(&self) {
         if self.treat_err_as_bug {
-            self.span_bug(sp, msg);
+            panic!("encountered error with `-Z treat_err_as_bug");
         }
+    }
+
+    pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str)
+                                          -> FatalError {
         self.emit(&sp.into(), msg, Fatal);
         self.bump_err_count();
+        self.panic_if_treat_err_as_bug();
         return FatalError;
     }
     pub fn span_fatal_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str)
-    -> FatalError {
-        if self.treat_err_as_bug {
-            self.span_bug(sp, msg);
-        }
+                                                    -> FatalError {
         self.emit_with_code(&sp.into(), msg, code, Fatal);
         self.bump_err_count();
+        self.panic_if_treat_err_as_bug();
         return FatalError;
     }
     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
-        if self.treat_err_as_bug {
-            self.span_bug(sp, msg);
-        }
         self.emit(&sp.into(), msg, Error);
         self.bump_err_count();
+        self.panic_if_treat_err_as_bug();
     }
     pub fn span_err_with_code<S: Into<MultiSpan>>(&self, sp: S, msg: &str, code: &str) {
-        if self.treat_err_as_bug {
-            self.span_bug(sp, msg);
-        }
         self.emit_with_code(&sp.into(), msg, code, Error);
         self.bump_err_count();
+        self.panic_if_treat_err_as_bug();
     }
     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
         self.emit(&sp.into(), msg, Warning);
@@ -699,13 +699,13 @@ pub fn expect<T, M>(diag: &Handler, opt: Option<T>, msg: M) -> T where
 ///
 /// FIXME(#33240)
 #[cfg(not(test))]
-fn check_old_skool() -> bool {
+pub fn check_old_skool() -> bool {
     use std::env;
     env::var("RUST_NEW_ERROR_FORMAT").is_err()
 }
 
 /// For unit tests, use the new format.
 #[cfg(test)]
-fn check_old_skool() -> bool {
+pub fn check_old_skool() -> bool {
     false
 }
diff --git a/src/libsyntax/errors/snippet/mod.rs b/src/libsyntax/errors/snippet/mod.rs
index 092effbb2f6..188e676e7df 100644
--- a/src/libsyntax/errors/snippet/mod.rs
+++ b/src/libsyntax/errors/snippet/mod.rs
@@ -58,6 +58,9 @@ struct Annotation {
     /// Is this annotation derived from primary span
     is_primary: bool,
 
+    /// Is this a large span minimized down to a smaller span
+    is_minimized: bool,
+
     /// Optional label to display adjacent to the annotation.
     label: Option<String>,
 }
@@ -90,6 +93,8 @@ pub enum Style {
     UnderlineSecondary,
     LabelPrimary,
     LabelSecondary,
+    OldSkoolNoteText,
+    OldSkoolNote,
     NoStyle,
 }
 
@@ -382,10 +387,10 @@ impl FileInfo {
         // Basically, although this loses information, multi-line spans just
         // never look good.
 
-        let (line, start_col, mut end_col) = if lines.len() == 1 {
-            (lines[0].line_index, lines[0].start_col, lines[0].end_col)
+        let (line, start_col, mut end_col, is_minimized) = if lines.len() == 1 {
+            (lines[0].line_index, lines[0].start_col, lines[0].end_col, false)
         } else {
-            (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1))
+            (lines[0].line_index, lines[0].start_col, CharPos(lines[0].start_col.0 + 1), true)
         };
 
         // Watch out for "empty spans". If we get a span like 6..6, we
@@ -401,6 +406,7 @@ impl FileInfo {
         self.lines[index].push_annotation(start_col,
                                           end_col,
                                           is_primary,
+                                          is_minimized,
                                           label);
     }
 
@@ -497,6 +503,30 @@ impl FileInfo {
                     match self.primary_span {
                         Some(span) => {
                             let lo = codemap.lookup_char_pos(span.lo);
+                            let hi = codemap.lookup_char_pos(span.hi);
+                            //Before each secondary line in old skool-mode, print the label
+                            //as an old-style note
+                            if !line.annotations[0].is_primary {
+                                if let Some(ann) = line.annotations[0].label.clone() {
+                                    output.push(RenderedLine {
+                                        text: vec![StyledString {
+                                            text: lo.file.name.clone(),
+                                            style: Style::FileNameStyle,
+                                        }, StyledString {
+                                            text: format!(":{}:{}: {}:{} ", lo.line, lo.col.0 + 1,
+                                                hi.line, hi.col.0+1),
+                                            style: Style::LineAndColumn,
+                                        }, StyledString {
+                                            text: format!("note: "),
+                                            style: Style::OldSkoolNote,
+                                        }, StyledString {
+                                            text: format!("{}", ann),
+                                            style: Style::OldSkoolNoteText,
+                                        }],
+                                        kind: RenderedLineKind::Annotations,
+                                    });
+                                }
+                            }
                             rendered_lines[0].text.insert(0, StyledString {
                                 text: format!(":{} ", lo.line),
                                 style: Style::LineAndColumn,
@@ -598,7 +628,7 @@ impl FileInfo {
                             if annotation.is_primary {
                                 Style::UnderlinePrimary
                             } else {
-                                Style::UnderlineSecondary
+                                Style::OldSkoolNote
                             });
                     }
                     else {
@@ -606,7 +636,7 @@ impl FileInfo {
                             if annotation.is_primary {
                                 Style::UnderlinePrimary
                             } else {
-                                Style::UnderlineSecondary
+                                Style::OldSkoolNote
                             });
                     }
                 }
@@ -615,10 +645,14 @@ impl FileInfo {
                 for p in annotation.start_col .. annotation.end_col {
                     if annotation.is_primary {
                         styled_buffer.putc(1, p, '^', Style::UnderlinePrimary);
-                        styled_buffer.set_style(0, p, Style::UnderlinePrimary);
+                        if !annotation.is_minimized {
+                            styled_buffer.set_style(0, p, Style::UnderlinePrimary);
+                        }
                     } else {
                         styled_buffer.putc(1, p, '-', Style::UnderlineSecondary);
-                        styled_buffer.set_style(0, p, Style::UnderlineSecondary);
+                        if !annotation.is_minimized {
+                            styled_buffer.set_style(0, p, Style::UnderlineSecondary);
+                        }
                     }
                 }
             }
@@ -819,11 +853,13 @@ impl Line {
                        start: CharPos,
                        end: CharPos,
                        is_primary: bool,
+                       is_minimized: bool,
                        label: Option<String>) {
         self.annotations.push(Annotation {
             start_col: start.0,
             end_col: end.0,
             is_primary: is_primary,
+            is_minimized: is_minimized,
             label: label,
         });
     }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 65df379781e..f243706eecb 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -70,15 +70,9 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
 
             // Keep going, outside-in.
             let fully_expanded = fld.fold_expr(expanded_expr);
-            let span = fld.new_span(span);
             fld.cx.bt_pop();
 
-            fully_expanded.map(|e| ast::Expr {
-                id: ast::DUMMY_NODE_ID,
-                node: e.node,
-                span: span,
-                attrs: e.attrs,
-            })
+            fully_expanded
         }
 
         ast::ExprKind::InPlace(placer, value_expr) => {
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index 6c61d6b914c..abfa6558064 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -67,8 +67,7 @@ struct Context<'a, 'b:'a> {
 
     name_positions: HashMap<String, usize>,
 
-    /// Updated as arguments are consumed or methods are entered
-    nest_level: usize,
+    /// Updated as arguments are consumed
     next_arg: usize,
 }
 
@@ -164,9 +163,7 @@ impl<'a, 'b> Context<'a, 'b> {
                 let pos = match arg.position {
                     parse::ArgumentNext => {
                         let i = self.next_arg;
-                        if self.check_positional_ok() {
-                            self.next_arg += 1;
-                        }
+                        self.next_arg += 1;
                         Exact(i)
                     }
                     parse::ArgumentIs(i) => Exact(i),
@@ -189,25 +186,13 @@ impl<'a, 'b> Context<'a, 'b> {
                 self.verify_arg_type(Named(s.to_string()), Unsigned);
             }
             parse::CountIsNextParam => {
-                if self.check_positional_ok() {
-                    let next_arg = self.next_arg;
-                    self.verify_arg_type(Exact(next_arg), Unsigned);
-                    self.next_arg += 1;
-                }
+                let next_arg = self.next_arg;
+                self.verify_arg_type(Exact(next_arg), Unsigned);
+                self.next_arg += 1;
             }
         }
     }
 
-    fn check_positional_ok(&mut self) -> bool {
-        if self.nest_level != 0 {
-            self.ecx.span_err(self.fmtsp, "cannot use implicit positional \
-                                           arguments nested inside methods");
-            false
-        } else {
-            true
-        }
-    }
-
     fn describe_num_args(&self) -> String {
         match self.args.len() {
             0 => "no arguments given".to_string(),
@@ -655,7 +640,6 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt, sp: Span,
         name_positions: HashMap::new(),
         name_types: HashMap::new(),
         name_ordering: name_ordering,
-        nest_level: 0,
         next_arg: 0,
         literal: String::new(),
         pieces: Vec::new(),
diff --git a/src/test/compile-fail/E0027.rs b/src/test/compile-fail/E0027.rs
new file mode 100644
index 00000000000..b2f20442b77
--- /dev/null
+++ b/src/test/compile-fail/E0027.rs
@@ -0,0 +1,22 @@
+// 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.
+
+struct Dog {
+    name: String,
+    age: u32,
+}
+
+fn main() {
+    let d = Dog { name: "Rusty".to_string(), age: 8 };
+
+    match d {
+        Dog { age: x } => {} //~ ERROR E0027
+    }
+}
diff --git a/src/test/compile-fail/E0029.rs b/src/test/compile-fail/E0029.rs
new file mode 100644
index 00000000000..9cbdec99520
--- /dev/null
+++ b/src/test/compile-fail/E0029.rs
@@ -0,0 +1,18 @@
+// 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.
+
+fn main() {
+    let s = "hoho";
+
+    match s {
+        "hello" ... "world" => {} //~ ERROR E0029
+        _ => {}
+    }
+}
diff --git a/src/test/compile-fail/E0030.rs b/src/test/compile-fail/E0030.rs
new file mode 100644
index 00000000000..7f26f6cdb84
--- /dev/null
+++ b/src/test/compile-fail/E0030.rs
@@ -0,0 +1,16 @@
+// 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.
+
+
+fn main() {
+    match 5u32 {
+        1000 ... 5 => {} //~ ERROR E0030
+    }
+}
diff --git a/src/test/compile-fail/E0033.rs b/src/test/compile-fail/E0033.rs
new file mode 100644
index 00000000000..946600013f3
--- /dev/null
+++ b/src/test/compile-fail/E0033.rs
@@ -0,0 +1,19 @@
+// 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.
+
+trait SomeTrait {
+    fn foo();
+}
+
+fn main() {
+    let trait_obj: &SomeTrait = SomeTrait; //~ ERROR E0425
+                                           //~^ ERROR E0038
+    let &invalid = trait_obj; //~ ERROR E0033
+}
diff --git a/src/test/compile-fail/E0034.rs b/src/test/compile-fail/E0034.rs
new file mode 100644
index 00000000000..669bece0f7d
--- /dev/null
+++ b/src/test/compile-fail/E0034.rs
@@ -0,0 +1,26 @@
+// 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.
+
+struct Test;
+
+trait Trait1 {
+    fn foo();
+}
+
+trait Trait2 {
+    fn foo();
+}
+
+impl Trait1 for Test { fn foo() {} }
+impl Trait2 for Test { fn foo() {} }
+
+fn main() {
+    Test::foo() //~ ERROR E0034
+}
diff --git a/src/test/compile-fail/E0035.rs b/src/test/compile-fail/E0035.rs
new file mode 100644
index 00000000000..43f46e3578c
--- /dev/null
+++ b/src/test/compile-fail/E0035.rs
@@ -0,0 +1,20 @@
+// 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.
+
+struct Test;
+
+impl Test {
+    fn method(&self) {}
+}
+
+fn main() {
+    let x = Test;
+    x.method::<i32>(); //~ ERROR E0035
+}
diff --git a/src/test/compile-fail/associated-types-eq-hr.rs b/src/test/compile-fail/associated-types-eq-hr.rs
index d5678c155fd..52a2ca9082d 100644
--- a/src/test/compile-fail/associated-types-eq-hr.rs
+++ b/src/test/compile-fail/associated-types-eq-hr.rs
@@ -40,6 +40,17 @@ impl<'a> TheTrait<&'a isize> for UintStruct {
     }
 }
 
+struct Tuple {
+}
+
+impl<'a> TheTrait<(&'a isize, &'a isize)> for Tuple {
+    type A = &'a isize;
+
+    fn get(&self, t: (&'a isize, &'a isize)) -> &'a isize {
+        t.0
+    }
+}
+
 fn foo<T>()
     where T : for<'x> TheTrait<&'x isize, A = &'x isize>
 {
@@ -52,10 +63,28 @@ fn bar<T>()
     // ok for UintStruct, but not IntStruct
 }
 
-fn baz<T>()
-    where T : for<'x,'y> TheTrait<&'x isize, A = &'y isize>
+fn tuple_one<T>()
+    where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'x isize>
+{
+    // not ok for tuple, two lifetimes and we pick first
+}
+
+fn tuple_two<T>()
+    where T : for<'x,'y> TheTrait<(&'x isize, &'y isize), A = &'y isize>
 {
-    // not ok for either struct, due to the use of two lifetimes
+    // not ok for tuple, two lifetimes and we pick second
+}
+
+fn tuple_three<T>()
+    where T : for<'x> TheTrait<(&'x isize, &'x isize), A = &'x isize>
+{
+    // ok for tuple
+}
+
+fn tuple_four<T>()
+    where T : for<'x,'y> TheTrait<(&'x isize, &'y isize)>
+{
+    // not ok for tuple, two lifetimes, and lifetime matching is invariant
 }
 
 pub fn main() {
@@ -65,6 +94,16 @@ pub fn main() {
     bar::<IntStruct>(); //~ ERROR type mismatch
     bar::<UintStruct>();
 
-    baz::<IntStruct>(); //~ ERROR type mismatch
-    baz::<UintStruct>(); //~ ERROR type mismatch
+    tuple_one::<Tuple>();
+    //~^ ERROR E0277
+    //~| ERROR type mismatch
+
+    tuple_two::<Tuple>();
+    //~^ ERROR E0277
+    //~| ERROR type mismatch
+
+    tuple_three::<Tuple>();
+
+    tuple_four::<Tuple>();
+    //~^ ERROR E0277
 }
diff --git a/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs b/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs
new file mode 100644
index 00000000000..f60f06b4ec8
--- /dev/null
+++ b/src/test/compile-fail/associated-types/bound-lifetime-constrained.rs
@@ -0,0 +1,66 @@
+// 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.
+
+// revisions: func object clause
+
+#![allow(dead_code)]
+#![feature(rustc_attrs)]
+#![feature(unboxed_closures)]
+#![deny(hr_lifetime_in_assoc_type)]
+
+trait Foo<'a> {
+    type Item;
+}
+
+impl<'a> Foo<'a> for() {
+    type Item = ();
+}
+
+// Check that appearing in a projection input in the argument is not enough:
+#[cfg(func)]
+fn func1(_: for<'a> fn(<() as Foo<'a>>::Item) -> &'a i32) {
+    //[func]~^ ERROR return type references lifetime `'a`
+    //[func]~| WARNING previously accepted
+}
+
+// Check that appearing in a projection input in the return still
+// causes an error:
+#[cfg(func)]
+fn func2(_: for<'a> fn() -> <() as Foo<'a>>::Item) {
+    //[func]~^ ERROR return type references lifetime `'a`
+    //[func]~| WARNING previously accepted
+}
+
+#[cfg(object)]
+fn object1(_: Box<for<'a> Fn(<() as Foo<'a>>::Item) -> &'a i32>) {
+    //[object]~^ ERROR `Output` references lifetime `'a`
+    //[object]~| WARNING previously accepted
+}
+
+#[cfg(object)]
+fn object2(_: Box<for<'a> Fn() -> <() as Foo<'a>>::Item>) {
+    //[object]~^ ERROR `Output` references lifetime `'a`
+    //[object]~| WARNING previously accepted
+}
+
+#[cfg(clause)]
+fn clause1<T>() where T: for<'a> Fn(<() as Foo<'a>>::Item) -> &'a i32 {
+    //[clause]~^ ERROR `Output` references lifetime `'a`
+    //[clause]~| WARNING previously accepted
+}
+
+#[cfg(clause)]
+fn clause2<T>() where T: for<'a> Fn() -> <() as Foo<'a>>::Item {
+    //[clause]~^ ERROR `Output` references lifetime `'a`
+    //[clause]~| WARNING previously accepted
+}
+
+#[rustc_error]
+fn main() { } //[ok]~ ERROR compilation successful
diff --git a/src/test/compile-fail/associated-types/bound-lifetime-in-binding-only.rs b/src/test/compile-fail/associated-types/bound-lifetime-in-binding-only.rs
new file mode 100644
index 00000000000..020c9e5e1db
--- /dev/null
+++ b/src/test/compile-fail/associated-types/bound-lifetime-in-binding-only.rs
@@ -0,0 +1,90 @@
+// 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.
+
+// revisions: angle paren ok elision
+
+#![allow(dead_code)]
+#![feature(rustc_attrs)]
+#![feature(unboxed_closures)]
+#![deny(hr_lifetime_in_assoc_type)]
+
+trait Foo {
+    type Item;
+}
+
+#[cfg(angle)]
+fn angle<T: for<'a> Foo<Item=&'a i32>>() {
+    //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
+    //[angle]~| WARNING previously accepted
+}
+
+#[cfg(angle)]
+fn angle1<T>() where T: for<'a> Foo<Item=&'a i32> {
+    //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
+    //[angle]~| WARNING previously accepted
+}
+
+#[cfg(angle)]
+fn angle2<T>() where for<'a> T: Foo<Item=&'a i32> {
+    //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
+    //[angle]~| WARNING previously accepted
+}
+
+#[cfg(angle)]
+fn angle3(_: &for<'a> Foo<Item=&'a i32>) {
+    //[angle]~^ ERROR binding for associated type `Item` references lifetime `'a`
+    //[angle]~| WARNING previously accepted
+}
+
+#[cfg(paren)]
+fn paren<T: for<'a> Fn() -> &'a i32>() {
+    //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
+    //[paren]~| WARNING previously accepted
+}
+
+#[cfg(paren)]
+fn paren1<T>() where T: for<'a> Fn() -> &'a i32 {
+    //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
+    //[paren]~| WARNING previously accepted
+}
+
+#[cfg(paren)]
+fn paren2<T>() where for<'a> T: Fn() -> &'a i32 {
+    //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
+    //[paren]~| WARNING previously accepted
+}
+
+#[cfg(paren)]
+fn paren3(_: &for<'a> Fn() -> &'a i32) {
+    //[paren]~^ ERROR binding for associated type `Output` references lifetime `'a`
+    //[paren]~| WARNING previously accepted
+}
+
+#[cfg(elision)]
+fn elision<T: Fn() -> &i32>() {
+    //[elision]~^ ERROR E0106
+}
+
+struct Parameterized<'a> { x: &'a str }
+
+#[cfg(ok)]
+fn ok1<T: for<'a> Fn(&Parameterized<'a>) -> &'a i32>() {
+}
+
+#[cfg(ok)]
+fn ok2<T: for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>>() {
+}
+
+#[cfg(ok)]
+fn ok3<T>() where for<'a> Parameterized<'a>: Foo<Item=&'a i32> {
+}
+
+#[rustc_error]
+fn main() { } //[ok]~ ERROR compilation successful
diff --git a/src/test/compile-fail/associated-types/bound-lifetime-in-return-only.rs b/src/test/compile-fail/associated-types/bound-lifetime-in-return-only.rs
new file mode 100644
index 00000000000..0b4a9bf58a6
--- /dev/null
+++ b/src/test/compile-fail/associated-types/bound-lifetime-in-return-only.rs
@@ -0,0 +1,64 @@
+// 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.
+
+// revisions: sig local structure ok elision
+
+#![allow(dead_code)]
+#![feature(rustc_attrs)]
+#![feature(unboxed_closures)]
+#![deny(hr_lifetime_in_assoc_type)]
+
+trait Foo {
+    type Item;
+}
+
+#[cfg(sig)]
+fn sig1(_: for<'a> fn() -> &'a i32) {
+    //[sig]~^ ERROR return type references lifetime `'a`
+    //[sig]~| WARNING previously accepted
+}
+
+#[cfg(sig)]
+fn sig2(_: for<'a, 'b> fn(&'b i32) -> &'a i32) {
+    //[sig]~^ ERROR return type references lifetime `'a`
+    //[sig]~| WARNING previously accepted
+}
+
+#[cfg(local)]
+fn local1() {
+    let _: for<'a> fn() -> &'a i32 = loop { };
+    //[local]~^ ERROR return type references lifetime `'a`
+    //[local]~| WARNING previously accepted
+}
+
+#[cfg(structure)]
+struct Struct1 {
+    x: for<'a> fn() -> &'a i32
+    //[structure]~^ ERROR return type references lifetime `'a`
+    //[structure]~| WARNING previously accepted
+}
+
+#[cfg(elision)]
+fn elision(_: fn() -> &i32) {
+    //[elision]~^ ERROR E0106
+}
+
+struct Parameterized<'a> { x: &'a str }
+
+#[cfg(ok)]
+fn ok1(_: &for<'a> Fn(&Parameterized<'a>) -> &'a i32) {
+}
+
+#[cfg(ok)]
+fn ok2(_: &for<'a,'b> Fn<(&'b Parameterized<'a>,), Output=&'a i32>) {
+}
+
+#[rustc_error]
+fn main() { } //[ok]~ ERROR compilation successful
diff --git a/src/test/compile-fail/auxiliary/cdylib-dep.rs b/src/test/compile-fail/auxiliary/cdylib-dep.rs
new file mode 100644
index 00000000000..a3d0222a14c
--- /dev/null
+++ b/src/test/compile-fail/auxiliary/cdylib-dep.rs
@@ -0,0 +1,11 @@
+// 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.
+
+#![crate_type = "dylib"]
diff --git a/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs b/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs
index 309e286f48e..7b811f581c1 100644
--- a/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs
+++ b/src/test/compile-fail/borrowck/borrowck-borrowed-uniq-rvalue-2.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// error-pattern: borrowed value does not live long enough
+
 struct defer<'a> {
     x: &'a [&'a str],
 }
@@ -28,6 +30,5 @@ fn defer<'r>(x: &'r [&'r str]) -> defer<'r> {
 
 fn main() {
     let x = defer(&vec!("Goodbye", "world!"));
-    //~^ ERROR borrowed value does not live long enough
     x.x[0];
 }
diff --git a/src/test/compile-fail/borrowck/borrowck-move-error-with-note.rs b/src/test/compile-fail/borrowck/borrowck-move-error-with-note.rs
index ffa7d192556..5d9c9d0bd46 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-error-with-note.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-error-with-note.rs
@@ -19,8 +19,8 @@ enum Foo {
 fn blah() {
     let f = &Foo::Foo1(box 1, box 2);
     match *f {             //~ ERROR cannot move out of
-                           //~| move occurs here
-        Foo::Foo1(num1,         //~ NOTE attempting to move value to here
+                           //~| cannot move out
+        Foo::Foo1(num1,         //~ NOTE to prevent move
                   num2) => (),  //~ NOTE and here
         Foo::Foo2(num) => (),   //~ NOTE and here
         Foo::Foo3 => ()
@@ -37,9 +37,9 @@ impl Drop for S {
 
 fn move_in_match() {
     match (S {f: "foo".to_string(), g: "bar".to_string()}) {
-        S {         //~ ERROR cannot move out of type `S`, which defines the `Drop` trait
-        //~| can not move out of here
-            f: _s,  //~ NOTE attempting to move value to here
+        S {         //~ ERROR cannot move out of type `S`, which implements the `Drop` trait
+        //~| cannot move out of here
+            f: _s,  //~ NOTE to prevent move
             g: _t   //~ NOTE and here
         } => {}
     }
@@ -55,8 +55,8 @@ fn free<T>(_: T) {}
 fn blah2() {
     let a = &A { a: box 1 };
     match a.a {           //~ ERROR cannot move out of
-                          //~| move occurs here
-        n => {            //~ NOTE attempting to move value to here
+                          //~| cannot move out
+        n => {            //~ NOTE to prevent move
             free(n)
         }
     }
diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs
index 3d13cbe30c5..16302d276ce 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-struct-with-dtor.rs
@@ -16,17 +16,17 @@ impl Drop for S {
 fn move_in_match() {
     match (S {f:"foo".to_string()}) {
         S {f:_s} => {}
-        //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
+        //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
     }
 }
 
 fn move_in_let() {
     let S {f:_s} = S {f:"foo".to_string()};
-    //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
+    //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
 }
 
 fn move_in_fn_arg(S {f:_s}: S) {
-    //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
+    //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs
index 625f7184905..f5fedb8d487 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.rs
@@ -16,17 +16,17 @@ impl Drop for S {
 fn move_in_match() {
     match S("foo".to_string()) {
         S(_s) => {}
-        //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
+        //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
     }
 }
 
 fn move_in_let() {
     let S(_s) = S("foo".to_string());
-    //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
+    //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
 }
 
 fn move_in_fn_arg(S(_s): S) {
-    //~^ ERROR cannot move out of type `S`, which defines the `Drop` trait
+    //~^ ERROR cannot move out of type `S`, which implements the `Drop` trait
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs
index 2f1c69d0d7d..15771295743 100644
--- a/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs
+++ b/src/test/compile-fail/borrowck/borrowck-move-out-of-vec-tail.rs
@@ -29,8 +29,8 @@ pub fn main() {
             match tail {
                 [Foo { string: a },
                 //~^ ERROR cannot move out of borrowed content
-                //~| move occurs here
-                //~| attempting to move value to here
+                //~| cannot move out
+                //~| to prevent move
                  Foo { string: b }] => {
                     //~^ NOTE and here
                 }
diff --git a/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs b/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs
index bf1497420e2..c364788a9cc 100644
--- a/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs
+++ b/src/test/compile-fail/borrowck/borrowck-struct-update-with-dtor.rs
@@ -19,11 +19,13 @@ struct T { a: isize, mv: Box<isize> }
 impl Drop for T { fn drop(&mut self) { } }
 
 fn f(s0:S) {
-    let _s2 = S{a: 2, ..s0}; //~error: cannot move out of type `S`, which defines the `Drop` trait
+    let _s2 = S{a: 2, ..s0};
+    //~^ error: cannot move out of type `S`, which implements the `Drop` trait
 }
 
 fn g(s0:T) {
-    let _s2 = T{a: 2, ..s0}; //~error: cannot move out of type `T`, which defines the `Drop` trait
+    let _s2 = T{a: 2, ..s0};
+    //~^ error: cannot move out of type `T`, which implements the `Drop` trait
 }
 
 fn main() { }
diff --git a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs
index 1c63b458e62..eec6c8473eb 100644
--- a/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs
+++ b/src/test/compile-fail/borrowck/borrowck-vec-pattern-nesting.rs
@@ -19,7 +19,7 @@ fn a() {
         [box ref _a, _, _] => {
         //~^ borrow of `vec[..]` occurs here
             vec[0] = box 4; //~ ERROR cannot assign
-            //~^ assignment to `vec[..]` occurs here
+            //~^ assignment to borrowed `vec[..]` occurs here
         }
     }
 }
@@ -31,7 +31,7 @@ fn b() {
         [_b..] => {
         //~^ borrow of `vec[..]` occurs here
             vec[0] = box 4; //~ ERROR cannot assign
-            //~^ assignment to `vec[..]` occurs here
+            //~^ assignment to borrowed `vec[..]` occurs here
         }
     }
 }
@@ -41,8 +41,8 @@ fn c() {
     let vec: &mut [Box<isize>] = &mut vec;
     match vec {
         [_a,         //~ ERROR cannot move out
-        //~| move occurs here
-        //~| attempting to move value to here
+        //~| cannot move out
+        //~| to prevent move
          _b..] => {
             // Note: `_a` is *moved* here, but `b` is borrowing,
             // hence illegal.
@@ -53,8 +53,8 @@ fn c() {
         _ => {}
     }
     let a = vec[0]; //~ ERROR cannot move out
-    //~^ NOTE attempting to move value to here
-    //~| can not move out of here
+    //~^ NOTE to prevent move
+    //~| cannot move out of here
 }
 
 fn d() {
@@ -62,13 +62,13 @@ fn d() {
     let vec: &mut [Box<isize>] = &mut vec;
     match vec {
         [_a..,     //~ ERROR cannot move out
-        //~^ move occurs here
-         _b] => {} //~ NOTE attempting to move value to here
+        //~^ cannot move out
+         _b] => {} //~ NOTE to prevent move
         _ => {}
     }
     let a = vec[0]; //~ ERROR cannot move out
-    //~^ NOTE attempting to move value to here
-    //~| can not move out of here
+    //~^ NOTE to prevent move
+    //~| cannot move out of here
 }
 
 fn e() {
@@ -76,15 +76,15 @@ fn e() {
     let vec: &mut [Box<isize>] = &mut vec;
     match vec {
         [_a, _b, _c] => {}  //~ ERROR cannot move out
-        //~| move occurs here
-        //~| NOTE attempting to move value to here
+        //~| cannot move out
+        //~| NOTE to prevent move
         //~| NOTE and here
         //~| NOTE and here
         _ => {}
     }
     let a = vec[0]; //~ ERROR cannot move out
-    //~^ NOTE attempting to move value to here
-    //~| can not move out of here
+    //~^ NOTE to prevent move
+    //~| cannot move out of here
 }
 
 fn main() {}
diff --git a/src/test/compile-fail/cdylib-deps-must-be-static.rs b/src/test/compile-fail/cdylib-deps-must-be-static.rs
new file mode 100644
index 00000000000..4b160f26e92
--- /dev/null
+++ b/src/test/compile-fail/cdylib-deps-must-be-static.rs
@@ -0,0 +1,17 @@
+// 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.
+
+// error-pattern: dependency `cdylib_dep` not found in rlib format
+// aux-build:cdylib-dep.rs
+// ignore-musl
+
+#![crate_type = "cdylib"]
+
+extern crate cdylib_dep;
diff --git a/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs b/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs
index 5078009d4b2..38049209903 100644
--- a/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs
+++ b/src/test/compile-fail/disallowed-deconstructing-destructing-struct-match.rs
@@ -23,6 +23,6 @@ fn main() {
 
     match x {
         X { x: y } => println!("contents: {}", y)
-        //~^ ERROR cannot move out of type `X`, which defines the `Drop` trait
+        //~^ ERROR cannot move out of type `X`, which implements the `Drop` trait
     }
 }
diff --git a/src/test/compile-fail/issue-15167.rs b/src/test/compile-fail/issue-15167.rs
index 898e6be6fc8..2bd7da91d2c 100644
--- a/src/test/compile-fail/issue-15167.rs
+++ b/src/test/compile-fail/issue-15167.rs
@@ -11,22 +11,26 @@
 // macro f should not be able to inject a reference to 'n'.
 
 macro_rules! f { () => (n) }
+//~^ ERROR unresolved name `n`
+//~| ERROR unresolved name `n`
+//~| ERROR unresolved name `n`
+//~| ERROR unresolved name `n`
 
 fn main() -> (){
     for n in 0..1 {
-        println!("{}", f!()); //~ ERROR unresolved name `n`
+        println!("{}", f!());
     }
 
     if let Some(n) = None {
-        println!("{}", f!()); //~ ERROR unresolved name `n`
+        println!("{}", f!());
     }
 
     if false {
     } else if let Some(n) = None {
-        println!("{}", f!()); //~ ERROR unresolved name `n`
+        println!("{}", f!());
     }
 
     while let Some(n) = None {
-        println!("{}", f!()); //~ ERROR unresolved name `n`
+        println!("{}", f!());
     }
 }
diff --git a/src/test/compile-fail/issue-26480.rs b/src/test/compile-fail/issue-26480.rs
index adcf8484f78..634a4014e11 100644
--- a/src/test/compile-fail/issue-26480.rs
+++ b/src/test/compile-fail/issue-26480.rs
@@ -26,6 +26,8 @@ macro_rules! write {
                   $arr.len() * size_of($arr[0]));
             //~^ ERROR mismatched types
             //~| expected u64, found usize
+            //~| expected type
+            //~| found type
         }
     }}
 }
@@ -38,6 +40,8 @@ fn main() {
     let hello = ['H', 'e', 'y'];
     write!(hello);
     //~^ NOTE in this expansion of write!
+    //~| NOTE in this expansion of write!
+    //~| NOTE in this expansion of write!
 
     cast!(2);
     //~^ NOTE in this expansion of cast!
diff --git a/src/test/compile-fail/issue-30255.rs b/src/test/compile-fail/issue-30255.rs
new file mode 100644
index 00000000000..1daa6a61f77
--- /dev/null
+++ b/src/test/compile-fail/issue-30255.rs
@@ -0,0 +1,35 @@
+// 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.
+//
+// Test that lifetime elision error messages correctly omit parameters
+// with no elided lifetimes
+
+struct S<'a> {
+    field: &'a i32,
+}
+
+fn f(a: &S, b: i32) -> &i32 {
+//~^ ERROR missing lifetime specifier [E0106]
+//~^^ HELP does not say which one of `a`'s 2 elided lifetimes it is borrowed from
+    panic!();
+}
+
+fn g(a: &S, b: bool, c: &i32) -> &i32 {
+//~^ ERROR missing lifetime specifier [E0106]
+//~^^ HELP does not say whether it is borrowed from one of `a`'s 2 elided lifetimes or `c`
+    panic!();
+}
+
+fn h(a: &bool, b: bool, c: &S, d: &i32) -> &i32 {
+//~^ ERROR missing lifetime specifier [E0106]
+//~^^ HELP does not say whether it is borrowed from `a`, one of `c`'s 2 elided lifetimes, or `d`
+    panic!();
+}
+
diff --git a/src/test/compile-fail/macro-backtrace-invalid-internals.rs b/src/test/compile-fail/macro-backtrace-invalid-internals.rs
index 5069ec7d284..ebec204184d 100644
--- a/src/test/compile-fail/macro-backtrace-invalid-internals.rs
+++ b/src/test/compile-fail/macro-backtrace-invalid-internals.rs
@@ -36,13 +36,13 @@ macro_rules! fake_method_expr {
 
 macro_rules! fake_field_expr {
      () => {
-          1.fake
+          1.fake //~ ERROR no field with that name
      }
 }
 
 macro_rules! fake_anon_field_expr {
      () => {
-          (1).0
+          (1).0 //~ ERROR type was not a tuple
      }
 }
 
@@ -52,8 +52,6 @@ fn main() {
     fake_anon_field_stmt!(); //~ NOTE in this expansion of
 
     let _ = fake_method_expr!(); //~ NOTE in this expansion of
-    let _ = fake_field_expr!(); //~ ERROR no field with that name
-                                //~^ NOTE in this expansion of
-    let _ = fake_anon_field_expr!(); //~ ERROR type was not a tuple
-                                     //~^ NOTE in this expansion of
+    let _ = fake_field_expr!(); //~ NOTE in this expansion of
+    let _ = fake_anon_field_expr!(); //~ NOTE in this expansion of
 }
diff --git a/src/test/compile-fail/macro-backtrace-nested.rs b/src/test/compile-fail/macro-backtrace-nested.rs
index c935ccef055..c2a270ea9f5 100644
--- a/src/test/compile-fail/macro-backtrace-nested.rs
+++ b/src/test/compile-fail/macro-backtrace-nested.rs
@@ -12,20 +12,19 @@
 // we replace the span of the expanded expression with that of the call site.
 
 macro_rules! nested_expr {
-    () => (fake)
+    () => (fake) //~ ERROR unresolved name
+                 //~^ ERROR unresolved name
 }
 
 macro_rules! call_nested_expr {
-    () => (nested_expr!())
+    () => (nested_expr!()) //~ NOTE in this expansion of nested_expr!
 }
 
 macro_rules! call_nested_expr_sum {
-    () => { 1 + nested_expr!(); } //~ ERROR unresolved name
-                                  //~^ NOTE in this expansion of nested_expr!
+    () => { 1 + nested_expr!(); } //~ NOTE in this expansion of nested_expr!
 }
 
 fn main() {
-    1 + call_nested_expr!(); //~ ERROR unresolved name
-                             //~^ NOTE in this expansion of call_nested_expr!
+    1 + call_nested_expr!(); //~ NOTE in this expansion of call_nested_expr!
     call_nested_expr_sum!(); //~ NOTE in this expansion of
 }
diff --git a/src/test/compile-fail/macro-backtrace-println.rs b/src/test/compile-fail/macro-backtrace-println.rs
index a485b9056de..c2277c3e6d8 100644
--- a/src/test/compile-fail/macro-backtrace-println.rs
+++ b/src/test/compile-fail/macro-backtrace-println.rs
@@ -21,11 +21,11 @@ macro_rules! myprint {
 }
 
 macro_rules! myprintln {
-    ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ ERROR invalid reference to argument `0`
-                                                    //~^ NOTE in this expansion of myprint!
-                                                    //~^^ NOTE in this expansion of concat!
+    ($fmt:expr) => (myprint!(concat!($fmt, "\n"))); //~ NOTE in this expansion of myprint!
+                                                    //~^ NOTE in this expansion of concat!
 }
 
 fn main() {
-    myprintln!("{}"); //~ NOTE in this expansion of
+    myprintln!("{}"); //~ ERROR invalid reference to argument `0`
+                      //~^ NOTE in this expansion of
 }
diff --git a/src/test/compile-fail/moves-based-on-type-block-bad.rs b/src/test/compile-fail/moves-based-on-type-block-bad.rs
index 1fd69e2dbfe..deaff3c3521 100644
--- a/src/test/compile-fail/moves-based-on-type-block-bad.rs
+++ b/src/test/compile-fail/moves-based-on-type-block-bad.rs
@@ -32,9 +32,10 @@ fn main() {
     loop {
         f(&s, |hellothere| {
             match hellothere.x { //~ ERROR cannot move out
-                                 //~| move occurs here
+                                 //~| cannot move out of borrowed content
                 box E::Foo(_) => {}
-                box E::Bar(x) => println!("{}", x.to_string()), //~ NOTE attempting to move value to here
+                box E::Bar(x) => println!("{}", x.to_string()),
+                //~^ NOTE to prevent move
                 box E::Baz => {}
             }
         })
diff --git a/src/test/compile-fail/on-unimplemented-bad-anno.rs b/src/test/compile-fail/on-unimplemented/bad-annotation.rs
index 8580749084d..8580749084d 100644
--- a/src/test/compile-fail/on-unimplemented-bad-anno.rs
+++ b/src/test/compile-fail/on-unimplemented/bad-annotation.rs
diff --git a/src/test/compile-fail/on-unimplemented/multiple-impls.rs b/src/test/compile-fail/on-unimplemented/multiple-impls.rs
new file mode 100644
index 00000000000..0df8c41ffe1
--- /dev/null
+++ b/src/test/compile-fail/on-unimplemented/multiple-impls.rs
@@ -0,0 +1,55 @@
+// 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.
+
+// Test if the on_unimplemented message override works
+
+#![feature(on_unimplemented)]
+#![feature(rustc_attrs)]
+
+struct Foo<T>(T);
+struct Bar<T>(T);
+
+#[rustc_on_unimplemented = "trait message"]
+trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+#[rustc_on_unimplemented = "on impl for Foo"]
+impl Index<Foo<usize>> for [i32] {
+    type Output = i32;
+    fn index(&self, _index: Foo<usize>) -> &i32 {
+        loop {}
+    }
+}
+
+#[rustc_on_unimplemented = "on impl for Bar"]
+impl Index<Bar<usize>> for [i32] {
+    type Output = i32;
+    fn index(&self, _index: Bar<usize>) -> &i32 {
+        loop {}
+    }
+}
+
+#[rustc_error]
+fn main() {
+    Index::index(&[] as &[i32], 2u32);
+    //~^ ERROR E0277
+    //~| NOTE trait message
+    //~| NOTE required by
+    Index::index(&[] as &[i32], Foo(2u32));
+    //~^ ERROR E0277
+    //~| NOTE on impl for Foo
+    //~| NOTE required by
+    Index::index(&[] as &[i32], Bar(2u32));
+    //~^ ERROR E0277
+    //~| NOTE on impl for Bar
+    //~| NOTE required by
+}
diff --git a/src/test/compile-fail/check_on_unimplemented.rs b/src/test/compile-fail/on-unimplemented/on-impl.rs
index 4471b625d79..4471b625d79 100644
--- a/src/test/compile-fail/check_on_unimplemented.rs
+++ b/src/test/compile-fail/on-unimplemented/on-impl.rs
diff --git a/src/test/compile-fail/on-unimplemented.rs b/src/test/compile-fail/on-unimplemented/on-trait.rs
index 39ce1b33ca1..39ce1b33ca1 100644
--- a/src/test/compile-fail/on-unimplemented.rs
+++ b/src/test/compile-fail/on-unimplemented/on-trait.rs
diff --git a/src/test/compile-fail/check_on_unimplemented_on_slice.rs b/src/test/compile-fail/on-unimplemented/slice-index.rs
index 6f4b211452c..6a8f9d471e1 100644
--- a/src/test/compile-fail/check_on_unimplemented_on_slice.rs
+++ b/src/test/compile-fail/on-unimplemented/slice-index.rs
@@ -18,5 +18,7 @@ use std::ops::Index;
 fn main() {
     let x = &[1, 2, 3] as &[i32];
     x[1i32]; //~ ERROR E0277
-             //~| NOTE a usize is required
+             //~| NOTE slice indices are of type `usize`
+    x[..1i32]; //~ ERROR E0277
+               //~| NOTE slice indices are of type `usize`
 }
diff --git a/src/test/compile-fail/variant-used-as-type.rs b/src/test/compile-fail/variant-used-as-type.rs
new file mode 100644
index 00000000000..73defa6eef9
--- /dev/null
+++ b/src/test/compile-fail/variant-used-as-type.rs
@@ -0,0 +1,30 @@
+// 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.
+
+// Test error message when enum variants are used as types
+
+
+// issue 21225
+enum Ty {
+    A,
+    B(Ty::A),
+    //~^ ERROR: found value `Ty::A` used as a type
+}
+
+
+// issue 19197
+enum E {
+    A
+}
+
+impl E::A {}
+//~^ ERROR: found value `E::A` used as a type
+
+fn main() {}
diff --git a/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs b/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs
new file mode 100644
index 00000000000..d802c9a8352
--- /dev/null
+++ b/src/test/incremental/callee_caller_cross_crate/auxiliary/a.rs
@@ -0,0 +1,24 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="rlib"]
+
+#[cfg(rpass1)]
+pub fn function0(x: u32) -> u32 {
+    x
+}
+
+#[cfg(rpass2)]
+pub fn function0(x: i32) -> i32 {
+    x
+}
+
+pub fn function1(x: u32) {
+}
diff --git a/src/test/incremental/callee_caller_cross_crate/b.rs b/src/test/incremental/callee_caller_cross_crate/b.rs
new file mode 100644
index 00000000000..e81f828beb1
--- /dev/null
+++ b/src/test/incremental/callee_caller_cross_crate/b.rs
@@ -0,0 +1,28 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:a.rs
+// revisions:rpass1 rpass2
+
+#![feature(rustc_attrs)]
+
+extern crate a;
+
+#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+pub fn call_function0() {
+    a::function0(77);
+}
+
+#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
+pub fn call_function1() {
+    a::function1(77);
+}
+
+pub fn main() { }
diff --git a/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs
new file mode 100644
index 00000000000..2494dca0509
--- /dev/null
+++ b/src/test/incremental/type_alias_cross_crate/auxiliary/a.rs
@@ -0,0 +1,21 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type="rlib"]
+
+#[cfg(rpass1)]
+pub type X = u32;
+
+#[cfg(rpass2)]
+pub type X = i32;
+
+pub type Y = char;
+
+pub fn foo() { }
diff --git a/src/test/incremental/type_alias_cross_crate/b.rs b/src/test/incremental/type_alias_cross_crate/b.rs
new file mode 100644
index 00000000000..b4e9b760101
--- /dev/null
+++ b/src/test/incremental/type_alias_cross_crate/b.rs
@@ -0,0 +1,29 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:a.rs
+// revisions:rpass1 rpass2
+
+#![feature(rustc_attrs)]
+
+extern crate a;
+
+#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
+pub fn use_X() -> u32 {
+    let x: a::X = 22;
+    x as u32
+}
+
+#[rustc_clean(label="TypeckItemBody", cfg="rpass2")]
+pub fn use_Y() {
+    let x: a::Y = 'c';
+}
+
+pub fn main() { }
diff --git a/src/test/run-make/cdylib/Makefile b/src/test/run-make/cdylib/Makefile
new file mode 100644
index 00000000000..ae3b82537db
--- /dev/null
+++ b/src/test/run-make/cdylib/Makefile
@@ -0,0 +1,19 @@
+include ../tools.mk
+
+all: $(call RUN_BINFILE,foo)
+	$(call RUN,foo)
+	rm $(call DYLIB,foo)
+	$(RUSTC) foo.rs -C lto
+	$(call RUN,foo)
+
+ifdef IS_MSVC
+$(call RUN_BINFILE,foo): $(call DYLIB,foo)
+	$(CC) $(CFLAGS) foo.c $(TMPDIR)/foo.dll.lib -Fe:`cygpath -w $@`
+else
+$(call RUN_BINFILE,foo): $(call DYLIB,foo)
+	$(CC) $(CFLAGS) foo.c -lfoo -o $(call RUN_BINFILE,foo) -L $(TMPDIR)
+endif
+
+$(call DYLIB,foo):
+	$(RUSTC) bar.rs
+	$(RUSTC) foo.rs
diff --git a/src/test/run-make/cdylib/bar.rs b/src/test/run-make/cdylib/bar.rs
new file mode 100644
index 00000000000..2c97298604c
--- /dev/null
+++ b/src/test/run-make/cdylib/bar.rs
@@ -0,0 +1,15 @@
+// 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.
+
+#![crate_type = "rlib"]
+
+pub fn bar() {
+    println!("hello!");
+}
diff --git a/src/test/run-make/cdylib/foo.c b/src/test/run-make/cdylib/foo.c
new file mode 100644
index 00000000000..1c950427c65
--- /dev/null
+++ b/src/test/run-make/cdylib/foo.c
@@ -0,0 +1,20 @@
+// 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.
+
+#include <assert.h>
+
+extern void foo();
+extern unsigned bar(unsigned a, unsigned b);
+
+int main() {
+  foo();
+  assert(bar(1, 2) == 3);
+  return 0;
+}
diff --git a/src/test/run-make/cdylib/foo.rs b/src/test/run-make/cdylib/foo.rs
new file mode 100644
index 00000000000..cdac6d19035
--- /dev/null
+++ b/src/test/run-make/cdylib/foo.rs
@@ -0,0 +1,23 @@
+// 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.
+
+#![crate_type = "cdylib"]
+
+extern crate bar;
+
+#[no_mangle]
+pub extern fn foo() {
+    bar::bar();
+}
+
+#[no_mangle]
+pub extern fn bar(a: u32, b: u32) -> u32 {
+    a + b
+}
diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs
index 0ad113b8d8b..0e84a0f5221 100644
--- a/src/test/run-make/execution-engine/test.rs
+++ b/src/test/run-make/execution-engine/test.rs
@@ -223,8 +223,12 @@ fn compile_program(input: &str, sysroot: PathBuf)
 
     let handle = thread.spawn(move || {
         let opts = build_exec_options(sysroot);
-        let cstore = Rc::new(CStore::new(token::get_ident_interner()));
-        let sess = build_session(opts, None, Registry::new(&rustc::DIAGNOSTICS),
+        let dep_graph = DepGraph::new(opts.build_dep_graph());
+        let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
+        let sess = build_session(opts,
+                                 &dep_graph,
+                                 None,
+                                 Registry::new(&rustc::DIAGNOSTICS),
                                  cstore.clone());
         rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
 
@@ -237,12 +241,12 @@ fn compile_program(input: &str, sysroot: PathBuf)
         let krate = driver::phase_2_configure_and_expand(&sess, &cstore, krate, &id, None)
             .expect("phase_2 returned `None`");
 
-        let dep_graph = DepGraph::new(sess.opts.build_dep_graph());
         let krate = driver::assign_node_ids(&sess, krate);
         let mut defs = ast_map::collect_definitions(&krate);
         read_local_crates(&sess, &cstore, &defs, &krate, &id, &dep_graph);
         let (analysis, resolutions, mut hir_forest) = {
-            driver::lower_and_resolve(&sess, &id, &mut defs, &krate, dep_graph, MakeGlobMap::No)
+            driver::lower_and_resolve(&sess, &id, &mut defs, &krate,
+                                      &sess.dep_graph, MakeGlobMap::No)
         };
 
         let arenas = ty::CtxtArenas::new();
diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs
index 80c06ca3274..41d250eadec 100644
--- a/src/test/run-make/issue-19371/foo.rs
+++ b/src/test/run-make/issue-19371/foo.rs
@@ -16,6 +16,7 @@ extern crate rustc_lint;
 extern crate rustc_metadata;
 extern crate syntax;
 
+use rustc::dep_graph::DepGraph;
 use rustc::session::{build_session, Session};
 use rustc::session::config::{basic_options, build_configuration, Input, OutputType};
 use rustc_driver::driver::{compile_input, CompileController, anon_src};
@@ -54,8 +55,9 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc<CStore>) {
     opts.maybe_sysroot = Some(sysroot);
 
     let descriptions = Registry::new(&rustc::DIAGNOSTICS);
-    let cstore = Rc::new(CStore::new(token::get_ident_interner()));
-    let sess = build_session(opts, None, descriptions, cstore.clone());
+    let dep_graph = DepGraph::new(opts.build_dep_graph());
+    let cstore = Rc::new(CStore::new(&dep_graph, token::get_ident_interner()));
+    let sess = build_session(opts, &dep_graph, None, descriptions, cstore.clone());
     rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
     (sess, cstore)
 }
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index b5cebe2e3ea..7593033ffe3 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -162,6 +162,11 @@ pub struct TestProps {
     pub forbid_output: Vec<String>,
     // Revisions to test for incremental compilation.
     pub revisions: Vec<String>,
+    // Directory (if any) to use for incremental compilation.  This is
+    // not set by end-users; rather it is set by the incremental
+    // testing harness and used when generating compilation
+    // arguments. (In particular, it propagates to the aux-builds.)
+    pub incremental_dir: Option<PathBuf>,
 }
 
 impl TestProps {
@@ -197,9 +202,20 @@ impl TestProps {
             pretty_mode: format!("normal"),
             pretty_compare_only: pretty_compare_only,
             forbid_output: forbid_output,
+            incremental_dir: None,
         }
     }
 
+    pub fn from_aux_file(&self, testfile: &Path, cfg: Option<&str>) -> Self {
+        let mut props = TestProps::new();
+
+        // copy over select properties to the aux build:
+        props.incremental_dir = self.incremental_dir.clone();
+        props.load_from(testfile, cfg);
+
+        props
+    }
+
     pub fn from_file(testfile: &Path) -> Self {
         let mut props = TestProps::new();
         props.load_from(testfile, None);
diff --git a/src/tools/compiletest/src/json.rs b/src/tools/compiletest/src/json.rs
index 3501b335205..84b78547ab9 100644
--- a/src/tools/compiletest/src/json.rs
+++ b/src/tools/compiletest/src/json.rs
@@ -12,6 +12,7 @@ use errors::{Error, ErrorKind};
 use rustc_serialize::json;
 use std::str::FromStr;
 use std::path::Path;
+use runtest::{ProcRes};
 
 // These structs are a subset of the ones found in
 // `syntax::errors::json`.
@@ -55,13 +56,13 @@ struct DiagnosticCode {
     explanation: Option<String>,
 }
 
-pub fn parse_output(file_name: &str, output: &str) -> Vec<Error> {
+pub fn parse_output(file_name: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
     output.lines()
-          .flat_map(|line| parse_line(file_name, line))
+          .flat_map(|line| parse_line(file_name, line, output, proc_res))
           .collect()
 }
 
-fn parse_line(file_name: &str, line: &str) -> Vec<Error> {
+fn parse_line(file_name: &str, line: &str, output: &str, proc_res: &ProcRes) -> Vec<Error> {
     // The compiler sometimes intermingles non-JSON stuff into the
     // output.  This hack just skips over such lines. Yuck.
     if line.chars().next() == Some('{') {
@@ -72,7 +73,9 @@ fn parse_line(file_name: &str, line: &str) -> Vec<Error> {
                 expected_errors
             }
             Err(error) => {
-                panic!("failed to decode compiler output as json: `{}`", error);
+                proc_res.fatal(Some(&format!(
+                    "failed to decode compiler output as json: `{}`\noutput: {}\nline: {}",
+                    error, line, output)));
             }
         }
     } else {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index a213c6d2d54..e6dc3a9d360 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -63,10 +63,6 @@ pub fn run(config: Config, testpaths: &TestPaths) {
         for revision in &base_props.revisions {
             let mut revision_props = base_props.clone();
             revision_props.load_from(&testpaths.file, Some(&revision));
-            revision_props.compile_flags.extend(vec![
-                format!("--cfg"),
-                format!("{}", revision),
-            ]);
             let rev_cx = TestCx {
                 config: &config,
                 props: &revision_props,
@@ -383,6 +379,12 @@ actual:\n\
                             self.config.build_base.to_str().unwrap().to_owned(),
                             "-L".to_owned(),
                             aux_dir.to_str().unwrap().to_owned());
+        if let Some(revision) = self.revision {
+            args.extend(vec![
+                format!("--cfg"),
+                format!("{}", revision),
+            ]);
+        }
         args.extend(self.split_maybe_args(&self.config.target_rustcflags));
         args.extend(self.props.compile_flags.iter().cloned());
         // FIXME (#9639): This needs to handle non-utf8 paths
@@ -1001,7 +1003,7 @@ actual:\n\
         let expect_note = expected_errors.iter().any(|ee| ee.kind == Some(ErrorKind::Note));
 
         // Parse the JSON output from the compiler and extract out the messages.
-        let actual_errors = json::parse_output(&file_name, &proc_res.stderr);
+        let actual_errors = json::parse_output(&file_name, &proc_res.stderr, &proc_res);
         let mut unexpected = 0;
         let mut not_found = 0;
         let mut found = vec![false; expected_errors.len()];
@@ -1102,7 +1104,7 @@ actual:\n\
         if self.props.build_aux_docs {
             for rel_ab in &self.props.aux_builds {
                 let aux_testpaths = self.compute_aux_test_paths(rel_ab);
-                let aux_props = TestProps::from_file(&aux_testpaths.file);
+                let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision);
                 let aux_cx = TestCx {
                     config: self.config,
                     props: &aux_props,
@@ -1186,7 +1188,7 @@ actual:\n\
 
         for rel_ab in &self.props.aux_builds {
             let aux_testpaths = self.compute_aux_test_paths(rel_ab);
-            let aux_props = TestProps::from_file(&aux_testpaths.file);
+            let aux_props = self.props.from_aux_file(&aux_testpaths.file, self.revision);
             let mut crate_type = if aux_props.no_prefer_dynamic {
                 Vec::new()
             } else {
@@ -1291,6 +1293,21 @@ actual:\n\
                             self.config.build_base.to_str().unwrap().to_owned(),
                             format!("--target={}", target));
 
+        if let Some(revision) = self.revision {
+            args.extend(vec![
+                format!("--cfg"),
+                format!("{}", revision),
+            ]);
+        }
+
+        if let Some(ref incremental_dir) = self.props.incremental_dir {
+            args.extend(vec![
+                format!("-Z"),
+                format!("incremental={}", incremental_dir.display()),
+            ]);
+        }
+
+
         match self.config.mode {
             CompileFail |
             ParseFail |
@@ -1530,21 +1547,7 @@ actual:\n\
 
     fn fatal_proc_rec(&self, err: &str, proc_res: &ProcRes) -> ! {
         self.error(err);
-        print!("\
-            status: {}\n\
-            command: {}\n\
-            stdout:\n\
-            ------------------------------------------\n\
-            {}\n\
-            ------------------------------------------\n\
-            stderr:\n\
-            ------------------------------------------\n\
-            {}\n\
-            ------------------------------------------\n\
-            \n",
-               proc_res.status, proc_res.cmdline, proc_res.stdout,
-               proc_res.stderr);
-        panic!();
+        proc_res.fatal(None);
     }
 
     fn _arm_exec_compiled_test(&self, env: Vec<(String, String)>) -> ProcRes {
@@ -1980,10 +1983,7 @@ actual:\n\
 
         // Add an extra flag pointing at the incremental directory.
         let mut revision_props = self.props.clone();
-        revision_props.compile_flags.extend(vec![
-            format!("-Z"),
-            format!("incremental={}", incremental_dir.display()),
-        ]);
+        revision_props.incremental_dir = Some(incremental_dir);
 
         let revision_cx = TestCx {
             config: self.config,
@@ -2197,7 +2197,7 @@ struct ProcArgs {
     args: Vec<String>,
 }
 
-struct ProcRes {
+pub struct ProcRes {
     status: Status,
     stdout: String,
     stderr: String,
@@ -2209,6 +2209,29 @@ enum Status {
     Normal(ExitStatus),
 }
 
+impl ProcRes {
+    pub fn fatal(&self, err: Option<&str>) -> ! {
+        if let Some(e) = err {
+            println!("\nerror: {}", e);
+        }
+        print!("\
+            status: {}\n\
+            command: {}\n\
+            stdout:\n\
+            ------------------------------------------\n\
+            {}\n\
+            ------------------------------------------\n\
+            stderr:\n\
+            ------------------------------------------\n\
+            {}\n\
+            ------------------------------------------\n\
+            \n",
+               self.status, self.cmdline, self.stdout,
+               self.stderr);
+        panic!();
+    }
+}
+
 impl Status {
     fn code(&self) -> Option<i32> {
         match *self {