about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/lib.rs3
-rw-r--r--src/doc/book/const-and-static.md2
-rw-r--r--src/doc/book/lifetimes.md90
-rw-r--r--src/doc/book/type-aliases.md2
-rw-r--r--src/doc/footer.inc1
-rw-r--r--src/doc/reference.md3
-rw-r--r--src/doc/rust.css8
-rw-r--r--src/liballoc/rc.rs28
-rw-r--r--src/libcollections/vec.rs228
-rw-r--r--src/libcollectionstest/lib.rs1
-rw-r--r--src/libcollectionstest/slice.rs41
-rw-r--r--src/libcollectionstest/vec.rs65
-rw-r--r--src/libcollectionstest/vec_deque.rs22
-rw-r--r--src/libcore/any.rs7
-rw-r--r--src/libcore/hash/mod.rs37
-rw-r--r--src/libcore/lib.rs2
-rw-r--r--src/libcore/macros.rs3
-rw-r--r--src/libcore/marker.rs3
-rw-r--r--src/libcore/num/bignum.rs17
-rw-r--r--src/libcore/num/diy_float.rs35
-rw-r--r--src/libcore/num/f32.rs48
-rw-r--r--src/libcore/num/f64.rs48
-rw-r--r--src/libcore/num/mod.rs14
-rw-r--r--src/libcore/num/wrapping.rs4
-rw-r--r--src/libgraphviz/lib.rs2
m---------src/liblibc0
-rw-r--r--src/liblog/directive.rs57
-rw-r--r--src/librustc/diagnostics.rs41
-rw-r--r--src/librustc/hir/lowering.rs8
-rw-r--r--src/librustc/infer/error_reporting.rs15
-rw-r--r--src/librustc/infer/mod.rs19
-rw-r--r--src/librustc/lib.rs2
-rw-r--r--src/librustc/session/filesearch.rs82
-rw-r--r--src/librustc/session/mod.rs8
-rw-r--r--src/librustc/traits/select.rs2
-rw-r--r--src/librustc/ty/context.rs21
-rw-r--r--src/librustc/ty/mod.rs18
-rw-r--r--src/librustc/ty/structural_impls.rs17
-rw-r--r--src/librustc/ty/subst.rs106
-rw-r--r--src/librustc/ty/util.rs31
-rw-r--r--src/librustc_back/lib.rs2
-rw-r--r--src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs4
-rw-r--r--src/librustc_borrowck/borrowck/mir/dataflow/impls.rs7
-rw-r--r--src/librustc_borrowck/borrowck/mir/dataflow/mod.rs5
-rw-r--r--src/librustc_borrowck/borrowck/mir/elaborate_drops.rs2
-rw-r--r--src/librustc_borrowck/lib.rs4
-rw-r--r--src/librustc_const_eval/eval.rs4
-rw-r--r--src/librustc_const_eval/lib.rs2
-rw-r--r--src/librustc_const_math/lib.rs2
-rw-r--r--src/librustc_data_structures/bitslice.rs (renamed from src/librustc_borrowck/bitslice.rs)3
-rw-r--r--src/librustc_data_structures/indexed_set.rs (renamed from src/librustc_borrowck/indexed_set.rs)5
-rw-r--r--src/librustc_data_structures/lib.rs2
-rw-r--r--src/librustc_driver/driver.rs12
-rw-r--r--src/librustc_driver/lib.rs8
-rw-r--r--src/librustc_errors/lib.rs2
-rw-r--r--src/librustc_incremental/calculate_svh/hasher.rs46
-rw-r--r--src/librustc_incremental/calculate_svh/mod.rs20
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs6
-rw-r--r--src/librustc_incremental/lib.rs2
-rw-r--r--src/librustc_lint/bad_style.rs167
-rw-r--r--src/librustc_lint/builtin.rs302
-rw-r--r--src/librustc_lint/lib.rs42
-rw-r--r--src/librustc_lint/types.rs474
-rw-r--r--src/librustc_lint/unused.rs100
-rw-r--r--src/librustc_llvm/ffi.rs11
-rw-r--r--src/librustc_metadata/creader.rs2
-rw-r--r--src/librustc_metadata/decoder.rs3
-rw-r--r--src/librustc_metadata/lib.rs2
-rw-r--r--src/librustc_mir/lib.rs2
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs70
-rw-r--r--src/librustc_resolve/lib.rs56
-rw-r--r--src/librustc_resolve/macros.rs211
-rw-r--r--src/librustc_resolve/resolve_imports.rs11
-rw-r--r--src/librustc_save_analysis/span_utils.rs10
-rw-r--r--src/librustc_trans/base.rs6
-rw-r--r--src/librustc_trans/builder.rs73
-rw-r--r--src/librustc_trans/callee.rs6
-rw-r--r--src/librustc_trans/closure.rs9
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs12
-rw-r--r--src/librustc_trans/debuginfo/mod.rs2
-rw-r--r--src/librustc_trans/debuginfo/type_names.rs6
-rw-r--r--src/librustc_trans/declare.rs3
-rw-r--r--src/librustc_trans/intrinsic.rs12
-rw-r--r--src/librustc_trans/lib.rs2
-rw-r--r--src/librustc_trans/meth.rs3
-rw-r--r--src/librustc_trans/mir/block.rs2
-rw-r--r--src/librustc_trans/mir/mod.rs34
-rw-r--r--src/librustc_trans/trans_item.rs27
-rw-r--r--src/librustc_trans/type_of.rs3
-rw-r--r--src/librustc_typeck/astconv.rs8
-rw-r--r--src/librustc_typeck/check/mod.rs6
-rw-r--r--src/librustc_typeck/lib.rs2
-rw-r--r--src/librustdoc/externalfiles.rs85
-rw-r--r--src/librustdoc/html/highlight.rs8
-rw-r--r--src/librustdoc/html/layout.rs9
-rw-r--r--src/librustdoc/html/markdown.rs43
-rw-r--r--src/librustdoc/html/render.rs8
-rw-r--r--src/librustdoc/html/static/extra.js25
-rw-r--r--src/librustdoc/html/static/playpen.js48
-rw-r--r--src/librustdoc/html/static/rustdoc.css5
-rw-r--r--src/librustdoc/lib.rs2
-rw-r--r--src/librustdoc/markdown.rs24
-rw-r--r--src/librustdoc/test.rs2
-rw-r--r--src/libserialize/json.rs7
-rw-r--r--src/libserialize/leb128.rs2
-rw-r--r--src/libserialize/lib.rs2
-rw-r--r--src/libserialize/opaque.rs21
-rw-r--r--src/libserialize/serialize.rs5
-rw-r--r--src/libstd/collections/hash/table.rs156
-rw-r--r--src/libstd/error.rs11
-rw-r--r--src/libstd/fs.rs126
-rw-r--r--src/libstd/io/buffered.rs21
-rw-r--r--src/libstd/io/mod.rs69
-rw-r--r--src/libstd/lib.rs3
-rw-r--r--src/libstd/net/addr.rs35
-rw-r--r--src/libstd/sync/mpsc/mod.rs5
-rw-r--r--src/libstd/sync/once.rs14
-rw-r--r--src/libstd/sync/rwlock.rs8
-rw-r--r--src/libstd/sys/common/poison.rs5
-rw-r--r--src/libstd/sys/unix/android.rs63
-rw-r--r--src/libstd/sys/unix/ext/fs.rs45
-rw-r--r--src/libstd/sys/unix/ext/mod.rs2
-rw-r--r--src/libstd/sys/unix/fd.rs48
-rw-r--r--src/libstd/sys/unix/fs.rs8
-rw-r--r--src/libstd/sys/windows/ext/fs.rs51
-rw-r--r--src/libstd/sys/windows/ext/mod.rs2
-rw-r--r--src/libstd/sys/windows/fs.rs8
-rw-r--r--src/libstd/sys/windows/handle.rs30
-rw-r--r--src/libsyntax/ast.rs2
-rw-r--r--src/libsyntax/codemap.rs6
-rw-r--r--src/libsyntax/config.rs5
-rw-r--r--src/libsyntax/ext/base.rs37
-rw-r--r--src/libsyntax/ext/expand.rs78
-rw-r--r--src/libsyntax/ext/placeholders.rs3
-rw-r--r--src/libsyntax/feature_gate.rs8
-rw-r--r--src/libsyntax/lib.rs2
-rw-r--r--src/libsyntax/parse/attr.rs12
-rw-r--r--src/libsyntax/parse/lexer/comments.rs40
-rw-r--r--src/libsyntax/parse/lexer/mod.rs399
-rw-r--r--src/libsyntax/parse/lexer/unicode_chars.rs2
-rw-r--r--src/libsyntax/parse/parser.rs346
-rw-r--r--src/libsyntax/parse/token.rs15
-rw-r--r--src/libsyntax/print/pprust.rs2
-rw-r--r--src/libsyntax/std_inject.rs22
-rw-r--r--src/libsyntax/util/interner.rs40
-rw-r--r--src/libsyntax_ext/asm.rs12
-rw-r--r--src/libsyntax_ext/deriving/mod.rs35
-rw-r--r--src/libsyntax_ext/lib.rs21
-rw-r--r--src/libsyntax_pos/lib.rs2
-rw-r--r--src/libterm/lib.rs2
-rw-r--r--src/libtest/lib.rs2
-rw-r--r--src/rtstartup/rsbegin.rs6
-rw-r--r--src/rustllvm/RustWrapper.cpp21
-rw-r--r--src/test/compile-fail/E0408.rs4
-rw-r--r--src/test/compile-fail/if-without-else-result.rs2
-rw-r--r--src/test/compile-fail/issue-2848.rs4
-rw-r--r--src/test/compile-fail/issue-32709.rs4
-rw-r--r--src/test/compile-fail/issue-33876.rs3
-rw-r--r--src/test/compile-fail/lint-group-style.rs2
-rw-r--r--src/test/compile-fail/lint-non-uppercase-statics.rs5
-rw-r--r--src/test/compile-fail/macro-shadowing.rs15
-rw-r--r--src/test/compile-fail/macro-use-scope.rs6
-rw-r--r--src/test/compile-fail/mir-dataflow/def-inits-1.rs1
-rw-r--r--src/test/compile-fail/mir-dataflow/inits-1.rs1
-rw-r--r--src/test/compile-fail/mir-dataflow/uninits-1.rs1
-rw-r--r--src/test/compile-fail/mir-dataflow/uninits-2.rs1
-rw-r--r--src/test/compile-fail/resolve-inconsistent-names.rs6
-rw-r--r--src/test/compile-fail/stmt_expr_attrs_no_feature.rs16
-rw-r--r--src/test/incremental/hashes/struct_defs.rs71
-rw-r--r--src/test/run-pass-fulldeps/macro-crate.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs2
-rw-r--r--src/test/run-pass-fulldeps/proc-macro/load-two.rs1
-rw-r--r--src/test/run-pass/const-err.rs4
-rw-r--r--src/test/run-pass/const-negation.rs2
-rw-r--r--src/test/run-pass/enum-discrim-autosizing.rs2
-rw-r--r--src/test/run-pass/ifmt.rs1
-rw-r--r--src/test/run-pass/impl-trait/example-st.rs2
-rw-r--r--src/test/run-pass/issue-17121.rs2
-rw-r--r--src/test/run-pass/issue-19404.rs5
-rw-r--r--src/test/run-pass/issue-20797.rs2
-rw-r--r--src/test/run-pass/issue-21400.rs2
-rw-r--r--src/test/run-pass/issue-36744-bitcast-args-if-needed.rs32
-rw-r--r--src/test/run-pass/issue-36744-without-calls.rs22
-rw-r--r--src/test/run-pass/issue-37020.rs (renamed from src/test/compile-fail/feature-gate-try-operator.rs)15
-rw-r--r--src/test/run-pass/issue-37109.rs25
-rw-r--r--src/test/run-pass/issue-8460.rs2
-rw-r--r--src/test/run-pass/try-operator-hygiene.rs2
-rw-r--r--src/test/run-pass/try-operator.rs2
-rw-r--r--src/test/rustdoc/playground-empty.rs21
-rw-r--r--src/test/rustdoc/playground-none.rs (renamed from src/test/run-pass/lint-non-uppercase-statics-lowercase-mut-statics.rs)16
-rw-r--r--src/test/rustdoc/playground.rs39
-rw-r--r--src/tools/compiletest/src/main.rs3
-rw-r--r--src/tools/error_index_generator/main.rs6
-rw-r--r--src/tools/linkchecker/main.rs2
-rw-r--r--src/tools/rustbook/build.rs7
-rw-r--r--src/tools/rustbook/main.rs1
196 files changed, 3260 insertions, 2188 deletions
diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs
index 12938b8326e..30983869c2e 100644
--- a/src/bootstrap/lib.rs
+++ b/src/bootstrap/lib.rs
@@ -991,7 +991,8 @@ impl Build {
 
     /// Returns the "musl root" for this `target`, if defined
     fn musl_root(&self, target: &str) -> Option<&Path> {
-        self.config.target_config[target].musl_root.as_ref()
+        self.config.target_config.get(target)
+            .and_then(|t| t.musl_root.as_ref())
             .or(self.config.musl_root.as_ref())
             .map(|p| &**p)
     }
diff --git a/src/doc/book/const-and-static.md b/src/doc/book/const-and-static.md
index 11aa25ac811..e8f17a41cbe 100644
--- a/src/doc/book/const-and-static.md
+++ b/src/doc/book/const-and-static.md
@@ -1,4 +1,4 @@
-% `const` and `static`
+% const and static
 
 Rust has a way of defining constants with the `const` keyword:
 
diff --git a/src/doc/book/lifetimes.md b/src/doc/book/lifetimes.md
index e865609f217..df1ee5a293c 100644
--- a/src/doc/book/lifetimes.md
+++ b/src/doc/book/lifetimes.md
@@ -50,11 +50,78 @@ complicated. For example, imagine this set of operations:
 4. You decide to use the resource.
 
 Uh oh! Your reference is pointing to an invalid resource. This is called a
-dangling pointer or ‘use after free’, when the resource is memory.
+dangling pointer or ‘use after free’, when the resource is memory. A small
+example of such a situation would be:
+
+```rust,compile_fail
+let r;              // Introduce reference: r
+{
+    let i = 1;      // Introduce scoped value: i
+    r = &i;         // Store reference of i in r
+}                   // i goes out of scope and is dropped.
+
+println!("{}", r);  // r still refers to i
+```
 
 To fix this, we have to make sure that step four never happens after step
-three. The ownership system in Rust does this through a concept called
-lifetimes, which describe the scope that a reference is valid for.
+three. In the small example above the Rust compiler is able to report the issue
+as it can see the lifetimes of the various values in the function.
+
+When we have a function that takes arguments by reference the situation becomes
+more complex. Consider the following example:
+
+```rust,compile_fail,E0106
+fn skip_prefix(line: &str, prefix: &str) -> &str {
+    // ...
+#   line
+}
+
+let line = "lang:en=Hello World!";
+let lang = "en";
+
+let v;
+{
+    let p = format!("lang:{}=", lang);  // -+ p goes into scope
+    v = skip_prefix(line, p.as_str());  //  |
+}                                       // -+ p goes out of scope
+println!("{}", v);
+```
+
+Here we have a function `skip_prefix` which takes two `&str` references
+as parameters and returns a single `&str` reference. We call it
+by passing in references to `line` and `p`: Two variables with different
+lifetimes. Now the safety of the `println!`-line depends on whether the
+reference returned by `skip_prefix` function references the still living
+`line` or the already dropped `p` string.
+
+Because of the above ambiguity, Rust will refuse to compile the example
+code. To get it to compile we need to tell the compiler more about the
+lifetimes of the references. This can be done by making the lifetimes
+explicit in the function declaration:
+
+```rust
+fn skip_prefix<'a, 'b>(line: &'a str, prefix: &'b str) -> &'a str {
+    // ...
+#   line
+}
+```
+
+Let's examine the changes without going too deep into the syntax for now -
+we'll get to that later. The first change was adding the `<'a, 'b>` after the
+method name. This introduces two lifetime parameters: `'a` and `'b`. Next each
+reference in the function signature was associated with one of the lifetime
+parameters by adding the lifetime name after the `&`. This tells the compiler
+how the lifetimes between different references are related.
+
+As a result the compiler is now able to deduce that the return value of
+`skip_prefix` has the same lifetime as the `line` parameter, which makes the `v`
+reference safe to use even after the `p` goes out of scope in the original
+example.
+
+In addition to the compiler being able to validate the usage of `skip_prefix`
+return value, it can also ensure that the implementation follows the contract
+established by the function declaration. This is useful especially when you are
+implementing traits that are introduced [later in the book][traits].
 
 **Note** It's important to understand that lifetime annotations are
 _descriptive_, not _prescriptive_. This means that how long a reference is valid
@@ -63,20 +130,14 @@ give information about lifetimes to the compiler that uses them to check the
 validity of references. The compiler can do so without annotations in simple
 cases, but needs the programmers support in complex scenarios.
 
-```rust
-// implicit
-fn foo(x: &i32) {
-}
+[traits]: traits.html
 
-// explicit
-fn bar<'a>(x: &'a i32) {
-}
-```
+# Syntax
 
 The `'a` reads ‘the lifetime a’. Technically, every reference has some lifetime
 associated with it, but the compiler lets you elide (i.e. omit, see
-["Lifetime Elision"][lifetime-elision] below) them in common cases.
-Before we get to that, though, let’s break the explicit example down:
+["Lifetime Elision"][lifetime-elision] below) them in common cases. Before we
+get to that, though, let’s look at a short example with explicit lifetimes:
 
 [lifetime-elision]: #lifetime-elision
 
@@ -94,7 +155,8 @@ focus on the lifetimes aspect.
 [generics]: generics.html
 
 We use `<>` to declare our lifetimes. This says that `bar` has one lifetime,
-`'a`. If we had two reference parameters, it would look like this:
+`'a`. If we had two reference parameters with different lifetimes, it would
+look like this:
 
 
 ```rust,ignore
diff --git a/src/doc/book/type-aliases.md b/src/doc/book/type-aliases.md
index def2e31f351..3798336f0a5 100644
--- a/src/doc/book/type-aliases.md
+++ b/src/doc/book/type-aliases.md
@@ -1,4 +1,4 @@
-% `type` Aliases
+% Type Aliases
 
 The `type` keyword lets you declare an alias of another type:
 
diff --git a/src/doc/footer.inc b/src/doc/footer.inc
index 7513e524e73..77e151235e8 100644
--- a/src/doc/footer.inc
+++ b/src/doc/footer.inc
@@ -5,4 +5,3 @@ or the <a href="https://opensource.org/licenses/MIT">MIT license</a>, at your op
 </p><p>
 This file may not be copied, modified, or distributed except according to those terms.
 </p></footer>
-<script type="text/javascript" src="playpen.js"></script>
diff --git a/src/doc/reference.md b/src/doc/reference.md
index 08ff982d4d7..84f459bf872 100644
--- a/src/doc/reference.md
+++ b/src/doc/reference.md
@@ -2472,8 +2472,7 @@ The currently implemented features of the reference compiler are:
 * - `default_type_parameter_fallback` - Allows type parameter defaults to
                                         influence type inference.
 
-* - `stmt_expr_attributes` - Allows attributes on expressions and
-                             non-item statements.
+* - `stmt_expr_attributes` - Allows attributes on expressions.
 
 * - `type_ascription` - Allows type ascription expressions `expr: Type`.
 
diff --git a/src/doc/rust.css b/src/doc/rust.css
index 262db5673e8..932594b9912 100644
--- a/src/doc/rust.css
+++ b/src/doc/rust.css
@@ -336,13 +336,11 @@ table th {
 
 /* Code snippets */
 
-.rusttest { display: none; }
 pre.rust { position: relative; }
 a.test-arrow {
+    background-color: rgba(78, 139, 202, 0.2);
     display: inline-block;
     position: absolute;
-
-    background-color: #4e8bca;
     color: #f5f5f5;
     padding: 5px 10px 5px 10px;
     border-radius: 5px;
@@ -350,6 +348,10 @@ a.test-arrow {
     top: 5px;
     right: 5px;
 }
+a.test-arrow:hover{
+    background-color: #4e8bca;
+    text-decoration: none;
+}
 
 .unstable-feature {
     border: 2px solid red;
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index 699f777138d..740d13c4762 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -230,13 +230,14 @@ use core::hash::{Hash, Hasher};
 use core::intrinsics::{abort, assume};
 use core::marker;
 use core::marker::Unsize;
-use core::mem::{self, align_of_val, forget, size_of_val, uninitialized};
+use core::mem::{self, align_of_val, forget, size_of, size_of_val, uninitialized};
 use core::ops::Deref;
 use core::ops::CoerceUnsized;
 use core::ptr::{self, Shared};
 use core::convert::From;
 
 use heap::deallocate;
+use raw_vec::RawVec;
 
 struct RcBox<T: ?Sized> {
     strong: Cell<usize>,
@@ -365,6 +366,31 @@ impl<T> Rc<T> {
     }
 }
 
+impl Rc<str> {
+    /// Constructs a new `Rc<str>` from a string slice.
+    #[doc(hidden)]
+    #[unstable(feature = "rustc_private",
+               reason = "for internal use in rustc",
+               issue = "0")]
+    pub fn __from_str(value: &str) -> Rc<str> {
+        unsafe {
+            // Allocate enough space for `RcBox<str>`.
+            let aligned_len = 2 + (value.len() + size_of::<usize>() - 1) / size_of::<usize>();
+            let vec = RawVec::<usize>::with_capacity(aligned_len);
+            let ptr = vec.ptr();
+            forget(vec);
+            // Initialize fields of `RcBox<str>`.
+            *ptr.offset(0) = 1; // strong: Cell::new(1)
+            *ptr.offset(1) = 1; // weak: Cell::new(1)
+            ptr::copy_nonoverlapping(value.as_ptr(), ptr.offset(2) as *mut u8, value.len());
+            // Combine the allocation address and the string length into a fat pointer to `RcBox`.
+            let rcbox_ptr: *mut RcBox<str> = mem::transmute([ptr as usize, value.len()]);
+            assert!(aligned_len * size_of::<usize>() == size_of_val(&*rcbox_ptr));
+            Rc { ptr: Shared::new(rcbox_ptr) }
+        }
+    }
+}
+
 impl<T: ?Sized> Rc<T> {
     /// Creates a new [`Weak`][weak] pointer to this value.
     ///
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index 54fd19dbe30..f3d78c20a4d 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -781,6 +781,130 @@ impl<T> Vec<T> {
         }
     }
 
+    /// Removes consecutive elements in the vector that resolve to the same key.
+    ///
+    /// If the vector is sorted, this removes all duplicates.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(dedup_by)]
+    ///
+    /// let mut vec = vec![10, 20, 21, 30, 20];
+    ///
+    /// vec.dedup_by_key(|i| *i / 10);
+    ///
+    /// assert_eq!(vec, [10, 20, 30, 20]);
+    /// ```
+    #[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")]
+    #[inline]
+    pub fn dedup_by_key<F, K>(&mut self, mut key: F) where F: FnMut(&mut T) -> K, K: PartialEq {
+        self.dedup_by(|a, b| key(a) == key(b))
+    }
+
+    /// Removes consecutive elements in the vector that resolve to the same key.
+    ///
+    /// If the vector is sorted, this removes all duplicates.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(dedup_by)]
+    /// use std::ascii::AsciiExt;
+    ///
+    /// let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
+    ///
+    /// vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
+    ///
+    /// assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
+    /// ```
+    #[unstable(feature = "dedup_by", reason = "recently added", issue = "37087")]
+    pub fn dedup_by<F>(&mut self, mut same_bucket: F) where F: FnMut(&mut T, &mut T) -> bool {
+        unsafe {
+            // Although we have a mutable reference to `self`, we cannot make
+            // *arbitrary* changes. The `same_bucket` calls could panic, so we
+            // must ensure that the vector is in a valid state at all time.
+            //
+            // The way that we handle this is by using swaps; we iterate
+            // over all the elements, swapping as we go so that at the end
+            // the elements we wish to keep are in the front, and those we
+            // wish to reject are at the back. We can then truncate the
+            // vector. This operation is still O(n).
+            //
+            // Example: We start in this state, where `r` represents "next
+            // read" and `w` represents "next_write`.
+            //
+            //           r
+            //     +---+---+---+---+---+---+
+            //     | 0 | 1 | 1 | 2 | 3 | 3 |
+            //     +---+---+---+---+---+---+
+            //           w
+            //
+            // Comparing self[r] against self[w-1], this is not a duplicate, so
+            // we swap self[r] and self[w] (no effect as r==w) and then increment both
+            // r and w, leaving us with:
+            //
+            //               r
+            //     +---+---+---+---+---+---+
+            //     | 0 | 1 | 1 | 2 | 3 | 3 |
+            //     +---+---+---+---+---+---+
+            //               w
+            //
+            // Comparing self[r] against self[w-1], this value is a duplicate,
+            // so we increment `r` but leave everything else unchanged:
+            //
+            //                   r
+            //     +---+---+---+---+---+---+
+            //     | 0 | 1 | 1 | 2 | 3 | 3 |
+            //     +---+---+---+---+---+---+
+            //               w
+            //
+            // Comparing self[r] against self[w-1], this is not a duplicate,
+            // so swap self[r] and self[w] and advance r and w:
+            //
+            //                       r
+            //     +---+---+---+---+---+---+
+            //     | 0 | 1 | 2 | 1 | 3 | 3 |
+            //     +---+---+---+---+---+---+
+            //                   w
+            //
+            // Not a duplicate, repeat:
+            //
+            //                           r
+            //     +---+---+---+---+---+---+
+            //     | 0 | 1 | 2 | 3 | 1 | 3 |
+            //     +---+---+---+---+---+---+
+            //                       w
+            //
+            // Duplicate, advance r. End of vec. Truncate to w.
+
+            let ln = self.len();
+            if ln <= 1 {
+                return;
+            }
+
+            // Avoid bounds checks by using raw pointers.
+            let p = self.as_mut_ptr();
+            let mut r: usize = 1;
+            let mut w: usize = 1;
+
+            while r < ln {
+                let p_r = p.offset(r as isize);
+                let p_wm1 = p.offset((w - 1) as isize);
+                if !same_bucket(&mut *p_r, &mut *p_wm1) {
+                    if r != w {
+                        let p_w = p_wm1.offset(1);
+                        mem::swap(&mut *p_r, &mut *p_w);
+                    }
+                    w += 1;
+                }
+                r += 1;
+            }
+
+            self.truncate(w);
+        }
+    }
+
     /// Appends an element to the back of a collection.
     ///
     /// # Panics
@@ -1155,90 +1279,9 @@ impl<T: PartialEq> Vec<T> {
     /// assert_eq!(vec, [1, 2, 3, 2]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[inline]
     pub fn dedup(&mut self) {
-        unsafe {
-            // Although we have a mutable reference to `self`, we cannot make
-            // *arbitrary* changes. The `PartialEq` comparisons could panic, so we
-            // must ensure that the vector is in a valid state at all time.
-            //
-            // The way that we handle this is by using swaps; we iterate
-            // over all the elements, swapping as we go so that at the end
-            // the elements we wish to keep are in the front, and those we
-            // wish to reject are at the back. We can then truncate the
-            // vector. This operation is still O(n).
-            //
-            // Example: We start in this state, where `r` represents "next
-            // read" and `w` represents "next_write`.
-            //
-            //           r
-            //     +---+---+---+---+---+---+
-            //     | 0 | 1 | 1 | 2 | 3 | 3 |
-            //     +---+---+---+---+---+---+
-            //           w
-            //
-            // Comparing self[r] against self[w-1], this is not a duplicate, so
-            // we swap self[r] and self[w] (no effect as r==w) and then increment both
-            // r and w, leaving us with:
-            //
-            //               r
-            //     +---+---+---+---+---+---+
-            //     | 0 | 1 | 1 | 2 | 3 | 3 |
-            //     +---+---+---+---+---+---+
-            //               w
-            //
-            // Comparing self[r] against self[w-1], this value is a duplicate,
-            // so we increment `r` but leave everything else unchanged:
-            //
-            //                   r
-            //     +---+---+---+---+---+---+
-            //     | 0 | 1 | 1 | 2 | 3 | 3 |
-            //     +---+---+---+---+---+---+
-            //               w
-            //
-            // Comparing self[r] against self[w-1], this is not a duplicate,
-            // so swap self[r] and self[w] and advance r and w:
-            //
-            //                       r
-            //     +---+---+---+---+---+---+
-            //     | 0 | 1 | 2 | 1 | 3 | 3 |
-            //     +---+---+---+---+---+---+
-            //                   w
-            //
-            // Not a duplicate, repeat:
-            //
-            //                           r
-            //     +---+---+---+---+---+---+
-            //     | 0 | 1 | 2 | 3 | 1 | 3 |
-            //     +---+---+---+---+---+---+
-            //                       w
-            //
-            // Duplicate, advance r. End of vec. Truncate to w.
-
-            let ln = self.len();
-            if ln <= 1 {
-                return;
-            }
-
-            // Avoid bounds checks by using raw pointers.
-            let p = self.as_mut_ptr();
-            let mut r: usize = 1;
-            let mut w: usize = 1;
-
-            while r < ln {
-                let p_r = p.offset(r as isize);
-                let p_wm1 = p.offset((w - 1) as isize);
-                if *p_r != *p_wm1 {
-                    if r != w {
-                        let p_w = p_wm1.offset(1);
-                        mem::swap(&mut *p_r, &mut *p_w);
-                    }
-                    w += 1;
-                }
-                r += 1;
-            }
-
-            self.truncate(w);
-        }
+        self.dedup_by(|a, b| a == b)
     }
 }
 
@@ -1571,7 +1614,24 @@ impl<T> Vec<T> {
 #[stable(feature = "extend_ref", since = "1.2.0")]
 impl<'a, T: 'a + Copy> Extend<&'a T> for Vec<T> {
     fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
-        self.extend(iter.into_iter().cloned());
+        <I as SpecExtendVec<T>>::extend_vec(iter, self);
+    }
+}
+
+// helper trait for specialization of Vec's Extend impl
+trait SpecExtendVec<T> {
+    fn extend_vec(self, vec: &mut Vec<T>);
+}
+
+impl <'a, T: 'a + Copy, I: IntoIterator<Item=&'a T>> SpecExtendVec<T> for I {
+    default fn extend_vec(self, vec: &mut Vec<T>) {
+        vec.extend(self.into_iter().cloned());
+    }
+}
+
+impl<'a, T: Copy> SpecExtendVec<T> for &'a [T] {
+    fn extend_vec(self, vec: &mut Vec<T>) {
+        vec.extend_from_slice(self);
     }
 }
 
diff --git a/src/libcollectionstest/lib.rs b/src/libcollectionstest/lib.rs
index c2b34647c32..88fb6540a9a 100644
--- a/src/libcollectionstest/lib.rs
+++ b/src/libcollectionstest/lib.rs
@@ -16,6 +16,7 @@
 #![feature(collections)]
 #![feature(collections_bound)]
 #![feature(const_fn)]
+#![feature(dedup_by)]
 #![feature(enumset)]
 #![feature(pattern)]
 #![feature(rand)]
diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs
index 9580714075a..130c16d7c15 100644
--- a/src/libcollectionstest/slice.rs
+++ b/src/libcollectionstest/slice.rs
@@ -316,47 +316,6 @@ fn test_clear() {
 }
 
 #[test]
-fn test_dedup() {
-    fn case(a: Vec<i32>, b: Vec<i32>) {
-        let mut v = a;
-        v.dedup();
-        assert_eq!(v, b);
-    }
-    case(vec![], vec![]);
-    case(vec![1], vec![1]);
-    case(vec![1, 1], vec![1]);
-    case(vec![1, 2, 3], vec![1, 2, 3]);
-    case(vec![1, 1, 2, 3], vec![1, 2, 3]);
-    case(vec![1, 2, 2, 3], vec![1, 2, 3]);
-    case(vec![1, 2, 3, 3], vec![1, 2, 3]);
-    case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]);
-}
-
-#[test]
-fn test_dedup_unique() {
-    let mut v0: Vec<Box<_>> = vec![box 1, box 1, box 2, box 3];
-    v0.dedup();
-    let mut v1: Vec<Box<_>> = vec![box 1, box 2, box 2, box 3];
-    v1.dedup();
-    let mut v2: Vec<Box<_>> = vec![box 1, box 2, box 3, box 3];
-    v2.dedup();
-    // If the boxed pointers were leaked or otherwise misused, valgrind
-    // and/or rt should raise errors.
-}
-
-#[test]
-fn test_dedup_shared() {
-    let mut v0: Vec<Box<_>> = vec![box 1, box 1, box 2, box 3];
-    v0.dedup();
-    let mut v1: Vec<Box<_>> = vec![box 1, box 2, box 2, box 3];
-    v1.dedup();
-    let mut v2: Vec<Box<_>> = vec![box 1, box 2, box 3, box 3];
-    v2.dedup();
-    // If the pointers were leaked or otherwise misused, valgrind and/or
-    // rt should raise errors.
-}
-
-#[test]
 fn test_retain() {
     let mut v = vec![1, 2, 3, 4, 5];
     v.retain(is_odd);
diff --git a/src/libcollectionstest/vec.rs b/src/libcollectionstest/vec.rs
index ee2b898d5c2..991c456fe74 100644
--- a/src/libcollectionstest/vec.rs
+++ b/src/libcollectionstest/vec.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::ascii::AsciiExt;
 use std::borrow::Cow;
 use std::iter::{FromIterator, repeat};
 use std::mem::size_of;
@@ -214,6 +215,60 @@ fn test_retain() {
 }
 
 #[test]
+fn test_dedup() {
+    fn case(a: Vec<i32>, b: Vec<i32>) {
+        let mut v = a;
+        v.dedup();
+        assert_eq!(v, b);
+    }
+    case(vec![], vec![]);
+    case(vec![1], vec![1]);
+    case(vec![1, 1], vec![1]);
+    case(vec![1, 2, 3], vec![1, 2, 3]);
+    case(vec![1, 1, 2, 3], vec![1, 2, 3]);
+    case(vec![1, 2, 2, 3], vec![1, 2, 3]);
+    case(vec![1, 2, 3, 3], vec![1, 2, 3]);
+    case(vec![1, 1, 2, 2, 2, 3, 3], vec![1, 2, 3]);
+}
+
+#[test]
+fn test_dedup_by_key() {
+    fn case(a: Vec<i32>, b: Vec<i32>) {
+        let mut v = a;
+        v.dedup_by_key(|i| *i / 10);
+        assert_eq!(v, b);
+    }
+    case(vec![], vec![]);
+    case(vec![10], vec![10]);
+    case(vec![10, 11], vec![10]);
+    case(vec![10, 20, 30], vec![10, 20, 30]);
+    case(vec![10, 11, 20, 30], vec![10, 20, 30]);
+    case(vec![10, 20, 21, 30], vec![10, 20, 30]);
+    case(vec![10, 20, 30, 31], vec![10, 20, 30]);
+    case(vec![10, 11, 20, 21, 22, 30, 31], vec![10, 20, 30]);
+}
+
+#[test]
+fn test_dedup_by() {
+    let mut vec = vec!["foo", "bar", "Bar", "baz", "bar"];
+    vec.dedup_by(|a, b| a.eq_ignore_ascii_case(b));
+
+    assert_eq!(vec, ["foo", "bar", "baz", "bar"]);
+}
+
+#[test]
+fn test_dedup_unique() {
+    let mut v0: Vec<Box<_>> = vec![box 1, box 1, box 2, box 3];
+    v0.dedup();
+    let mut v1: Vec<Box<_>> = vec![box 1, box 2, box 2, box 3];
+    v1.dedup();
+    let mut v2: Vec<Box<_>> = vec![box 1, box 2, box 3, box 3];
+    v2.dedup();
+    // If the boxed pointers were leaked or otherwise misused, valgrind
+    // and/or rt should raise errors.
+}
+
+#[test]
 fn zero_sized_values() {
     let mut v = Vec::new();
     assert_eq!(v.len(), 0);
@@ -271,22 +326,22 @@ fn test_zip_unzip() {
 
 #[test]
 fn test_vec_truncate_drop() {
-    static mut drops: u32 = 0;
+    static mut DROPS: u32 = 0;
     struct Elem(i32);
     impl Drop for Elem {
         fn drop(&mut self) {
             unsafe {
-                drops += 1;
+                DROPS += 1;
             }
         }
     }
 
     let mut v = vec![Elem(1), Elem(2), Elem(3), Elem(4), Elem(5)];
-    assert_eq!(unsafe { drops }, 0);
+    assert_eq!(unsafe { DROPS }, 0);
     v.truncate(3);
-    assert_eq!(unsafe { drops }, 2);
+    assert_eq!(unsafe { DROPS }, 2);
     v.truncate(0);
-    assert_eq!(unsafe { drops }, 5);
+    assert_eq!(unsafe { DROPS }, 5);
 }
 
 #[test]
diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollectionstest/vec_deque.rs
index 5e8633a9748..9dfd3430268 100644
--- a/src/libcollectionstest/vec_deque.rs
+++ b/src/libcollectionstest/vec_deque.rs
@@ -695,12 +695,12 @@ fn test_show() {
 
 #[test]
 fn test_drop() {
-    static mut drops: i32 = 0;
+    static mut DROPS: i32 = 0;
     struct Elem;
     impl Drop for Elem {
         fn drop(&mut self) {
             unsafe {
-                drops += 1;
+                DROPS += 1;
             }
         }
     }
@@ -712,17 +712,17 @@ fn test_drop() {
     ring.push_front(Elem);
     drop(ring);
 
-    assert_eq!(unsafe { drops }, 4);
+    assert_eq!(unsafe { DROPS }, 4);
 }
 
 #[test]
 fn test_drop_with_pop() {
-    static mut drops: i32 = 0;
+    static mut DROPS: i32 = 0;
     struct Elem;
     impl Drop for Elem {
         fn drop(&mut self) {
             unsafe {
-                drops += 1;
+                DROPS += 1;
             }
         }
     }
@@ -735,20 +735,20 @@ fn test_drop_with_pop() {
 
     drop(ring.pop_back());
     drop(ring.pop_front());
-    assert_eq!(unsafe { drops }, 2);
+    assert_eq!(unsafe { DROPS }, 2);
 
     drop(ring);
-    assert_eq!(unsafe { drops }, 4);
+    assert_eq!(unsafe { DROPS }, 4);
 }
 
 #[test]
 fn test_drop_clear() {
-    static mut drops: i32 = 0;
+    static mut DROPS: i32 = 0;
     struct Elem;
     impl Drop for Elem {
         fn drop(&mut self) {
             unsafe {
-                drops += 1;
+                DROPS += 1;
             }
         }
     }
@@ -759,10 +759,10 @@ fn test_drop_clear() {
     ring.push_back(Elem);
     ring.push_front(Elem);
     ring.clear();
-    assert_eq!(unsafe { drops }, 4);
+    assert_eq!(unsafe { DROPS }, 4);
 
     drop(ring);
-    assert_eq!(unsafe { drops }, 4);
+    assert_eq!(unsafe { DROPS }, 4);
 }
 
 #[test]
diff --git a/src/libcore/any.rs b/src/libcore/any.rs
index a3018a46eea..f7edcb998a9 100644
--- a/src/libcore/any.rs
+++ b/src/libcore/any.rs
@@ -73,7 +73,6 @@
 
 use fmt;
 use intrinsics;
-use marker::Reflect;
 
 ///////////////////////////////////////////////////////////////////////////////
 // Any trait
@@ -86,7 +85,7 @@ use marker::Reflect;
 ///
 /// [mod]: index.html
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait Any: Reflect + 'static {
+pub trait Any: 'static {
     /// Gets the `TypeId` of `self`.
     ///
     /// # Examples
@@ -112,7 +111,7 @@ pub trait Any: Reflect + 'static {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Reflect + 'static + ?Sized > Any for T {
+impl<T: 'static + ?Sized > Any for T {
     fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
 }
 
@@ -366,7 +365,7 @@ impl TypeId {
     /// }
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    pub fn of<T: ?Sized + Reflect + 'static>() -> TypeId {
+    pub fn of<T: ?Sized + 'static>() -> TypeId {
         TypeId {
             t: unsafe { intrinsics::type_id::<T>() },
         }
diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs
index 6a60cfcc120..ac36cbaace7 100644
--- a/src/libcore/hash/mod.rs
+++ b/src/libcore/hash/mod.rs
@@ -38,7 +38,9 @@
 //! ```
 //!
 //! If you need more control over how a value is hashed, you need to implement
-//! the `Hash` trait:
+//! the [`Hash`] trait:
+//!
+//! [`Hash`]: trait.Hash.html
 //!
 //! ```rust
 //! use std::hash::{Hash, Hasher, SipHasher};
@@ -90,7 +92,7 @@ mod sip;
 /// The `H` type parameter is an abstract hash state that is used by the `Hash`
 /// to compute the hash.
 ///
-/// If you are also implementing `Eq`, there is an additional property that
+/// If you are also implementing [`Eq`], there is an additional property that
 /// is important:
 ///
 /// ```text
@@ -98,13 +100,13 @@ mod sip;
 /// ```
 ///
 /// In other words, if two keys are equal, their hashes should also be equal.
-/// `HashMap` and `HashSet` both rely on this behavior.
+/// [`HashMap`] and [`HashSet`] both rely on this behavior.
 ///
 /// ## Derivable
 ///
 /// This trait can be used with `#[derive]` if all fields implement `Hash`.
 /// When `derive`d, the resulting hash will be the combination of the values
-/// from calling `.hash()` on each field.
+/// from calling [`.hash()`] on each field.
 ///
 /// ## How can I implement `Hash`?
 ///
@@ -127,6 +129,11 @@ mod sip;
 ///     }
 /// }
 /// ```
+///
+/// [`Eq`]: ../../std/cmp/trait.Eq.html
+/// [`HashMap`]: ../../std/collections/struct.HashMap.html
+/// [`HashSet`]: ../../std/collections/struct.HashSet.html
+/// [`.hash()`]: #tymethod.hash
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Hash {
     /// Feeds this value into the state given, updating the hasher as necessary.
@@ -151,35 +158,35 @@ pub trait Hasher {
     #[stable(feature = "rust1", since = "1.0.0")]
     fn finish(&self) -> u64;
 
-    /// Writes some data into this `Hasher`
+    /// Writes some data into this `Hasher`.
     #[stable(feature = "rust1", since = "1.0.0")]
     fn write(&mut self, bytes: &[u8]);
 
-    /// Write a single `u8` into this hasher
+    /// Write a single `u8` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_u8(&mut self, i: u8) {
         self.write(&[i])
     }
-    /// Write a single `u16` into this hasher.
+    /// Writes a single `u16` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_u16(&mut self, i: u16) {
         self.write(&unsafe { mem::transmute::<_, [u8; 2]>(i) })
     }
-    /// Write a single `u32` into this hasher.
+    /// Writes a single `u32` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_u32(&mut self, i: u32) {
         self.write(&unsafe { mem::transmute::<_, [u8; 4]>(i) })
     }
-    /// Write a single `u64` into this hasher.
+    /// Writes a single `u64` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_u64(&mut self, i: u64) {
         self.write(&unsafe { mem::transmute::<_, [u8; 8]>(i) })
     }
-    /// Write a single `usize` into this hasher.
+    /// Writes a single `usize` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_usize(&mut self, i: usize) {
@@ -189,31 +196,31 @@ pub trait Hasher {
         self.write(bytes);
     }
 
-    /// Write a single `i8` into this hasher.
+    /// Writes a single `i8` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_i8(&mut self, i: i8) {
         self.write_u8(i as u8)
     }
-    /// Write a single `i16` into this hasher.
+    /// Writes a single `i16` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_i16(&mut self, i: i16) {
         self.write_u16(i as u16)
     }
-    /// Write a single `i32` into this hasher.
+    /// Writes a single `i32` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_i32(&mut self, i: i32) {
         self.write_u32(i as u32)
     }
-    /// Write a single `i64` into this hasher.
+    /// Writes a single `i64` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_i64(&mut self, i: i64) {
         self.write_u64(i as u64)
     }
-    /// Write a single `isize` into this hasher.
+    /// Writes a single `isize` into this hasher.
     #[inline]
     #[stable(feature = "hasher_write", since = "1.3.0")]
     fn write_isize(&mut self, i: isize) {
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs
index 1ae4cf8e5ef..28101d21fc2 100644
--- a/src/libcore/lib.rs
+++ b/src/libcore/lib.rs
@@ -89,7 +89,7 @@
 #![feature(specialization)]
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![feature(never_type)]
 #![feature(prelude_import)]
 
diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs
index 99c24e4c48d..6e08abd3461 100644
--- a/src/libcore/macros.rs
+++ b/src/libcore/macros.rs
@@ -255,6 +255,9 @@ macro_rules! debug_assert_ne {
 /// Helper macro for reducing boilerplate code for matching `Result` together
 /// with converting downstream errors.
 ///
+/// Prefer using `?` syntax to `try!`. `?` is built in to the language and is
+/// more succinct than `try!`. It is the standard method for error propagation.
+///
 /// `try!` matches the given `Result`. In case of the `Ok` variant, the
 /// expression has the value of the wrapped value.
 ///
diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs
index 5a1a034a363..03d8af1563d 100644
--- a/src/libcore/marker.rs
+++ b/src/libcore/marker.rs
@@ -587,6 +587,7 @@ mod impls {
 #[unstable(feature = "reflect_marker",
            reason = "requires RFC and more experience",
            issue = "27749")]
+#[rustc_deprecated(since = "1.14.0", reason = "Specialization makes parametricity impossible")]
 #[rustc_on_unimplemented = "`{Self}` does not implement `Any`; \
                             ensure all type parameters are bounded by `Any`"]
 pub trait Reflect {}
@@ -594,4 +595,6 @@ pub trait Reflect {}
 #[unstable(feature = "reflect_marker",
            reason = "requires RFC and more experience",
            issue = "27749")]
+#[rustc_deprecated(since = "1.14.0", reason = "Specialization makes parametricity impossible")]
+#[allow(deprecated)]
 impl Reflect for .. { }
diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs
index 1ca550c6746..a1f4630c304 100644
--- a/src/libcore/num/bignum.rs
+++ b/src/libcore/num/bignum.rs
@@ -34,19 +34,22 @@ use intrinsics;
 pub trait FullOps: Sized {
     /// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
     /// where `W` is the number of bits in `Self`.
-    fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self);
+    fn full_add(self, other: Self, carry: bool) -> (bool /* carry */, Self);
 
     /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + carry`,
     /// where `W` is the number of bits in `Self`.
-    fn full_mul(self, other: Self, carry: Self) -> (Self /*carry*/, Self);
+    fn full_mul(self, other: Self, carry: Self) -> (Self /* carry */, Self);
 
     /// Returns `(carry', v')` such that `carry' * 2^W + v' = self * other + other2 + carry`,
     /// where `W` is the number of bits in `Self`.
-    fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /*carry*/, Self);
+    fn full_mul_add(self, other: Self, other2: Self, carry: Self) -> (Self /* carry */, Self);
 
     /// Returns `(quo, rem)` such that `borrow * 2^W + self = quo * other + rem`
     /// and `0 <= rem < other`, where `W` is the number of bits in `Self`.
-    fn full_div_rem(self, other: Self, borrow: Self) -> (Self /*quotient*/, Self /*remainder*/);
+    fn full_div_rem(self,
+                    other: Self,
+                    borrow: Self)
+                    -> (Self /* quotient */, Self /* remainder */);
 }
 
 macro_rules! impl_full_ops {
@@ -100,11 +103,7 @@ impl_full_ops! {
 
 /// Table of powers of 5 representable in digits. Specifically, the largest {u8, u16, u32} value
 /// that's a power of five, plus the corresponding exponent. Used in `mul_pow5`.
-const SMALL_POW5: [(u64, usize); 3] = [
-    (125, 3),
-    (15625, 6),
-    (1_220_703_125, 13),
-];
+const SMALL_POW5: [(u64, usize); 3] = [(125, 3), (15625, 6), (1_220_703_125, 13)];
 
 macro_rules! define_bignum {
     ($name:ident: type=$ty:ty, n=$n:expr) => (
diff --git a/src/libcore/num/diy_float.rs b/src/libcore/num/diy_float.rs
index 7c369ee3b3b..11eea753f93 100644
--- a/src/libcore/num/diy_float.rs
+++ b/src/libcore/num/diy_float.rs
@@ -49,12 +49,30 @@ impl Fp {
     pub fn normalize(&self) -> Fp {
         let mut f = self.f;
         let mut e = self.e;
-        if f >> (64 - 32) == 0 { f <<= 32; e -= 32; }
-        if f >> (64 - 16) == 0 { f <<= 16; e -= 16; }
-        if f >> (64 -  8) == 0 { f <<=  8; e -=  8; }
-        if f >> (64 -  4) == 0 { f <<=  4; e -=  4; }
-        if f >> (64 -  2) == 0 { f <<=  2; e -=  2; }
-        if f >> (64 -  1) == 0 { f <<=  1; e -=  1; }
+        if f >> (64 - 32) == 0 {
+            f <<= 32;
+            e -= 32;
+        }
+        if f >> (64 - 16) == 0 {
+            f <<= 16;
+            e -= 16;
+        }
+        if f >> (64 - 8) == 0 {
+            f <<= 8;
+            e -= 8;
+        }
+        if f >> (64 - 4) == 0 {
+            f <<= 4;
+            e -= 4;
+        }
+        if f >> (64 - 2) == 0 {
+            f <<= 2;
+            e -= 2;
+        }
+        if f >> (64 - 1) == 0 {
+            f <<= 1;
+            e -= 1;
+        }
         debug_assert!(f >= (1 >> 63));
         Fp { f: f, e: e }
     }
@@ -66,6 +84,9 @@ impl Fp {
         assert!(edelta >= 0);
         let edelta = edelta as usize;
         assert_eq!(self.f << edelta >> edelta, self.f);
-        Fp { f: self.f << edelta, e: e }
+        Fp {
+            f: self.f << edelta,
+            e: e,
+        }
     }
 }
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index 07b05f91f48..4527d46a27d 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -61,13 +61,13 @@ pub const MAX_10_EXP: i32 = 38;
 
 /// Not a Number (NaN).
 #[stable(feature = "rust1", since = "1.0.0")]
-pub const NAN: f32 = 0.0_f32/0.0_f32;
+pub const NAN: f32 = 0.0_f32 / 0.0_f32;
 /// Infinity (∞).
 #[stable(feature = "rust1", since = "1.0.0")]
-pub const INFINITY: f32 = 1.0_f32/0.0_f32;
+pub const INFINITY: f32 = 1.0_f32 / 0.0_f32;
 /// Negative infinity (-∞).
 #[stable(feature = "rust1", since = "1.0.0")]
-pub const NEG_INFINITY: f32 = -1.0_f32/0.0_f32;
+pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32;
 
 /// Basic mathematical constants.
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -144,26 +144,40 @@ pub mod consts {
            issue = "32110")]
 impl Float for f32 {
     #[inline]
-    fn nan() -> f32 { NAN }
+    fn nan() -> f32 {
+        NAN
+    }
 
     #[inline]
-    fn infinity() -> f32 { INFINITY }
+    fn infinity() -> f32 {
+        INFINITY
+    }
 
     #[inline]
-    fn neg_infinity() -> f32 { NEG_INFINITY }
+    fn neg_infinity() -> f32 {
+        NEG_INFINITY
+    }
 
     #[inline]
-    fn zero() -> f32 { 0.0 }
+    fn zero() -> f32 {
+        0.0
+    }
 
     #[inline]
-    fn neg_zero() -> f32 { -0.0 }
+    fn neg_zero() -> f32 {
+        -0.0
+    }
 
     #[inline]
-    fn one() -> f32 { 1.0 }
+    fn one() -> f32 {
+        1.0
+    }
 
     /// Returns `true` if the number is NaN.
     #[inline]
-    fn is_nan(self) -> bool { self != self }
+    fn is_nan(self) -> bool {
+        self != self
+    }
 
     /// Returns `true` if the number is infinite.
     #[inline]
@@ -192,11 +206,11 @@ impl Float for f32 {
 
         let bits: u32 = unsafe { mem::transmute(self) };
         match (bits & MAN_MASK, bits & EXP_MASK) {
-            (0, 0)        => Fp::Zero,
-            (_, 0)        => Fp::Subnormal,
+            (0, 0) => Fp::Zero,
+            (_, 0) => Fp::Subnormal,
             (0, EXP_MASK) => Fp::Infinite,
             (_, EXP_MASK) => Fp::Nan,
-            _             => Fp::Normal,
+            _ => Fp::Normal,
         }
     }
 
@@ -252,7 +266,9 @@ impl Float for f32 {
 
     /// Returns the reciprocal (multiplicative inverse) of the number.
     #[inline]
-    fn recip(self) -> f32 { 1.0 / self }
+    fn recip(self) -> f32 {
+        1.0 / self
+    }
 
     #[inline]
     fn powi(self, n: i32) -> f32 {
@@ -261,7 +277,9 @@ impl Float for f32 {
 
     /// Converts to degrees, assuming the number is in radians.
     #[inline]
-    fn to_degrees(self) -> f32 { self * (180.0f32 / consts::PI) }
+    fn to_degrees(self) -> f32 {
+        self * (180.0f32 / consts::PI)
+    }
 
     /// Converts to radians, assuming the number is in degrees.
     #[inline]
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 82a09e599e0..991a8568349 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -61,13 +61,13 @@ pub const MAX_10_EXP: i32 = 308;
 
 /// Not a Number (NaN).
 #[stable(feature = "rust1", since = "1.0.0")]
-pub const NAN: f64 = 0.0_f64/0.0_f64;
+pub const NAN: f64 = 0.0_f64 / 0.0_f64;
 /// Infinity (∞).
 #[stable(feature = "rust1", since = "1.0.0")]
-pub const INFINITY: f64 = 1.0_f64/0.0_f64;
+pub const INFINITY: f64 = 1.0_f64 / 0.0_f64;
 /// Negative infinity (-∞).
 #[stable(feature = "rust1", since = "1.0.0")]
-pub const NEG_INFINITY: f64 = -1.0_f64/0.0_f64;
+pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64;
 
 /// Basic mathematical constants.
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -144,26 +144,40 @@ pub mod consts {
            issue = "32110")]
 impl Float for f64 {
     #[inline]
-    fn nan() -> f64 { NAN }
+    fn nan() -> f64 {
+        NAN
+    }
 
     #[inline]
-    fn infinity() -> f64 { INFINITY }
+    fn infinity() -> f64 {
+        INFINITY
+    }
 
     #[inline]
-    fn neg_infinity() -> f64 { NEG_INFINITY }
+    fn neg_infinity() -> f64 {
+        NEG_INFINITY
+    }
 
     #[inline]
-    fn zero() -> f64 { 0.0 }
+    fn zero() -> f64 {
+        0.0
+    }
 
     #[inline]
-    fn neg_zero() -> f64 { -0.0 }
+    fn neg_zero() -> f64 {
+        -0.0
+    }
 
     #[inline]
-    fn one() -> f64 { 1.0 }
+    fn one() -> f64 {
+        1.0
+    }
 
     /// Returns `true` if the number is NaN.
     #[inline]
-    fn is_nan(self) -> bool { self != self }
+    fn is_nan(self) -> bool {
+        self != self
+    }
 
     /// Returns `true` if the number is infinite.
     #[inline]
@@ -192,11 +206,11 @@ impl Float for f64 {
 
         let bits: u64 = unsafe { mem::transmute(self) };
         match (bits & MAN_MASK, bits & EXP_MASK) {
-            (0, 0)        => Fp::Zero,
-            (_, 0)        => Fp::Subnormal,
+            (0, 0) => Fp::Zero,
+            (_, 0) => Fp::Subnormal,
             (0, EXP_MASK) => Fp::Infinite,
             (_, EXP_MASK) => Fp::Nan,
-            _             => Fp::Normal,
+            _ => Fp::Normal,
         }
     }
 
@@ -252,7 +266,9 @@ impl Float for f64 {
 
     /// Returns the reciprocal (multiplicative inverse) of the number.
     #[inline]
-    fn recip(self) -> f64 { 1.0 / self }
+    fn recip(self) -> f64 {
+        1.0 / self
+    }
 
     #[inline]
     fn powi(self, n: i32) -> f64 {
@@ -261,7 +277,9 @@ impl Float for f64 {
 
     /// Converts to degrees, assuming the number is in radians.
     #[inline]
-    fn to_degrees(self) -> f64 { self * (180.0f64 / consts::PI) }
+    fn to_degrees(self) -> f64 {
+        self * (180.0f64 / consts::PI)
+    }
 
     /// Converts to radians, assuming the number is in degrees.
     #[inline]
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 516d6f7c4a0..a4529909e83 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -43,7 +43,8 @@ use str::FromStr;
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)]
-pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
+pub struct Wrapping<T>(#[stable(feature = "rust1", since = "1.0.0")]
+                       pub T);
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: fmt::Debug> fmt::Debug for Wrapping<T> {
@@ -2402,7 +2403,7 @@ pub enum FpCategory {
 
     /// Positive or negative infinity.
     #[stable(feature = "rust1", since = "1.0.0")]
-    Infinite ,
+    Infinite,
 
     /// Positive or negative zero.
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -2662,8 +2663,7 @@ macro_rules! doit {
 }
 doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }
 
-fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
-                                         -> Result<T, ParseIntError> {
+fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32) -> Result<T, ParseIntError> {
     use self::IntErrorKind::*;
     use self::ParseIntError as PIE;
 
@@ -2686,7 +2686,7 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
     let (is_positive, digits) = match src[0] {
         b'+' => (true, &src[1..]),
         b'-' if is_signed_ty => (false, &src[1..]),
-        _ => (true, src)
+        _ => (true, src),
     };
 
     if digits.is_empty() {
@@ -2738,7 +2738,9 @@ fn from_str_radix<T: FromStrRadixHelper>(src: &str, radix: u32)
 /// [`i8::from_str_radix()`]: ../../std/primitive.i8.html#method.from_str_radix
 #[derive(Debug, Clone, PartialEq, Eq)]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub struct ParseIntError { kind: IntErrorKind }
+pub struct ParseIntError {
+    kind: IntErrorKind,
+}
 
 #[derive(Debug, Clone, PartialEq, Eq)]
 enum IntErrorKind {
diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs
index 2c69880dfa3..d35c451ac26 100644
--- a/src/libcore/num/wrapping.rs
+++ b/src/libcore/num/wrapping.rs
@@ -310,13 +310,13 @@ mod shift_max {
         pub const isize: u32 = super::i64;
     }
 
-    pub const  i8: u32 = (1 << 3) - 1;
+    pub const i8: u32 = (1 << 3) - 1;
     pub const i16: u32 = (1 << 4) - 1;
     pub const i32: u32 = (1 << 5) - 1;
     pub const i64: u32 = (1 << 6) - 1;
     pub use self::platform::isize;
 
-    pub const  u8: u32 = i8;
+    pub const u8: u32 = i8;
     pub const u16: u32 = i16;
     pub const u32: u32 = i32;
     pub const u64: u32 = i64;
diff --git a/src/libgraphviz/lib.rs b/src/libgraphviz/lib.rs
index 74cc498a7df..95c46ec5715 100644
--- a/src/libgraphviz/lib.rs
+++ b/src/libgraphviz/lib.rs
@@ -295,7 +295,7 @@
 #![cfg_attr(not(stage0), deny(warnings))]
 
 #![feature(str_escape)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 
 use self::LabelText::*;
 
diff --git a/src/liblibc b/src/liblibc
-Subproject 5a17b4a733a22d445fdd63326f826fcd8a58432
+Subproject ebeab042e6bb14a447627b57ed9a493e2cc0e09
diff --git a/src/liblog/directive.rs b/src/liblog/directive.rs
index f1ebf167378..eb50d6e6135 100644
--- a/src/liblog/directive.rs
+++ b/src/liblog/directive.rs
@@ -22,12 +22,12 @@ pub const LOG_LEVEL_NAMES: [&'static str; 5] = ["ERROR", "WARN", "INFO", "DEBUG"
 /// Parse an individual log level that is either a number or a symbolic log level
 fn parse_log_level(level: &str) -> Option<u32> {
     level.parse::<u32>()
-         .ok()
-         .or_else(|| {
-             let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
-             pos.map(|p| p as u32 + 1)
-         })
-         .map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
+        .ok()
+        .or_else(|| {
+            let pos = LOG_LEVEL_NAMES.iter().position(|&name| name.eq_ignore_ascii_case(level));
+            pos.map(|p| p as u32 + 1)
+        })
+        .map(|p| cmp::min(p, ::MAX_LOG_LEVEL))
 }
 
 /// Parse a logging specification string (e.g: "crate1,crate2::mod3,crate3::x=1/foo")
@@ -52,32 +52,31 @@ pub fn parse_logging_spec(spec: &str) -> (Vec<LogDirective>, Option<String>) {
                 continue;
             }
             let mut parts = s.split('=');
-            let (log_level, name) = match (parts.next(),
-                                           parts.next().map(|s| s.trim()),
-                                           parts.next()) {
-                (Some(part0), None, None) => {
-                    // if the single argument is a log-level string or number,
-                    // treat that as a global fallback
-                    match parse_log_level(part0) {
-                        Some(num) => (num, None),
-                        None => (::MAX_LOG_LEVEL, Some(part0)),
+            let (log_level, name) =
+                match (parts.next(), parts.next().map(|s| s.trim()), parts.next()) {
+                    (Some(part0), None, None) => {
+                        // if the single argument is a log-level string or number,
+                        // treat that as a global fallback
+                        match parse_log_level(part0) {
+                            Some(num) => (num, None),
+                            None => (::MAX_LOG_LEVEL, Some(part0)),
+                        }
                     }
-                }
-                (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
-                (Some(part0), Some(part1), None) => {
-                    match parse_log_level(part1) {
-                        Some(num) => (num, Some(part0)),
-                        _ => {
-                            println!("warning: invalid logging spec '{}', ignoring it", part1);
-                            continue;
+                    (Some(part0), Some(""), None) => (::MAX_LOG_LEVEL, Some(part0)),
+                    (Some(part0), Some(part1), None) => {
+                        match parse_log_level(part1) {
+                            Some(num) => (num, Some(part0)),
+                            _ => {
+                                println!("warning: invalid logging spec '{}', ignoring it", part1);
+                                continue;
+                            }
                         }
                     }
-                }
-                _ => {
-                    println!("warning: invalid logging spec '{}', ignoring it", s);
-                    continue;
-                }
-            };
+                    _ => {
+                        println!("warning: invalid logging spec '{}', ignoring it", s);
+                        continue;
+                    }
+                };
             dirs.push(LogDirective {
                 name: name.map(str::to_owned),
                 level: log_level,
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs
index de68cc707ad..465a09505e4 100644
--- a/src/librustc/diagnostics.rs
+++ b/src/librustc/diagnostics.rs
@@ -1327,30 +1327,6 @@ let x: i32 = "I am not a number!";
 //      |
 //    type `i32` assigned to variable `x`
 ```
-
-Another situation in which this occurs is when you attempt to use the `try!`
-macro inside a function that does not return a `Result<T, E>`:
-
-```compile_fail,E0308
-use std::fs::File;
-
-fn main() {
-    let mut f = try!(File::create("foo.txt"));
-}
-```
-
-This code gives an error like this:
-
-```text
-<std macros>:5:8: 6:42 error: mismatched types:
- expected `()`,
-     found `core::result::Result<_, _>`
- (expected (),
-     found enum `core::result::Result`) [E0308]
-```
-
-`try!` returns a `Result<T, E>`, and so the function must. But `main()` has
-`()` as its return type, hence the error.
 "##,
 
 E0309: r##"
@@ -1431,6 +1407,23 @@ fn make_child<'elve>(x: &mut &'elve isize, y: &mut &'elve isize) {
 ```
 "##,
 
+E0317: r##"
+This error occurs when an `if` expression without an `else` block is used in a
+context where a type other than `()` is expected, for example a `let`
+expression:
+
+```compile_fail,E0317
+fn main() {
+    let x = 5;
+    let a = if x == 5 { 1 };
+}
+```
+
+An `if` expression without an `else` block has the type `()`, so this is a type
+error. To resolve it, add an `else` block having the same type as the `if`
+block.
+"##,
+
 E0398: r##"
 In Rust 1.3, the default object lifetime bounds are expected to change, as
 described in RFC #1156 [1]. You are getting a warning because the compiler
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index bca3ed93812..137c6b58dc9 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -94,13 +94,7 @@ pub fn lower_crate(sess: &Session,
     let _ignore = sess.dep_graph.in_ignore();
 
     LoweringContext {
-        crate_root: if std_inject::no_core(krate) {
-            None
-        } else if std_inject::no_std(krate) {
-            Some("core")
-        } else {
-            Some("std")
-        },
+        crate_root: std_inject::injected_crate_name(krate),
         sess: sess,
         parent_def: None,
         resolver: resolver,
diff --git a/src/librustc/infer/error_reporting.rs b/src/librustc/infer/error_reporting.rs
index 3f216d69168..373ea4aac57 100644
--- a/src/librustc/infer/error_reporting.rs
+++ b/src/librustc/infer/error_reporting.rs
@@ -577,11 +577,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                                          terr: &TypeError<'tcx>)
                                          -> DiagnosticBuilder<'tcx>
     {
-        // FIXME: do we want to use a different error code for each origin?
-        let mut diag = struct_span_err!(
-            self.tcx.sess, trace.origin.span(), E0308,
-            "{}", trace.origin.as_failure_str()
-        );
+        let span = trace.origin.span();
+        let failure_str = trace.origin.as_failure_str();
+        let mut diag = match trace.origin {
+            TypeOrigin::IfExpressionWithNoElse(_) => {
+                struct_span_err!(self.tcx.sess, span, E0317, "{}", failure_str)
+            },
+            _ => {
+                struct_span_err!(self.tcx.sess, span, E0308, "{}", failure_str)
+            },
+        };
         self.note_type_err(&mut diag, trace.origin, None, Some(trace.values), terr);
         diag
     }
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 39fc50666a8..af994e884fe 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -25,7 +25,7 @@ use middle::mem_categorization as mc;
 use middle::mem_categorization::McResult;
 use middle::region::CodeExtent;
 use mir::tcx::LvalueTy;
-use ty::subst::{Subst, Substs};
+use ty::subst::{Kind, Subst, Substs};
 use ty::adjustment;
 use ty::{TyVid, IntVid, FloatVid};
 use ty::{self, Ty, TyCtxt};
@@ -583,7 +583,8 @@ impl_trans_normalize!('gcx,
     ty::FnSig<'gcx>,
     &'gcx ty::BareFnTy<'gcx>,
     ty::ClosureSubsts<'gcx>,
-    ty::PolyTraitRef<'gcx>
+    ty::PolyTraitRef<'gcx>,
+    ty::ExistentialTraitRef<'gcx>
 );
 
 impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> {
@@ -603,6 +604,18 @@ impl<'gcx> TransNormalize<'gcx> for LvalueTy<'gcx> {
 
 // NOTE: Callable from trans only!
 impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
+    /// Currently, higher-ranked type bounds inhibit normalization. Therefore,
+    /// each time we erase them in translation, we need to normalize
+    /// the contents.
+    pub fn erase_late_bound_regions_and_normalize<T>(self, value: &ty::Binder<T>)
+        -> T
+        where T: TransNormalize<'tcx>
+    {
+        assert!(!value.needs_subst());
+        let value = self.erase_late_bound_regions(value);
+        self.normalize_associated_type(&value)
+    }
+
     pub fn normalize_associated_type<T>(self, value: &T) -> T
         where T: TransNormalize<'tcx>
     {
@@ -1208,7 +1221,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     pub fn type_var_for_def(&self,
                             span: Span,
                             def: &ty::TypeParameterDef<'tcx>,
-                            substs: &Substs<'tcx>)
+                            substs: &[Kind<'tcx>])
                             -> Ty<'tcx> {
         let default = def.default.map(|default| {
             type_variable::Default {
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index c34286f0195..25731df4778 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -40,7 +40,7 @@
 #![feature(rustc_private)]
 #![feature(slice_patterns)]
 #![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![cfg_attr(test, feature(test))]
 
 extern crate arena;
diff --git a/src/librustc/session/filesearch.rs b/src/librustc/session/filesearch.rs
index a3eea324fd8..82c2425aead 100644
--- a/src/librustc/session/filesearch.rs
+++ b/src/librustc/session/filesearch.rs
@@ -12,6 +12,7 @@
 
 pub use self::FileMatch::*;
 
+use std::borrow::Cow;
 use std::collections::HashSet;
 use std::env;
 use std::fs;
@@ -67,33 +68,32 @@ impl<'a> FileSearch<'a> {
     {
         self.for_each_lib_search_path(|lib_search_path, kind| {
             debug!("searching {}", lib_search_path.display());
-            match fs::read_dir(lib_search_path) {
-                Ok(files) => {
-                    let files = files.filter_map(|p| p.ok().map(|s| s.path()))
-                                     .collect::<Vec<_>>();
-                    fn is_rlib(p: &Path) -> bool {
-                        p.extension().and_then(|s| s.to_str()) == Some("rlib")
+            let files = match fs::read_dir(lib_search_path) {
+                Ok(files) => files,
+                Err(..) => return,
+            };
+            let files = files.filter_map(|p| p.ok().map(|s| s.path()))
+                             .collect::<Vec<_>>();
+            fn is_rlib(p: &Path) -> bool {
+                p.extension() == Some("rlib".as_ref())
+            }
+            // Reading metadata out of rlibs is faster, and if we find both
+            // an rlib and a dylib we only read one of the files of
+            // metadata, so in the name of speed, bring all rlib files to
+            // the front of the search list.
+            let files1 = files.iter().filter(|p| is_rlib(p));
+            let files2 = files.iter().filter(|p| !is_rlib(p));
+            for path in files1.chain(files2) {
+                debug!("testing {}", path.display());
+                let maybe_picked = pick(path, kind);
+                match maybe_picked {
+                    FileMatches => {
+                        debug!("picked {}", path.display());
                     }
-                    // Reading metadata out of rlibs is faster, and if we find both
-                    // an rlib and a dylib we only read one of the files of
-                    // metadata, so in the name of speed, bring all rlib files to
-                    // the front of the search list.
-                    let files1 = files.iter().filter(|p| is_rlib(p));
-                    let files2 = files.iter().filter(|p| !is_rlib(p));
-                    for path in files1.chain(files2) {
-                        debug!("testing {}", path.display());
-                        let maybe_picked = pick(path, kind);
-                        match maybe_picked {
-                            FileMatches => {
-                                debug!("picked {}", path.display());
-                            }
-                            FileDoesntMatch => {
-                                debug!("rejected {}", path.display());
-                            }
-                        }
+                    FileDoesntMatch => {
+                        debug!("rejected {}", path.display());
                     }
                 }
-                Err(..) => (),
             }
         });
     }
@@ -123,8 +123,8 @@ impl<'a> FileSearch<'a> {
     // Returns a list of directories where target-specific tool binaries are located.
     pub fn get_tools_search_paths(&self) -> Vec<PathBuf> {
         let mut p = PathBuf::from(self.sysroot);
-        p.push(&find_libdir(self.sysroot));
-        p.push(&rustlibdir());
+        p.push(find_libdir(self.sysroot).as_ref());
+        p.push(RUST_LIB_DIR);
         p.push(&self.triple);
         p.push("bin");
         vec![p]
@@ -132,9 +132,9 @@ impl<'a> FileSearch<'a> {
 }
 
 pub fn relative_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf {
-    let mut p = PathBuf::from(&find_libdir(sysroot));
+    let mut p = PathBuf::from(find_libdir(sysroot).as_ref());
     assert!(p.is_relative());
-    p.push(&rustlibdir());
+    p.push(RUST_LIB_DIR);
     p.push(target_triple);
     p.push("lib");
     p
@@ -166,7 +166,7 @@ pub fn get_or_default_sysroot() -> PathBuf {
 }
 
 // The name of the directory rustc expects libraries to be located.
-fn find_libdir(sysroot: &Path) -> String {
+fn find_libdir(sysroot: &Path) -> Cow<'static, str> {
     // FIXME: This is a quick hack to make the rustc binary able to locate
     // Rust libraries in Linux environments where libraries might be installed
     // to lib64/lib32. This would be more foolproof by basing the sysroot off
@@ -176,31 +176,23 @@ fn find_libdir(sysroot: &Path) -> String {
     // "lib" (i.e. non-default), this value is used (see issue #16552).
 
     match option_env!("CFG_LIBDIR_RELATIVE") {
-        Some(libdir) if libdir != "lib" => return libdir.to_string(),
-        _ => if sysroot.join(&primary_libdir_name()).join(&rustlibdir()).exists() {
-            return primary_libdir_name();
+        Some(libdir) if libdir != "lib" => return libdir.into(),
+        _ => if sysroot.join(PRIMARY_LIB_DIR).join(RUST_LIB_DIR).exists() {
+            return PRIMARY_LIB_DIR.into();
         } else {
-            return secondary_libdir_name();
+            return SECONDARY_LIB_DIR.into();
         }
     }
 
     #[cfg(target_pointer_width = "64")]
-    fn primary_libdir_name() -> String {
-        "lib64".to_string()
-    }
+    const PRIMARY_LIB_DIR: &'static str = "lib64";
 
     #[cfg(target_pointer_width = "32")]
-    fn primary_libdir_name() -> String {
-        "lib32".to_string()
-    }
+    const PRIMARY_LIB_DIR: &'static str = "lib32";
 
-    fn secondary_libdir_name() -> String {
-        "lib".to_string()
-    }
+    const SECONDARY_LIB_DIR: &'static str = "lib";
 }
 
 // The name of rustc's own place to organize libraries.
 // Used to be "rustc", now the default is "rustlib"
-pub fn rustlibdir() -> String {
-    "rustlib".to_string()
-}
+const RUST_LIB_DIR: &'static str = "rustlib";
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index f706bab32c8..d002aba595b 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -118,6 +118,8 @@ pub struct PerfStats {
     pub incr_comp_hashes_time: Cell<Duration>,
     // The number of incr. comp. hash computations performed
     pub incr_comp_hashes_count: Cell<u64>,
+    // The number of bytes hashed when computing ICH values
+    pub incr_comp_bytes_hashed: Cell<u64>,
     // The accumulated time spent on computing symbol hashes
     pub symbol_hash_time: Cell<Duration>,
 }
@@ -439,6 +441,11 @@ impl Session {
                  duration_to_secs_str(self.perf_stats.incr_comp_hashes_time.get()));
         println!("Total number of incr. comp. hashes computed:   {}",
                  self.perf_stats.incr_comp_hashes_count.get());
+        println!("Total number of bytes hashed for incr. comp.:  {}",
+                 self.perf_stats.incr_comp_bytes_hashed.get());
+        println!("Average bytes hashed per incr. comp. HIR node: {}",
+                 self.perf_stats.incr_comp_bytes_hashed.get() /
+                 self.perf_stats.incr_comp_hashes_count.get());
         println!("Total time spent computing symbol hashes:      {}",
                  duration_to_secs_str(self.perf_stats.symbol_hash_time.get()));
     }
@@ -571,6 +578,7 @@ pub fn build_session_(sopts: config::Options,
             svh_time: Cell::new(Duration::from_secs(0)),
             incr_comp_hashes_time: Cell::new(Duration::from_secs(0)),
             incr_comp_hashes_count: Cell::new(0),
+            incr_comp_bytes_hashed: Cell::new(0),
             symbol_hash_time: Cell::new(Duration::from_secs(0)),
         }
     };
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index 66631111097..dbaa8db3e89 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -336,7 +336,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
         self.infcx.tcx
     }
 
-    pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'tcx> {
+    pub fn param_env(&self) -> &'cx ty::ParameterEnvironment<'gcx> {
         self.infcx.param_env()
     }
 
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index d371cc2f8ad..8352d6bed50 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -22,7 +22,7 @@ use middle::free_region::FreeRegionMap;
 use middle::region::RegionMaps;
 use middle::resolve_lifetime;
 use middle::stability;
-use ty::subst::Substs;
+use ty::subst::{Kind, Substs};
 use traits;
 use ty::{self, TraitRef, Ty, TypeAndMut};
 use ty::{TyS, TypeVariants, Slice};
@@ -55,7 +55,7 @@ pub struct CtxtArenas<'tcx> {
     // internings
     type_: TypedArena<TyS<'tcx>>,
     type_list: TypedArena<Vec<Ty<'tcx>>>,
-    substs: TypedArena<Substs<'tcx>>,
+    substs: TypedArena<Vec<Kind<'tcx>>>,
     bare_fn: TypedArena<BareFnTy<'tcx>>,
     region: TypedArena<Region>,
     stability: TypedArena<attr::Stability>,
@@ -824,7 +824,7 @@ impl<'a, 'tcx> Lift<'tcx> for Ty<'a> {
 impl<'a, 'tcx> Lift<'tcx> for &'a Substs<'a> {
     type Lifted = &'tcx Substs<'tcx>;
     fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Substs<'tcx>> {
-        if let Some(&Interned(substs)) = tcx.interners.substs.borrow().get(*self) {
+        if let Some(&Interned(substs)) = tcx.interners.substs.borrow().get(&self[..]) {
             if *self as *const _ == substs as *const _ {
                 return Some(substs);
             }
@@ -1097,9 +1097,9 @@ impl<'tcx: 'lcx, 'lcx> Borrow<[Ty<'lcx>]> for Interned<'tcx, Slice<Ty<'tcx>>> {
     }
 }
 
-impl<'tcx: 'lcx, 'lcx> Borrow<Substs<'lcx>> for Interned<'tcx, Substs<'tcx>> {
-    fn borrow<'a>(&'a self) -> &'a Substs<'lcx> {
-        self.0
+impl<'tcx: 'lcx, 'lcx> Borrow<[Kind<'lcx>]> for Interned<'tcx, Substs<'tcx>> {
+    fn borrow<'a>(&'a self) -> &'a [Kind<'lcx>] {
+        &self.0[..]
     }
 }
 
@@ -1189,9 +1189,6 @@ fn keep_local<'tcx, T: ty::TypeFoldable<'tcx>>(x: &T) -> bool {
 }
 
 direct_interners!('tcx,
-    substs: mk_substs(|substs: &Substs| {
-        substs.params().iter().any(keep_local)
-    }) -> Substs<'tcx>,
     bare_fn: mk_bare_fn(|fty: &BareFnTy| {
         keep_local(&fty.sig)
     }) -> BareFnTy<'tcx>,
@@ -1209,6 +1206,12 @@ intern_method!('tcx,
     }, keep_local) -> Slice<Ty<'tcx>>
 );
 
+intern_method!('tcx,
+    substs: mk_substs(Vec<Kind<'tcx>>, Deref::deref, |xs: &[Kind]| -> &Slice<Kind> {
+        unsafe { mem::transmute(xs) }
+    }, keep_local) -> Slice<Kind<'tcx>>
+);
+
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Create an unsafe fn ty based on a safe fn ty.
     pub fn safe_to_unsafe_fn_ty(self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 6db82b86207..d1fa2128842 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -34,7 +34,7 @@ use util::nodemap::FnvHashMap;
 
 use serialize::{self, Encodable, Encoder};
 use std::borrow::Cow;
-use std::cell::Cell;
+use std::cell::{Cell, RefCell};
 use std::hash::{Hash, Hasher};
 use std::iter;
 use std::ops::Deref;
@@ -521,7 +521,7 @@ pub type Ty<'tcx> = &'tcx TyS<'tcx>;
 impl<'tcx> serialize::UseSpecializedEncodable for Ty<'tcx> {}
 impl<'tcx> serialize::UseSpecializedDecodable for Ty<'tcx> {}
 
-/// A wrapper for slices with the additioanl invariant
+/// A wrapper for slices with the additional invariant
 /// that the slice is interned and no other slice with
 /// the same contents can exist in the same context.
 /// This means we can use pointer + length for both
@@ -1220,6 +1220,12 @@ pub struct ParameterEnvironment<'tcx> {
     /// regions don't have this implicit scope and instead introduce
     /// relationships in the environment.
     pub free_id_outlive: CodeExtent,
+
+    /// A cache for `moves_by_default`.
+    pub is_copy_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
+
+    /// A cache for `type_is_sized`
+    pub is_sized_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
 }
 
 impl<'a, 'tcx> ParameterEnvironment<'tcx> {
@@ -1232,6 +1238,8 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
             implicit_region_bound: self.implicit_region_bound,
             caller_bounds: caller_bounds,
             free_id_outlive: self.free_id_outlive,
+            is_copy_cache: RefCell::new(FnvHashMap()),
+            is_sized_cache: RefCell::new(FnvHashMap()),
         }
     }
 
@@ -2773,7 +2781,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             free_substs: Substs::empty(self),
             caller_bounds: Vec::new(),
             implicit_region_bound: self.mk_region(ty::ReEmpty),
-            free_id_outlive: free_id_outlive
+            free_id_outlive: free_id_outlive,
+            is_copy_cache: RefCell::new(FnvHashMap()),
+            is_sized_cache: RefCell::new(FnvHashMap()),
         }
     }
 
@@ -2844,6 +2854,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             implicit_region_bound: tcx.mk_region(ty::ReScope(free_id_outlive)),
             caller_bounds: predicates,
             free_id_outlive: free_id_outlive,
+            is_copy_cache: RefCell::new(FnvHashMap()),
+            is_sized_cache: RefCell::new(FnvHashMap()),
         };
 
         let cause = traits::ObligationCause::misc(span, free_id_outlive.node_id(&self.region_maps));
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index abd5cb51f39..5948e02620e 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -901,23 +901,6 @@ impl<'tcx> TypeFoldable<'tcx> for ty::ClosureUpvar<'tcx> {
     }
 }
 
-impl<'tcx> TypeFoldable<'tcx> for ty::ParameterEnvironment<'tcx> {
-    fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        ty::ParameterEnvironment {
-            free_substs: self.free_substs.fold_with(folder),
-            implicit_region_bound: self.implicit_region_bound.fold_with(folder),
-            caller_bounds: self.caller_bounds.fold_with(folder),
-            free_id_outlive: self.free_id_outlive,
-        }
-    }
-
-    fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.free_substs.visit_with(visitor) ||
-            self.implicit_region_bound.visit_with(visitor) ||
-            self.caller_bounds.visit_with(visitor)
-    }
-}
-
 impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::error::ExpectedFound<T> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
         ty::error::ExpectedFound {
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index 6911d217426..7d7bbd93122 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -11,7 +11,7 @@
 // Type substitutions.
 
 use hir::def_id::DefId;
-use ty::{self, Ty, TyCtxt};
+use ty::{self, Slice, Ty, TyCtxt};
 use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
 
 use serialize::{self, Encodable, Encoder, Decodable, Decoder};
@@ -161,26 +161,19 @@ impl<'tcx> Decodable for Kind<'tcx> {
 }
 
 /// A substitution mapping type/region parameters to new values.
-#[derive(Clone, PartialEq, Eq, Debug, Hash, RustcEncodable, RustcDecodable)]
-pub struct Substs<'tcx> {
-    params: Vec<Kind<'tcx>>
-}
+pub type Substs<'tcx> = Slice<Kind<'tcx>>;
 
 impl<'a, 'gcx, 'tcx> Substs<'tcx> {
     pub fn new<I>(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I)
                   -> &'tcx Substs<'tcx>
     where I: IntoIterator<Item=Kind<'tcx>> {
-        tcx.mk_substs(Substs {
-            params: params.into_iter().collect()
-        })
+        tcx.mk_substs(params.into_iter().collect())
     }
 
     pub fn maybe_new<I, E>(tcx: TyCtxt<'a, 'gcx, 'tcx>, params: I)
                            -> Result<&'tcx Substs<'tcx>, E>
     where I: IntoIterator<Item=Result<Kind<'tcx>, E>> {
-        Ok(tcx.mk_substs(Substs {
-            params: params.into_iter().collect::<Result<_, _>>()?
-        }))
+        Ok(Substs::new(tcx, params.into_iter().collect::<Result<Vec<_>, _>>()?))
     }
 
     pub fn new_trait(tcx: TyCtxt<'a, 'gcx, 'tcx>,
@@ -193,7 +186,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
     }
 
     pub fn empty(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx Substs<'tcx> {
-        Substs::new(tcx, vec![])
+        Substs::new(tcx, iter::empty())
     }
 
     /// Creates a Substs for generic parameter definitions,
@@ -206,82 +199,82 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
                             mut mk_region: FR,
                             mut mk_type: FT)
                             -> &'tcx Substs<'tcx>
-    where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region,
-          FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> {
+    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
+          FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
         let defs = tcx.lookup_generics(def_id);
-        let mut substs = Substs {
-            params: Vec::with_capacity(defs.count())
-        };
+        let mut substs = Vec::with_capacity(defs.count());
 
-        substs.fill_item(tcx, defs, &mut mk_region, &mut mk_type);
+        Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type);
 
-        tcx.mk_substs(substs)
+        Substs::new(tcx, substs)
     }
 
-    fn fill_item<FR, FT>(&mut self,
+    fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
                          tcx: TyCtxt<'a, 'gcx, 'tcx>,
                          defs: &ty::Generics<'tcx>,
                          mk_region: &mut FR,
                          mk_type: &mut FT)
-    where FR: FnMut(&ty::RegionParameterDef, &Substs<'tcx>) -> &'tcx ty::Region,
-          FT: FnMut(&ty::TypeParameterDef<'tcx>, &Substs<'tcx>) -> Ty<'tcx> {
+    where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
+          FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
+
         if let Some(def_id) = defs.parent {
             let parent_defs = tcx.lookup_generics(def_id);
-            self.fill_item(tcx, parent_defs, mk_region, mk_type);
+            Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type);
         }
 
         // Handle Self first, before all regions.
         let mut types = defs.types.iter();
         if defs.parent.is_none() && defs.has_self {
             let def = types.next().unwrap();
-            let ty = mk_type(def, self);
-            assert_eq!(def.index as usize, self.params.len());
-            self.params.push(Kind::from(ty));
+            let ty = mk_type(def, substs);
+            assert_eq!(def.index as usize, substs.len());
+            substs.push(Kind::from(ty));
         }
 
         for def in &defs.regions {
-            let region = mk_region(def, self);
-            assert_eq!(def.index as usize, self.params.len());
-            self.params.push(Kind::from(region));
+            let region = mk_region(def, substs);
+            assert_eq!(def.index as usize, substs.len());
+            substs.push(Kind::from(region));
         }
 
         for def in types {
-            let ty = mk_type(def, self);
-            assert_eq!(def.index as usize, self.params.len());
-            self.params.push(Kind::from(ty));
+            let ty = mk_type(def, substs);
+            assert_eq!(def.index as usize, substs.len());
+            substs.push(Kind::from(ty));
         }
     }
 
     pub fn is_noop(&self) -> bool {
-        self.params.is_empty()
+        self.is_empty()
     }
 
     #[inline]
     pub fn params(&self) -> &[Kind<'tcx>] {
-        &self.params
+        // FIXME (dikaiosune) this should be removed, and corresponding compilation errors fixed
+        self
     }
 
     #[inline]
     pub fn types(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
-        self.params.iter().filter_map(|k| k.as_type())
+        self.iter().filter_map(|k| k.as_type())
     }
 
     #[inline]
     pub fn regions(&'a self) -> impl DoubleEndedIterator<Item=&'tcx ty::Region> + 'a {
-        self.params.iter().filter_map(|k| k.as_region())
+        self.iter().filter_map(|k| k.as_region())
     }
 
     #[inline]
     pub fn type_at(&self, i: usize) -> Ty<'tcx> {
-        self.params[i].as_type().unwrap_or_else(|| {
-            bug!("expected type for param #{} in {:?}", i, self.params);
+        self[i].as_type().unwrap_or_else(|| {
+            bug!("expected type for param #{} in {:?}", i, self);
         })
     }
 
     #[inline]
     pub fn region_at(&self, i: usize) -> &'tcx ty::Region {
-        self.params[i].as_region().unwrap_or_else(|| {
-            bug!("expected region for param #{} in {:?}", i, self.params);
+        self[i].as_region().unwrap_or_else(|| {
+            bug!("expected region for param #{} in {:?}", i, self);
         })
     }
 
@@ -305,19 +298,14 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> {
                        target_substs: &Substs<'tcx>)
                        -> &'tcx Substs<'tcx> {
         let defs = tcx.lookup_generics(source_ancestor);
-        tcx.mk_substs(Substs {
-            params: target_substs.params.iter()
-                .chain(&self.params[defs.own_count()..]).cloned().collect()
-        })
+        Substs::new(tcx, target_substs.iter().chain(&self[defs.own_count()..]).cloned())
     }
 }
 
 impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
     fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
-        let params = self.params.iter().map(|k| k.fold_with(folder)).collect();
-        folder.tcx().mk_substs(Substs {
-            params: params
-        })
+        let params = self.iter().map(|k| k.fold_with(folder)).collect();
+        folder.tcx().mk_substs(params)
     }
 
     fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
@@ -325,7 +313,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx Substs<'tcx> {
     }
 
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
-        self.params.visit_with(visitor)
+        self.iter().any(|t| t.visit_with(visitor))
     }
 }
 
@@ -340,19 +328,19 @@ impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Substs<'tcx> {}
 
 pub trait Subst<'tcx> : Sized {
     fn subst<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                      substs: &Substs<'tcx>) -> Self {
+                      substs: &[Kind<'tcx>]) -> Self {
         self.subst_spanned(tcx, substs, None)
     }
 
     fn subst_spanned<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                               substs: &Substs<'tcx>,
+                               substs: &[Kind<'tcx>],
                                span: Option<Span>)
                                -> Self;
 }
 
 impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T {
     fn subst_spanned<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                               substs: &Substs<'tcx>,
+                               substs: &[Kind<'tcx>],
                                span: Option<Span>)
                                -> T
     {
@@ -371,7 +359,7 @@ impl<'tcx, T:TypeFoldable<'tcx>> Subst<'tcx> for T {
 
 struct SubstFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'gcx, 'tcx>,
-    substs: &'a Substs<'tcx>,
+    substs: &'a [Kind<'tcx>],
 
     // The location for which the substitution is performed, if available.
     span: Option<Span>,
@@ -404,7 +392,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
         // the specialized routine `ty::replace_late_regions()`.
         match *r {
             ty::ReEarlyBound(data) => {
-                let r = self.substs.params.get(data.index as usize)
+                let r = self.substs.get(data.index as usize)
                             .and_then(|k| k.as_region());
                 match r {
                     Some(r) => {
@@ -461,7 +449,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for SubstFolder<'a, 'gcx, 'tcx> {
 impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
     fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> {
         // Look up the type in the substitutions. It really should be in there.
-        let opt_ty = self.substs.params.get(p.idx as usize)
+        let opt_ty = self.substs.get(p.idx as usize)
                          .and_then(|k| k.as_type());
         let ty = match opt_ty {
             Some(t) => t,
@@ -475,7 +463,7 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> {
                     source_ty,
                     p.idx,
                     self.root_ty,
-                    self.substs.params);
+                    self.substs);
             }
         };
 
@@ -552,7 +540,7 @@ impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> {
                        -> ty::TraitRef<'tcx> {
         let defs = tcx.lookup_generics(trait_id);
 
-        let params = substs.params[..defs.own_count()].iter().cloned();
+        let params = substs[..defs.own_count()].iter().cloned();
         ty::TraitRef {
             def_id: trait_id,
             substs: Substs::new(tcx, params)
@@ -567,7 +555,7 @@ impl<'a, 'gcx, 'tcx> ty::ExistentialTraitRef<'tcx> {
         // Assert there is a Self.
         trait_ref.substs.type_at(0);
 
-        let params = trait_ref.substs.params[1..].iter().cloned();
+        let params = trait_ref.substs[1..].iter().cloned();
         ty::ExistentialTraitRef {
             def_id: trait_ref.def_id,
             substs: Substs::new(tcx, params)
@@ -587,7 +575,7 @@ impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> {
         assert!(!self_ty.has_escaping_regions());
 
         self.map_bound(|trait_ref| {
-            let params = trait_ref.substs.params.iter().cloned();
+            let params = trait_ref.substs.iter().cloned();
             let params = iter::once(Kind::from(self_ty)).chain(params);
             ty::TraitRef {
                 def_id: trait_ref.def_id,
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index c9ab577a992..5b0f43e3cf1 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -20,9 +20,11 @@ use ty::{Disr, ParameterEnvironment};
 use ty::fold::TypeVisitor;
 use ty::layout::{Layout, LayoutError};
 use ty::TypeVariants::*;
+use util::nodemap::FnvHashMap;
 
 use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
 
+use std::cell::RefCell;
 use std::cmp;
 use std::hash::{Hash, Hasher};
 use std::collections::hash_map::DefaultHasher;
@@ -579,11 +581,24 @@ impl<'a, 'gcx, 'tcx, H: Hasher> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tc
 impl<'a, 'tcx> ty::TyS<'tcx> {
     fn impls_bound(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
                    param_env: &ParameterEnvironment<'tcx>,
-                   bound: ty::BuiltinBound, span: Span) -> bool
+                   bound: ty::BuiltinBound,
+                   cache: &RefCell<FnvHashMap<Ty<'tcx>, bool>>,
+                   span: Span) -> bool
     {
-        tcx.infer_ctxt(None, Some(param_env.clone()), Reveal::ExactMatch).enter(|infcx| {
-            traits::type_known_to_meet_builtin_bound(&infcx, self, bound, span)
-        })
+        if self.has_param_types() || self.has_self_ty() {
+            if let Some(result) = cache.borrow().get(self) {
+                return *result;
+            }
+        }
+        let result =
+            tcx.infer_ctxt(None, Some(param_env.clone()), Reveal::ExactMatch)
+            .enter(|infcx| {
+                traits::type_known_to_meet_builtin_bound(&infcx, self, bound, span)
+            });
+        if self.has_param_types() || self.has_self_ty() {
+            cache.borrow_mut().insert(self, result);
+        }
+        return result;
     }
 
     // FIXME (@jroesch): I made this public to use it, not sure if should be private
@@ -610,7 +625,9 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
             TyArray(..) | TySlice(..) | TyTrait(..) | TyTuple(..) |
             TyClosure(..) | TyAdt(..) | TyAnon(..) |
             TyProjection(..) | TyParam(..) | TyInfer(..) | TyError => None
-        }.unwrap_or_else(|| !self.impls_bound(tcx, param_env, ty::BoundCopy, span));
+        }.unwrap_or_else(|| {
+            !self.impls_bound(tcx, param_env, ty::BoundCopy, &param_env.is_copy_cache, span)
+        });
 
         if !self.has_param_types() && !self.has_self_ty() {
             self.flags.set(self.flags.get() | if result {
@@ -650,7 +667,9 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
 
             TyAdt(..) | TyProjection(..) | TyParam(..) |
             TyInfer(..) | TyAnon(..) | TyError => None
-        }.unwrap_or_else(|| self.impls_bound(tcx, param_env, ty::BoundSized, span));
+        }.unwrap_or_else(|| {
+            self.impls_bound(tcx, param_env, ty::BoundSized, &param_env.is_sized_cache, span)
+        });
 
         if !self.has_param_types() && !self.has_self_ty() {
             self.flags.set(self.flags.get() | if result {
diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs
index c0f358ca801..e6d1982d31c 100644
--- a/src/librustc_back/lib.rs
+++ b/src/librustc_back/lib.rs
@@ -37,7 +37,7 @@
 #![feature(rustc_private)]
 #![feature(staged_api)]
 #![feature(step_by)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![cfg_attr(test, feature(test, rand))]
 
 extern crate syntax;
diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs
index 91be50d11f9..f6260527039 100644
--- a/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs
+++ b/src/librustc_borrowck/borrowck/mir/dataflow/graphviz.rs
@@ -12,6 +12,8 @@
 
 use syntax::ast::NodeId;
 use rustc::mir::repr::{BasicBlock, Mir};
+use rustc_data_structures::bitslice::bits_to_string;
+use rustc_data_structures::indexed_set::{IdxSet};
 use rustc_data_structures::indexed_vec::Idx;
 
 use dot;
@@ -27,8 +29,6 @@ use std::path::Path;
 
 use super::super::MoveDataParamEnv;
 use super::super::MirBorrowckCtxtPreDataflow;
-use bitslice::bits_to_string;
-use indexed_set::{IdxSet};
 use super::{BitDenotation, DataflowState};
 
 impl<O: BitDenotation> DataflowState<O> {
diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs
index 55dda8eda3a..dce167975cf 100644
--- a/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs
+++ b/src/librustc_borrowck/borrowck/mir/dataflow/impls.rs
@@ -10,6 +10,9 @@
 
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::{self, Mir, Location};
+use rustc_data_structures::bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep.
+use rustc_data_structures::bitslice::{BitwiseOperator};
+use rustc_data_structures::indexed_set::{IdxSet};
 use rustc_data_structures::indexed_vec::Idx;
 
 use super::super::gather_moves::{MoveOutIndex, MovePathIndex};
@@ -21,10 +24,6 @@ use super::super::on_lookup_result_bits;
 
 use super::{BitDenotation, BlockSets, DataflowOperator};
 
-use bitslice::BitSlice; // adds set_bit/get_bit to &[usize] bitvector rep.
-use bitslice::{BitwiseOperator};
-use indexed_set::{IdxSet};
-
 // Dataflow analyses are built upon some interpretation of the
 // bitvectors attached to each basic block, represented via a
 // zero-sized structure.
diff --git a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs
index a9b4de45096..0c510e95b67 100644
--- a/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs
+++ b/src/librustc_borrowck/borrowck/mir/dataflow/mod.rs
@@ -8,7 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use rustc_data_structures::indexed_set::{IdxSet, IdxSetBuf};
 use rustc_data_structures::indexed_vec::Idx;
+use rustc_data_structures::bitslice::{bitwise, BitwiseOperator};
 
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::{self, Mir};
@@ -22,9 +24,6 @@ use std::usize;
 use super::MirBorrowckCtxtPreDataflow;
 use super::MoveDataParamEnv;
 
-use bitslice::{bitwise, BitwiseOperator};
-use indexed_set::{IdxSet, IdxSetBuf};
-
 pub use self::sanity_check::sanity_check_via_rustc_peek;
 pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
 pub use self::impls::{DefinitelyInitializedLvals, MovingOutStatements};
diff --git a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
index 188fce467be..25986b85f7b 100644
--- a/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
+++ b/src/librustc_borrowck/borrowck/mir/elaborate_drops.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use indexed_set::IdxSetBuf;
 use super::gather_moves::{MoveData, MovePathIndex, LookupResult};
 use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
 use super::dataflow::{DataflowResults};
@@ -23,6 +22,7 @@ use rustc::mir::transform::{Pass, MirPass, MirSource};
 use rustc::middle::const_val::ConstVal;
 use rustc::middle::lang_items;
 use rustc::util::nodemap::FnvHashMap;
+use rustc_data_structures::indexed_set::IdxSetBuf;
 use rustc_data_structures::indexed_vec::Idx;
 use syntax_pos::Span;
 
diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs
index 22b590592fe..da899714e93 100644
--- a/src/librustc_borrowck/lib.rs
+++ b/src/librustc_borrowck/lib.rs
@@ -26,7 +26,7 @@
 #![feature(staged_api)]
 #![feature(associated_consts)]
 #![feature(nonzero)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
 extern crate syntax_pos;
@@ -50,8 +50,6 @@ pub use borrowck::{AnalysisData, BorrowckCtxt, ElaborateDrops};
 pub mod diagnostics;
 
 mod borrowck;
-mod bitslice;
-mod indexed_set;
 
 pub mod graphviz;
 
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index d876b4b6fec..81dd642de5d 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -732,6 +732,10 @@ pub fn eval_const_expr_partial<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
               hir::BiBitOr => a | b,
               hir::BiEq => a == b,
               hir::BiNe => a != b,
+              hir::BiLt => a < b,
+              hir::BiLe => a <= b,
+              hir::BiGe => a >= b,
+              hir::BiGt => a > b,
               _ => signal!(e, InvalidOpForBools(op.node)),
              })
           }
diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs
index f926fef065e..7b40269ba56 100644
--- a/src/librustc_const_eval/lib.rs
+++ b/src/librustc_const_eval/lib.rs
@@ -27,7 +27,7 @@
 #![feature(staged_api)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(slice_patterns)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 
diff --git a/src/librustc_const_math/lib.rs b/src/librustc_const_math/lib.rs
index 741dd4107e0..31fccb41ce5 100644
--- a/src/librustc_const_math/lib.rs
+++ b/src/librustc_const_math/lib.rs
@@ -25,7 +25,7 @@
 
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/librustc_borrowck/bitslice.rs b/src/librustc_data_structures/bitslice.rs
index 80fa86a007e..ba53578e579 100644
--- a/src/librustc_borrowck/bitslice.rs
+++ b/src/librustc_data_structures/bitslice.rs
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// FIXME: move this to `rustc_data_structures` and potentially merge
-// with `bitvec` there.
+// FIXME: merge with `bitvec`
 
 use std::mem;
 
diff --git a/src/librustc_borrowck/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs
index 671aff97d20..2e9e054e97e 100644
--- a/src/librustc_borrowck/indexed_set.rs
+++ b/src/librustc_data_structures/indexed_set.rs
@@ -8,16 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// FIXME: move this to `rustc_data_structures`
-
 use std::fmt;
 use std::marker::PhantomData;
 use std::mem;
 use std::ops::{Deref, DerefMut, Range};
 use bitslice::{BitSlice, Word};
 use bitslice::{bitwise, Union, Subtract};
-
-use rustc_data_structures::indexed_vec::Idx;
+use indexed_vec::Idx;
 
 /// Represents a set (or packed family of sets), of some element type
 /// E, where each E is identified by some unique index type `T`.
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index e7da18cef10..c8f4d766153 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -41,9 +41,11 @@ extern crate serialize as rustc_serialize; // used by deriving
 #[cfg(unix)]
 extern crate libc;
 
+pub mod bitslice;
 pub mod bitvec;
 pub mod graph;
 pub mod ivar;
+pub mod indexed_set;
 pub mod indexed_vec;
 pub mod obligation_forest;
 pub mod snapshot_map;
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index ea42f7ba93e..e8ab2f3a240 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -649,7 +649,7 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
     let resolver_arenas = Resolver::arenas();
     let mut resolver =
         Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas);
-    syntax_ext::register_builtins(&mut resolver, sess.features.borrow().quote);
+    syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote);
 
     krate = time(time_passes, "expansion", || {
         // Windows dlls do not have rpaths, so they don't know how to find their
@@ -686,11 +686,17 @@ pub fn phase_2_configure_and_expand<'a, F>(sess: &Session,
             ..syntax::ext::expand::ExpansionConfig::default(crate_name.to_string())
         };
         let mut ecx = ExtCtxt::new(&sess.parse_sess, krate.config.clone(), cfg, &mut resolver);
-        let ret = syntax::ext::expand::expand_crate(&mut ecx, syntax_exts, krate);
+        let err_count = ecx.parse_sess.span_diagnostic.err_count();
+
+        let krate = ecx.monotonic_expander().expand_crate(krate);
+
+        if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count {
+            ecx.parse_sess.span_diagnostic.abort_if_errors();
+        }
         if cfg!(windows) {
             env::set_var("PATH", &old_path);
         }
-        ret
+        krate
     });
 
     krate.exported_macros = mem::replace(&mut resolver.exported_macros, Vec::new());
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 492165e2f2a..6972bdac5e1 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -31,7 +31,7 @@
 #![feature(rustc_private)]
 #![feature(set_stdio)]
 #![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 
 extern crate arena;
 extern crate flate;
@@ -729,6 +729,10 @@ pub fn version(binary: &str, matches: &getopts::Matches) {
         println!("commit-date: {}", unw(commit_date_str()));
         println!("host: {}", config::host_triple());
         println!("release: {}", unw(release_str()));
+        unsafe {
+            println!("LLVM version: {}.{}",
+                     llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
+        }
     }
 }
 
@@ -1110,7 +1114,7 @@ pub fn monitor<F: FnOnce() + Send + 'static>(f: F) {
                              errors::Level::Note);
             }
 
-            println!("{}", str::from_utf8(&data.lock().unwrap()).unwrap());
+            writeln!(io::stderr(), "{}", str::from_utf8(&data.lock().unwrap()).unwrap()).unwrap();
         }
 
         exit_on_err();
diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs
index bc599a82076..af8ac81b4fb 100644
--- a/src/librustc_errors/lib.rs
+++ b/src/librustc_errors/lib.rs
@@ -21,7 +21,7 @@
 #![allow(unused_attributes)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![feature(range_contains)]
 #![feature(libc)]
 #![feature(unicode)]
diff --git a/src/librustc_incremental/calculate_svh/hasher.rs b/src/librustc_incremental/calculate_svh/hasher.rs
new file mode 100644
index 00000000000..28db39d667c
--- /dev/null
+++ b/src/librustc_incremental/calculate_svh/hasher.rs
@@ -0,0 +1,46 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::hash::Hasher;
+use std::collections::hash_map::DefaultHasher;
+
+#[derive(Debug)]
+pub struct IchHasher {
+    // FIXME: this should use SHA1, not DefaultHasher. DefaultHasher is not
+    // built to avoid collisions.
+    state: DefaultHasher,
+    bytes_hashed: u64,
+}
+
+impl IchHasher {
+    pub fn new() -> IchHasher {
+        IchHasher {
+            state: DefaultHasher::new(),
+            bytes_hashed: 0
+        }
+    }
+
+    pub fn bytes_hashed(&self) -> u64 {
+        self.bytes_hashed
+    }
+}
+
+impl Hasher for IchHasher {
+    #[inline]
+    fn finish(&self) -> u64 {
+        self.state.finish()
+    }
+
+    #[inline]
+    fn write(&mut self, bytes: &[u8]) {
+        self.state.write(bytes);
+        self.bytes_hashed += bytes.len() as u64;
+    }
+}
diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs
index a22b51ac044..12627e02deb 100644
--- a/src/librustc_incremental/calculate_svh/mod.rs
+++ b/src/librustc_incremental/calculate_svh/mod.rs
@@ -30,7 +30,6 @@
 use syntax::ast;
 use std::cell::RefCell;
 use std::hash::{Hash, Hasher};
-use std::collections::hash_map::DefaultHasher;
 use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
@@ -43,10 +42,12 @@ use rustc::session::config::DebugInfoLevel::NoDebugInfo;
 use self::def_path_hash::DefPathHashes;
 use self::svh_visitor::StrictVersionHashVisitor;
 use self::caching_codemap_view::CachingCodemapView;
+use self::hasher::IchHasher;
 
 mod def_path_hash;
 mod svh_visitor;
 mod caching_codemap_view;
+mod hasher;
 
 pub struct IncrementalHashesMap {
     hashes: FnvHashMap<DepNode<DefId>, u64>,
@@ -74,6 +75,10 @@ impl IncrementalHashesMap {
     pub fn iter<'a>(&'a self) -> ::std::collections::hash_map::Iter<'a, DepNode<DefId>, u64> {
         self.hashes.iter()
     }
+
+    pub fn len(&self) -> usize {
+        self.hashes.len()
+    }
 }
 
 impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
@@ -102,6 +107,9 @@ pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
                                  |v| visit::walk_crate(v, krate));
         krate.visit_all_items(&mut visitor);
     });
+
+    tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
+
     record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
     visitor.hashes
 }
@@ -127,9 +135,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
     {
         assert!(def_id.is_local());
         debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
-        // FIXME: this should use SHA1, not DefaultHasher. DefaultHasher is not
-        // built to avoid collisions.
-        let mut state = DefaultHasher::new();
+        let mut state = IchHasher::new();
         walk_op(&mut StrictVersionHashVisitor::new(&mut state,
                                                    self.tcx,
                                                    &mut self.def_path_hashes,
@@ -138,12 +144,16 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
         let item_hash = state.finish();
         self.hashes.insert(DepNode::Hir(def_id), item_hash);
         debug!("calculate_item_hash: def_id={:?} hash={:?}", def_id, item_hash);
+
+        let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
+                           state.bytes_hashed();
+        self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
     }
 
     fn compute_crate_hash(&mut self) {
         let krate = self.tcx.map.krate();
 
-        let mut crate_state = DefaultHasher::new();
+        let mut crate_state = IchHasher::new();
 
         let crate_disambiguator = self.tcx.sess.local_crate_disambiguator();
         "crate_disambiguator".hash(&mut crate_state);
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
index 3df68ac583d..584e5598b9f 100644
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ b/src/librustc_incremental/calculate_svh/svh_visitor.rs
@@ -31,10 +31,10 @@ use rustc::hir::intravisit as visit;
 use rustc::ty::TyCtxt;
 use rustc_data_structures::fnv;
 use std::hash::Hash;
-use std::collections::hash_map::DefaultHasher;
 
 use super::def_path_hash::DefPathHashes;
 use super::caching_codemap_view::CachingCodemapView;
+use super::hasher::IchHasher;
 
 const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
     "cfg",
@@ -48,7 +48,7 @@ const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
 
 pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
     pub tcx: TyCtxt<'hash, 'tcx, 'tcx>,
-    pub st: &'a mut DefaultHasher,
+    pub st: &'a mut IchHasher,
     // collect a deterministic hash of def-ids that we have seen
     def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
     hash_spans: bool,
@@ -56,7 +56,7 @@ pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
 }
 
 impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
-    pub fn new(st: &'a mut DefaultHasher,
+    pub fn new(st: &'a mut IchHasher,
                tcx: TyCtxt<'hash, 'tcx, 'tcx>,
                def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
                codemap: &'a mut CachingCodemapView<'tcx>,
diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs
index 2c1340e566d..67104e912f9 100644
--- a/src/librustc_incremental/lib.rs
+++ b/src/librustc_incremental/lib.rs
@@ -20,7 +20,7 @@
 #![cfg_attr(not(stage0), deny(warnings))]
 
 #![feature(dotdot_in_tuple_patterns)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![feature(rustc_private)]
 #![feature(staged_api)]
 #![feature(rand)]
diff --git a/src/librustc_lint/bad_style.rs b/src/librustc_lint/bad_style.rs
index 84d65308f95..fea3de59520 100644
--- a/src/librustc_lint/bad_style.rs
+++ b/src/librustc_lint/bad_style.rs
@@ -24,19 +24,21 @@ use rustc::hir::intravisit::FnKind;
 pub enum MethodLateContext {
     TraitDefaultImpl,
     TraitImpl,
-    PlainImpl
+    PlainImpl,
 }
 
 pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext {
     let def_id = cx.tcx.map.local_def_id(id);
     match cx.tcx.impl_or_trait_items.borrow().get(&def_id) {
         None => span_bug!(span, "missing method descriptor?!"),
-        Some(item) => match item.container() {
-            ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
-            ty::ImplContainer(cid) => {
-                match cx.tcx.impl_trait_ref(cid) {
-                    Some(_) => MethodLateContext::TraitImpl,
-                    None => MethodLateContext::PlainImpl
+        Some(item) => {
+            match item.container() {
+                ty::TraitContainer(..) => MethodLateContext::TraitDefaultImpl,
+                ty::ImplContainer(cid) => {
+                    match cx.tcx.impl_trait_ref(cid) {
+                        Some(_) => MethodLateContext::TraitImpl,
+                        None => MethodLateContext::PlainImpl,
+                    }
                 }
             }
         }
@@ -63,19 +65,20 @@ impl NonCamelCaseTypes {
 
             // start with a non-lowercase letter rather than non-uppercase
             // ones (some scripts don't have a concept of upper/lowercase)
-            !name.is_empty() &&
-                !name.chars().next().unwrap().is_lowercase() &&
-                !name.contains('_')
+            !name.is_empty() && !name.chars().next().unwrap().is_lowercase() && !name.contains('_')
         }
 
         fn to_camel_case(s: &str) -> String {
-            s.split('_').flat_map(|word| word.chars().enumerate().map(|(i, c)|
-                if i == 0 {
-                    c.to_uppercase().collect::<String>()
-                } else {
-                    c.to_lowercase().collect()
-                }
-            )).collect::<Vec<_>>().concat()
+            s.split('_')
+                .flat_map(|word| {
+                    word.chars().enumerate().map(|(i, c)| if i == 0 {
+                        c.to_uppercase().collect::<String>()
+                    } else {
+                        c.to_lowercase().collect()
+                    })
+                })
+                .collect::<Vec<_>>()
+                .concat()
         }
 
         let s = name.as_str();
@@ -83,9 +86,14 @@ impl NonCamelCaseTypes {
         if !is_camel_case(name) {
             let c = to_camel_case(&s);
             let m = if c.is_empty() {
-                format!("{} `{}` should have a camel case name such as `CamelCase`", sort, s)
+                format!("{} `{}` should have a camel case name such as `CamelCase`",
+                        sort,
+                        s)
             } else {
-                format!("{} `{}` should have a camel case name such as `{}`", sort, s, c)
+                format!("{} `{}` should have a camel case name such as `{}`",
+                        sort,
+                        s,
+                        c)
             };
             cx.span_lint(NON_CAMEL_CASE_TYPES, span, &m[..]);
         }
@@ -100,10 +108,14 @@ impl LintPass for NonCamelCaseTypes {
 
 impl LateLintPass for NonCamelCaseTypes {
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
-        let extern_repr_count = it.attrs.iter().filter(|attr| {
-            attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr).iter()
-                .any(|r| r == &attr::ReprExtern)
-        }).count();
+        let extern_repr_count = it.attrs
+            .iter()
+            .filter(|attr| {
+                attr::find_repr_attrs(cx.tcx.sess.diagnostic(), attr)
+                    .iter()
+                    .any(|r| r == &attr::ReprExtern)
+            })
+            .count();
         let has_extern_repr = extern_repr_count > 0;
 
         if has_extern_repr {
@@ -111,12 +123,10 @@ impl LateLintPass for NonCamelCaseTypes {
         }
 
         match it.node {
-            hir::ItemTy(..) | hir::ItemStruct(..) | hir::ItemUnion(..) => {
-                self.check_case(cx, "type", it.name, it.span)
-            }
-            hir::ItemTrait(..) => {
-                self.check_case(cx, "trait", it.name, it.span)
-            }
+            hir::ItemTy(..) |
+            hir::ItemStruct(..) |
+            hir::ItemUnion(..) => self.check_case(cx, "type", it.name, it.span),
+            hir::ItemTrait(..) => self.check_case(cx, "trait", it.name, it.span),
             hir::ItemEnum(ref enum_definition, _) => {
                 if has_extern_repr {
                     return;
@@ -126,7 +136,7 @@ impl LateLintPass for NonCamelCaseTypes {
                     self.check_case(cx, "variant", variant.node.name, variant.span);
                 }
             }
-            _ => ()
+            _ => (),
         }
     }
 
@@ -165,9 +175,7 @@ impl NonSnakeCase {
                 continue;
             }
             for ch in s.chars() {
-                if !buf.is_empty() && buf != "'"
-                                   && ch.is_uppercase()
-                                   && !last_upper {
+                if !buf.is_empty() && buf != "'" && ch.is_uppercase() && !last_upper {
                     words.push(buf);
                     buf = String::new();
                 }
@@ -205,10 +213,11 @@ impl NonSnakeCase {
             let sc = NonSnakeCase::to_snake_case(name);
             let msg = if sc != name {
                 format!("{} `{}` should have a snake case name such as `{}`",
-                        sort, name, sc)
+                        sort,
+                        name,
+                        sc)
             } else {
-                format!("{} `{}` should have a snake case name",
-                        sort, name)
+                format!("{} `{}` should have a snake case name", sort, name)
             };
             match span {
                 Some(span) => cx.span_lint(NON_SNAKE_CASE, span, &msg),
@@ -226,8 +235,10 @@ impl LintPass for NonSnakeCase {
 
 impl LateLintPass for NonSnakeCase {
     fn check_crate(&mut self, cx: &LateContext, cr: &hir::Crate) {
-        let attr_crate_name = cr.attrs.iter().find(|at| at.check_name("crate_name"))
-                                      .and_then(|at| at.value_str().map(|s| (at, s)));
+        let attr_crate_name = cr.attrs
+            .iter()
+            .find(|at| at.check_name("crate_name"))
+            .and_then(|at| at.value_str().map(|s| (at, s)));
         if let Some(ref name) = cx.tcx.sess.opts.crate_name {
             self.check_snake_case(cx, "crate", name, None);
         } else if let Some((attr, ref name)) = attr_crate_name {
@@ -235,22 +246,28 @@ impl LateLintPass for NonSnakeCase {
         }
     }
 
-    fn check_fn(&mut self, cx: &LateContext,
-                fk: FnKind, _: &hir::FnDecl,
-                _: &hir::Block, span: Span, id: ast::NodeId) {
+    fn check_fn(&mut self,
+                cx: &LateContext,
+                fk: FnKind,
+                _: &hir::FnDecl,
+                _: &hir::Block,
+                span: Span,
+                id: ast::NodeId) {
         match fk {
-            FnKind::Method(name, ..) => match method_context(cx, id, span) {
-                MethodLateContext::PlainImpl => {
-                    self.check_snake_case(cx, "method", &name.as_str(), Some(span))
-                },
-                MethodLateContext::TraitDefaultImpl => {
-                    self.check_snake_case(cx, "trait method", &name.as_str(), Some(span))
-                },
-                _ => (),
-            },
+            FnKind::Method(name, ..) => {
+                match method_context(cx, id, span) {
+                    MethodLateContext::PlainImpl => {
+                        self.check_snake_case(cx, "method", &name.as_str(), Some(span))
+                    }
+                    MethodLateContext::TraitDefaultImpl => {
+                        self.check_snake_case(cx, "trait method", &name.as_str(), Some(span))
+                    }
+                    _ => (),
+                }
+            }
             FnKind::ItemFn(name, ..) => {
                 self.check_snake_case(cx, "function", &name.as_str(), Some(span))
-            },
+            }
             FnKind::Closure(_) => (),
         }
     }
@@ -263,13 +280,17 @@ impl LateLintPass for NonSnakeCase {
 
     fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
         if let hir::MethodTraitItem(_, None) = trait_item.node {
-            self.check_snake_case(cx, "trait method", &trait_item.name.as_str(),
+            self.check_snake_case(cx,
+                                  "trait method",
+                                  &trait_item.name.as_str(),
                                   Some(trait_item.span));
         }
     }
 
     fn check_lifetime_def(&mut self, cx: &LateContext, t: &hir::LifetimeDef) {
-        self.check_snake_case(cx, "lifetime", &t.lifetime.name.as_str(),
+        self.check_snake_case(cx,
+                              "lifetime",
+                              &t.lifetime.name.as_str(),
                               Some(t.lifetime.span));
     }
 
@@ -282,8 +303,12 @@ impl LateLintPass for NonSnakeCase {
         }
     }
 
-    fn check_struct_def(&mut self, cx: &LateContext, s: &hir::VariantData,
-                        _: ast::Name, _: &hir::Generics, _: ast::NodeId) {
+    fn check_struct_def(&mut self,
+                        cx: &LateContext,
+                        s: &hir::VariantData,
+                        _: ast::Name,
+                        _: &hir::Generics,
+                        _: ast::NodeId) {
         for sf in s.fields() {
             self.check_snake_case(cx, "structure field", &sf.name.as_str(), Some(sf.span));
         }
@@ -306,13 +331,16 @@ impl NonUpperCaseGlobals {
         if s.chars().any(|c| c.is_lowercase()) {
             let uc = NonSnakeCase::to_snake_case(&s).to_uppercase();
             if uc != &s[..] {
-                cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
-                    &format!("{} `{}` should have an upper case name such as `{}`",
-                             sort, s, uc));
+                cx.span_lint(NON_UPPER_CASE_GLOBALS,
+                             span,
+                             &format!("{} `{}` should have an upper case name such as `{}`",
+                                      sort,
+                                      s,
+                                      uc));
             } else {
-                cx.span_lint(NON_UPPER_CASE_GLOBALS, span,
-                    &format!("{} `{}` should have an upper case name",
-                             sort, s));
+                cx.span_lint(NON_UPPER_CASE_GLOBALS,
+                             span,
+                             &format!("{} `{}` should have an upper case name", sort, s));
             }
         }
     }
@@ -327,9 +355,8 @@ impl LintPass for NonUpperCaseGlobals {
 impl LateLintPass for NonUpperCaseGlobals {
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         match it.node {
-            // only check static constants
-            hir::ItemStatic(_, hir::MutImmutable, _) => {
-                NonUpperCaseGlobals::check_upper_case(cx, "static constant", it.name, it.span);
+            hir::ItemStatic(..) => {
+                NonUpperCaseGlobals::check_upper_case(cx, "static variable", it.name, it.span);
             }
             hir::ItemConst(..) => {
                 NonUpperCaseGlobals::check_upper_case(cx, "constant", it.name, it.span);
@@ -341,8 +368,7 @@ impl LateLintPass for NonUpperCaseGlobals {
     fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) {
         match ti.node {
             hir::ConstTraitItem(..) => {
-                NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
-                                                      ti.name, ti.span);
+                NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span);
             }
             _ => {}
         }
@@ -351,8 +377,7 @@ impl LateLintPass for NonUpperCaseGlobals {
     fn check_impl_item(&mut self, cx: &LateContext, ii: &hir::ImplItem) {
         match ii.node {
             hir::ImplItemKind::Const(..) => {
-                NonUpperCaseGlobals::check_upper_case(cx, "associated constant",
-                                                      ii.name, ii.span);
+                NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ii.name, ii.span);
             }
             _ => {}
         }
@@ -363,8 +388,10 @@ impl LateLintPass for NonUpperCaseGlobals {
         if let PatKind::Path(None, ref path) = p.node {
             if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
                 if let Def::Const(..) = cx.tcx.expect_def(p.id) {
-                    NonUpperCaseGlobals::check_upper_case(cx, "constant in pattern",
-                                                          path.segments[0].name, path.span);
+                    NonUpperCaseGlobals::check_upper_case(cx,
+                                                          "constant in pattern",
+                                                          path.segments[0].name,
+                                                          path.span);
                 }
             }
         }
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index b610a924a33..3428ec8d4c9 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -37,15 +37,15 @@ use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::adjustment;
 use rustc::traits::{self, Reveal};
 use rustc::hir::map as hir_map;
-use util::nodemap::{NodeSet};
+use util::nodemap::NodeSet;
 use lint::{Level, LateContext, LintContext, LintArray, Lint};
 use lint::{LintPass, LateLintPass};
 
 use std::collections::HashSet;
 
-use syntax::{ast};
+use syntax::ast;
 use syntax::attr;
-use syntax_pos::{Span};
+use syntax_pos::Span;
 
 use rustc::hir::{self, PatKind};
 use rustc::hir::intravisit::FnKind;
@@ -75,7 +75,8 @@ impl LateLintPass for WhileTrue {
         if let hir::ExprWhile(ref cond, ..) = e.node {
             if let hir::ExprLit(ref lit) = cond.node {
                 if let ast::LitKind::Bool(true) = lit.node {
-                    cx.span_lint(WHILE_TRUE, e.span,
+                    cx.span_lint(WHILE_TRUE,
+                                 e.span,
                                  "denote infinite loops with loop { ... }");
                 }
             }
@@ -93,8 +94,7 @@ declare_lint! {
 pub struct BoxPointers;
 
 impl BoxPointers {
-    fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>,
-                                 span: Span, ty: Ty<'tcx>) {
+    fn check_heap_type<'a, 'tcx>(&self, cx: &LateContext<'a, 'tcx>, span: Span, ty: Ty<'tcx>) {
         for leaf_ty in ty.walk() {
             if let ty::TyBox(_) = leaf_ty.sty {
                 let m = format!("type uses owned (Box type) pointers: {}", ty);
@@ -117,10 +117,8 @@ impl LateLintPass for BoxPointers {
             hir::ItemTy(..) |
             hir::ItemEnum(..) |
             hir::ItemStruct(..) |
-            hir::ItemUnion(..) =>
-                self.check_heap_type(cx, it.span,
-                                     cx.tcx.node_id_to_type(it.id)),
-            _ => ()
+            hir::ItemUnion(..) => self.check_heap_type(cx, it.span, cx.tcx.node_id_to_type(it.id)),
+            _ => (),
         }
 
         // If it's a struct, we also have to check the fields' types
@@ -128,11 +126,12 @@ impl LateLintPass for BoxPointers {
             hir::ItemStruct(ref struct_def, _) |
             hir::ItemUnion(ref struct_def, _) => {
                 for struct_field in struct_def.fields() {
-                    self.check_heap_type(cx, struct_field.span,
+                    self.check_heap_type(cx,
+                                         struct_field.span,
                                          cx.tcx.node_id_to_type(struct_field.id));
                 }
             }
-            _ => ()
+            _ => (),
         }
     }
 
@@ -166,9 +165,11 @@ impl LateLintPass for NonShorthandFieldPatterns {
                 }
                 if let PatKind::Binding(_, ident, None) = fieldpat.node.pat.node {
                     if ident.node == fieldpat.node.name {
-                        cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span,
+                        cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS,
+                                     fieldpat.span,
                                      &format!("the `{}:` in this pattern is redundant and can \
-                                              be removed", ident.node))
+                                              be removed",
+                                              ident.node))
                     }
                 }
             }
@@ -203,27 +204,35 @@ impl LateLintPass for UnsafeCode {
 
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         match it.node {
-            hir::ItemTrait(hir::Unsafety::Unsafe, ..) =>
-                cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait"),
+            hir::ItemTrait(hir::Unsafety::Unsafe, ..) => {
+                cx.span_lint(UNSAFE_CODE, it.span, "declaration of an `unsafe` trait")
+            }
 
-            hir::ItemImpl(hir::Unsafety::Unsafe, ..) =>
-                cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait"),
+            hir::ItemImpl(hir::Unsafety::Unsafe, ..) => {
+                cx.span_lint(UNSAFE_CODE, it.span, "implementation of an `unsafe` trait")
+            }
 
             _ => return,
         }
     }
 
-    fn check_fn(&mut self, cx: &LateContext, fk: FnKind, _: &hir::FnDecl,
-                _: &hir::Block, span: Span, _: ast::NodeId) {
+    fn check_fn(&mut self,
+                cx: &LateContext,
+                fk: FnKind,
+                _: &hir::FnDecl,
+                _: &hir::Block,
+                span: Span,
+                _: ast::NodeId) {
         match fk {
-            FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) =>
-                cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function"),
+            FnKind::ItemFn(_, _, hir::Unsafety::Unsafe, ..) => {
+                cx.span_lint(UNSAFE_CODE, span, "declaration of an `unsafe` function")
+            }
 
             FnKind::Method(_, sig, ..) => {
                 if sig.unsafety == hir::Unsafety::Unsafe {
                     cx.span_lint(UNSAFE_CODE, span, "implementation of an `unsafe` method")
                 }
-            },
+            }
 
             _ => (),
         }
@@ -232,7 +241,8 @@ impl LateLintPass for UnsafeCode {
     fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
         if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
             if sig.unsafety == hir::Unsafety::Unsafe {
-                cx.span_lint(UNSAFE_CODE, trait_item.span,
+                cx.span_lint(UNSAFE_CODE,
+                             trait_item.span,
                              "declaration of an `unsafe` method")
             }
         }
@@ -263,9 +273,9 @@ pub struct MissingDoc {
 impl MissingDoc {
     pub fn new() -> MissingDoc {
         MissingDoc {
-            struct_def_stack: vec!(),
+            struct_def_stack: vec![],
             in_variant: false,
-            doc_hidden_stack: vec!(false),
+            doc_hidden_stack: vec![false],
             private_traits: HashSet::new(),
         }
     }
@@ -275,11 +285,11 @@ impl MissingDoc {
     }
 
     fn check_missing_docs_attrs(&self,
-                               cx: &LateContext,
-                               id: Option<ast::NodeId>,
-                               attrs: &[ast::Attribute],
-                               sp: Span,
-                               desc: &'static str) {
+                                cx: &LateContext,
+                                id: Option<ast::NodeId>,
+                                attrs: &[ast::Attribute],
+                                sp: Span,
+                                desc: &'static str) {
         // If we're building a test harness, then warning about
         // documentation is probably not really relevant right now.
         if cx.sess().opts.test {
@@ -302,7 +312,8 @@ impl MissingDoc {
 
         let has_doc = attrs.iter().any(|a| a.is_value_str() && a.name() == "doc");
         if !has_doc {
-            cx.span_lint(MISSING_DOCS, sp,
+            cx.span_lint(MISSING_DOCS,
+                         sp,
                          &format!("missing documentation for {}", desc));
         }
     }
@@ -316,8 +327,10 @@ impl LintPass for MissingDoc {
 
 impl LateLintPass for MissingDoc {
     fn enter_lint_attrs(&mut self, _: &LateContext, attrs: &[ast::Attribute]) {
-        let doc_hidden = self.doc_hidden() || attrs.iter().any(|attr| {
-            attr.check_name("doc") && match attr.meta_item_list() {
+        let doc_hidden = self.doc_hidden() ||
+                         attrs.iter().any(|attr| {
+            attr.check_name("doc") &&
+            match attr.meta_item_list() {
                 None => false,
                 Some(l) => attr::list_contains_name(&l[..], "hidden"),
             }
@@ -329,13 +342,21 @@ impl LateLintPass for MissingDoc {
         self.doc_hidden_stack.pop().expect("empty doc_hidden_stack");
     }
 
-    fn check_struct_def(&mut self, _: &LateContext, _: &hir::VariantData,
-                        _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) {
+    fn check_struct_def(&mut self,
+                        _: &LateContext,
+                        _: &hir::VariantData,
+                        _: ast::Name,
+                        _: &hir::Generics,
+                        item_id: ast::NodeId) {
         self.struct_def_stack.push(item_id);
     }
 
-    fn check_struct_def_post(&mut self, _: &LateContext, _: &hir::VariantData,
-                             _: ast::Name, _: &hir::Generics, item_id: ast::NodeId) {
+    fn check_struct_def_post(&mut self,
+                             _: &LateContext,
+                             _: &hir::VariantData,
+                             _: ast::Name,
+                             _: &hir::Generics,
+                             item_id: ast::NodeId) {
         let popped = self.struct_def_stack.pop().expect("empty struct_def_stack");
         assert!(popped == item_id);
     }
@@ -358,10 +379,10 @@ impl LateLintPass for MissingDoc {
                     for itm in items {
                         self.private_traits.insert(itm.id);
                     }
-                    return
+                    return;
                 }
                 "a trait"
-            },
+            }
             hir::ItemTy(..) => "a type alias",
             hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_items) => {
                 // If the trait is private, add the impl items to private_traits so they don't get
@@ -369,26 +390,30 @@ impl LateLintPass for MissingDoc {
                 let real_trait = cx.tcx.expect_def(trait_ref.ref_id).def_id();
                 if let Some(node_id) = cx.tcx.map.as_local_node_id(real_trait) {
                     match cx.tcx.map.find(node_id) {
-                        Some(hir_map::NodeItem(item)) => if item.vis == hir::Visibility::Inherited {
-                            for itm in impl_items {
-                                self.private_traits.insert(itm.id);
+                        Some(hir_map::NodeItem(item)) => {
+                            if item.vis == hir::Visibility::Inherited {
+                                for itm in impl_items {
+                                    self.private_traits.insert(itm.id);
+                                }
                             }
-                        },
-                        _ => { }
+                        }
+                        _ => {}
                     }
                 }
-                return
-            },
+                return;
+            }
             hir::ItemConst(..) => "a constant",
             hir::ItemStatic(..) => "a static",
-            _ => return
+            _ => return,
         };
 
         self.check_missing_docs_attrs(cx, Some(it.id), &it.attrs, it.span, desc);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
-        if self.private_traits.contains(&trait_item.id) { return }
+        if self.private_traits.contains(&trait_item.id) {
+            return;
+        }
 
         let desc = match trait_item.node {
             hir::ConstTraitItem(..) => "an associated constant",
@@ -396,9 +421,11 @@ impl LateLintPass for MissingDoc {
             hir::TypeTraitItem(..) => "an associated type",
         };
 
-        self.check_missing_docs_attrs(cx, Some(trait_item.id),
+        self.check_missing_docs_attrs(cx,
+                                      Some(trait_item.id),
                                       &trait_item.attrs,
-                                      trait_item.span, desc);
+                                      trait_item.span,
+                                      desc);
     }
 
     fn check_impl_item(&mut self, cx: &LateContext, impl_item: &hir::ImplItem) {
@@ -412,26 +439,34 @@ impl LateLintPass for MissingDoc {
             hir::ImplItemKind::Method(..) => "a method",
             hir::ImplItemKind::Type(_) => "an associated type",
         };
-        self.check_missing_docs_attrs(cx, Some(impl_item.id),
+        self.check_missing_docs_attrs(cx,
+                                      Some(impl_item.id),
                                       &impl_item.attrs,
-                                      impl_item.span, desc);
+                                      impl_item.span,
+                                      desc);
     }
 
     fn check_struct_field(&mut self, cx: &LateContext, sf: &hir::StructField) {
         if !sf.is_positional() {
             if sf.vis == hir::Public || self.in_variant {
-                let cur_struct_def = *self.struct_def_stack.last()
+                let cur_struct_def = *self.struct_def_stack
+                    .last()
                     .expect("empty struct_def_stack");
-                self.check_missing_docs_attrs(cx, Some(cur_struct_def),
-                                              &sf.attrs, sf.span,
+                self.check_missing_docs_attrs(cx,
+                                              Some(cur_struct_def),
+                                              &sf.attrs,
+                                              sf.span,
                                               "a struct field")
             }
         }
     }
 
     fn check_variant(&mut self, cx: &LateContext, v: &hir::Variant, _: &hir::Generics) {
-        self.check_missing_docs_attrs(cx, Some(v.node.data.id()),
-                                      &v.node.attrs, v.span, "a variant");
+        self.check_missing_docs_attrs(cx,
+                                      Some(v.node.data.id()),
+                                      &v.node.attrs,
+                                      v.span,
+                                      "a variant");
         assert!(!self.in_variant);
         self.in_variant = true;
     }
@@ -486,7 +521,9 @@ impl LateLintPass for MissingCopyImplementations {
             }
             _ => return,
         };
-        if def.has_dtor() { return; }
+        if def.has_dtor() {
+            return;
+        }
         let parameter_environment = cx.tcx.empty_parameter_environment();
         // FIXME (@jroesch) should probably inver this so that the parameter env still impls this
         // method
@@ -514,9 +551,7 @@ pub struct MissingDebugImplementations {
 
 impl MissingDebugImplementations {
     pub fn new() -> MissingDebugImplementations {
-        MissingDebugImplementations {
-            impling_types: None,
-        }
+        MissingDebugImplementations { impling_types: None }
     }
 }
 
@@ -533,7 +568,9 @@ impl LateLintPass for MissingDebugImplementations {
         }
 
         match item.node {
-            hir::ItemStruct(..) | hir::ItemUnion(..) | hir::ItemEnum(..) => {},
+            hir::ItemStruct(..) |
+            hir::ItemUnion(..) |
+            hir::ItemEnum(..) => {}
             _ => return,
         }
 
@@ -585,12 +622,13 @@ pub struct Deprecated {
 
 impl Deprecated {
     pub fn new() -> Deprecated {
-        Deprecated {
-            current_item: ast::CRATE_NODE_ID,
-        }
+        Deprecated { current_item: ast::CRATE_NODE_ID }
     }
 
-    fn lint(&self, cx: &LateContext, _id: DefId, span: Span,
+    fn lint(&self,
+            cx: &LateContext,
+            _id: DefId,
+            span: Span,
             stability: &Option<&attr::Stability>,
             deprecation: &Option<stability::DeprecationEntry>) {
         // Deprecated attributes apply in-crate and cross-crate.
@@ -641,9 +679,10 @@ impl LintPass for Deprecated {
 impl LateLintPass for Deprecated {
     fn check_item(&mut self, cx: &LateContext, item: &hir::Item) {
         self.push_item(item.id);
-        stability::check_item(cx.tcx, item, false,
-                              &mut |id, sp, stab, depr|
-                                self.lint(cx, id, sp, &stab, &depr));
+        stability::check_item(cx.tcx,
+                              item,
+                              false,
+                              &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
     }
 
     fn check_item_post(&mut self, cx: &LateContext, item: &hir::Item) {
@@ -651,27 +690,30 @@ impl LateLintPass for Deprecated {
     }
 
     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
-        stability::check_expr(cx.tcx, e,
-                              &mut |id, sp, stab, depr|
-                                self.lint(cx, id, sp, &stab, &depr));
+        stability::check_expr(cx.tcx,
+                              e,
+                              &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
     }
 
     fn check_path(&mut self, cx: &LateContext, path: &hir::Path, id: ast::NodeId) {
-        stability::check_path(cx.tcx, path, id,
-                              &mut |id, sp, stab, depr|
-                                self.lint(cx, id, sp, &stab, &depr));
+        stability::check_path(cx.tcx,
+                              path,
+                              id,
+                              &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
     }
 
     fn check_path_list_item(&mut self, cx: &LateContext, item: &hir::PathListItem) {
-        stability::check_path_list_item(cx.tcx, item,
-                                         &mut |id, sp, stab, depr|
-                                           self.lint(cx, id, sp, &stab, &depr));
+        stability::check_path_list_item(cx.tcx,
+                                        item,
+                                        &mut |id, sp, stab, depr| {
+                                            self.lint(cx, id, sp, &stab, &depr)
+                                        });
     }
 
     fn check_pat(&mut self, cx: &LateContext, pat: &hir::Pat) {
-        stability::check_pat(cx.tcx, pat,
-                             &mut |id, sp, stab, depr|
-                                self.lint(cx, id, sp, &stab, &depr));
+        stability::check_pat(cx.tcx,
+                             pat,
+                             &mut |id, sp, stab, depr| self.lint(cx, id, sp, &stab, &depr));
     }
 
     fn check_impl_item(&mut self, _: &LateContext, item: &hir::ImplItem) {
@@ -716,15 +758,20 @@ impl LintPass for UnconditionalRecursion {
 }
 
 impl LateLintPass for UnconditionalRecursion {
-    fn check_fn(&mut self, cx: &LateContext, fn_kind: FnKind, _: &hir::FnDecl,
-                blk: &hir::Block, sp: Span, id: ast::NodeId) {
+    fn check_fn(&mut self,
+                cx: &LateContext,
+                fn_kind: FnKind,
+                _: &hir::FnDecl,
+                blk: &hir::Block,
+                sp: Span,
+                id: ast::NodeId) {
         let method = match fn_kind {
             FnKind::ItemFn(..) => None,
             FnKind::Method(..) => {
                 cx.tcx.impl_or_trait_item(cx.tcx.map.local_def_id(id)).as_opt_method()
             }
             // closures can't recur, so they don't matter.
-            FnKind::Closure(_) => return
+            FnKind::Closure(_) => return,
         };
 
         // Walk through this function (say `f`) looking to see if
@@ -779,10 +826,8 @@ impl LateLintPass for UnconditionalRecursion {
             // is this a recursive call?
             let self_recursive = if node_id != ast::DUMMY_NODE_ID {
                 match method {
-                    Some(ref method) => {
-                        expr_refers_to_this_method(cx.tcx, method, node_id)
-                    }
-                    None => expr_refers_to_this_fn(cx.tcx, id, node_id)
+                    Some(ref method) => expr_refers_to_this_method(cx.tcx, method, node_id),
+                    None => expr_refers_to_this_fn(cx.tcx, id, node_id),
                 }
             } else {
                 false
@@ -808,7 +853,8 @@ impl LateLintPass for UnconditionalRecursion {
         // no break */ }`) shouldn't be linted unless it actually
         // recurs.
         if !reached_exit_without_self_call && !self_call_spans.is_empty() {
-            let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION, sp,
+            let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION,
+                                             sp,
                                              "function cannot return without recurring");
 
             // FIXME #19668: these could be span_lint_note's instead of this manual guard.
@@ -829,23 +875,21 @@ impl LateLintPass for UnconditionalRecursion {
         // Functions for identifying if the given Expr NodeId `id`
         // represents a call to the function `fn_id`/method `method`.
 
-        fn expr_refers_to_this_fn(tcx: TyCtxt,
-                                  fn_id: ast::NodeId,
-                                  id: ast::NodeId) -> bool {
+        fn expr_refers_to_this_fn(tcx: TyCtxt, fn_id: ast::NodeId, id: ast::NodeId) -> bool {
             match tcx.map.get(id) {
                 hir_map::NodeExpr(&hir::Expr { node: hir::ExprCall(ref callee, _), .. }) => {
-                    tcx.expect_def_or_none(callee.id).map_or(false, |def| {
-                        def.def_id() == tcx.map.local_def_id(fn_id)
-                    })
+                    tcx.expect_def_or_none(callee.id)
+                        .map_or(false, |def| def.def_id() == tcx.map.local_def_id(fn_id))
                 }
-                _ => false
+                _ => false,
             }
         }
 
         // Check if the expression `id` performs a call to `method`.
         fn expr_refers_to_this_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                 method: &ty::Method,
-                                                id: ast::NodeId) -> bool {
+                                                id: ast::NodeId)
+                                                -> bool {
             // Check for method calls and overloaded operators.
             let opt_m = tcx.tables.borrow().method_map.get(&ty::MethodCall::expr(id)).cloned();
             if let Some(m) = opt_m {
@@ -859,9 +903,11 @@ impl LateLintPass for UnconditionalRecursion {
             if let Some(adjustment::AdjustDerefRef(adj)) = opt_adj {
                 for i in 0..adj.autoderefs {
                     let method_call = ty::MethodCall::autoderef(id, i as u32);
-                    if let Some(m) = tcx.tables.borrow().method_map
-                                                        .get(&method_call)
-                                                        .cloned() {
+                    if let Some(m) = tcx.tables
+                        .borrow()
+                        .method_map
+                        .get(&method_call)
+                        .cloned() {
                         if method_call_refers_to_method(tcx, method, m.def_id, m.substs, id) {
                             return true;
                         }
@@ -877,13 +923,16 @@ impl LateLintPass for UnconditionalRecursion {
                     match tcx.expect_def_or_none(callee.id) {
                         Some(Def::Method(def_id)) => {
                             let item_substs = tcx.node_id_item_substs(callee.id);
-                            method_call_refers_to_method(
-                                tcx, method, def_id, &item_substs.substs, id)
+                            method_call_refers_to_method(tcx,
+                                                         method,
+                                                         def_id,
+                                                         &item_substs.substs,
+                                                         id)
                         }
-                        _ => false
+                        _ => false,
                     }
                 }
-                _ => false
+                _ => false,
             }
         }
 
@@ -893,15 +942,14 @@ impl LateLintPass for UnconditionalRecursion {
                                                   method: &ty::Method,
                                                   callee_id: DefId,
                                                   callee_substs: &Substs<'tcx>,
-                                                  expr_id: ast::NodeId) -> bool {
+                                                  expr_id: ast::NodeId)
+                                                  -> bool {
             let callee_item = tcx.impl_or_trait_item(callee_id);
 
             match callee_item.container() {
                 // This is an inherent method, so the `def_id` refers
                 // directly to the method definition.
-                ty::ImplContainer(_) => {
-                    callee_id == method.def_id
-                }
+                ty::ImplContainer(_) => callee_id == method.def_id,
 
                 // A trait method, from any number of possible sources.
                 // Attempt to select a concrete impl before checking.
@@ -939,13 +987,12 @@ impl LateLintPass for UnconditionalRecursion {
                                 let container = ty::ImplContainer(vtable_impl.impl_def_id);
                                 // It matches if it comes from the same impl,
                                 // and has the same method name.
-                                container == method.container
-                                    && callee_item.name() == method.name
+                                container == method.container && callee_item.name() == method.name
                             }
 
                             // There's no way to know if this call is
                             // recursive, so we assume it's not.
-                            _ => false
+                            _ => false,
                         }
                     })
                 }
@@ -992,7 +1039,8 @@ impl LateLintPass for PluginAsLibrary {
         };
 
         if prfn.is_some() {
-            cx.span_lint(PLUGIN_AS_LIBRARY, it.span,
+            cx.span_lint(PLUGIN_AS_LIBRARY,
+                         it.span,
                          "compiler plugin used as an ordinary library");
         }
     }
@@ -1050,15 +1098,15 @@ impl LateLintPass for InvalidNoMangleItems {
                                      "generic functions must be mangled");
                     }
                 }
-            },
+            }
             hir::ItemStatic(..) => {
                 if attr::contains_name(&it.attrs, "no_mangle") &&
-                       !cx.access_levels.is_reachable(it.id) {
+                   !cx.access_levels.is_reachable(it.id) {
                     let msg = format!("static {} is marked #[no_mangle], but not exported",
                                       it.name);
                     cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
                 }
-            },
+            }
             hir::ItemConst(..) => {
                 if attr::contains_name(&it.attrs, "no_mangle") {
                     // Const items do not refer to a particular location in memory, and therefore
@@ -1068,7 +1116,7 @@ impl LateLintPass for InvalidNoMangleItems {
                     cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg);
                 }
             }
-            _ => {},
+            _ => {}
         }
     }
 }
@@ -1096,19 +1144,21 @@ impl LateLintPass for MutableTransmutes {
                    consider instead using an UnsafeCell";
         match get_transmute_from_to(cx, expr) {
             Some((&ty::TyRef(_, from_mt), &ty::TyRef(_, to_mt))) => {
-                if to_mt.mutbl == hir::Mutability::MutMutable
-                    && from_mt.mutbl == hir::Mutability::MutImmutable {
+                if to_mt.mutbl == hir::Mutability::MutMutable &&
+                   from_mt.mutbl == hir::Mutability::MutImmutable {
                     cx.span_lint(MUTABLE_TRANSMUTES, expr.span, msg);
                 }
             }
-            _ => ()
+            _ => (),
         }
 
-        fn get_transmute_from_to<'a, 'tcx>(cx: &LateContext<'a, 'tcx>, expr: &hir::Expr)
-            -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
+        fn get_transmute_from_to<'a, 'tcx>
+            (cx: &LateContext<'a, 'tcx>,
+             expr: &hir::Expr)
+             -> Option<(&'tcx ty::TypeVariants<'tcx>, &'tcx ty::TypeVariants<'tcx>)> {
             match expr.node {
                 hir::ExprPath(..) => (),
-                _ => return None
+                _ => return None,
             }
             if let Def::Fn(did) = cx.tcx.expect_def(expr.id) {
                 if !def_id_is_transmute(cx, did) {
@@ -1120,8 +1170,8 @@ impl LateLintPass for MutableTransmutes {
                         let from = bare_fn.sig.0.inputs[0];
                         let to = bare_fn.sig.0.output;
                         return Some((&from.sty, &to.sty));
-                    },
-                    _ => ()
+                    }
+                    _ => (),
                 }
             }
             None
@@ -1130,7 +1180,7 @@ impl LateLintPass for MutableTransmutes {
         fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
             match cx.tcx.lookup_item_type(def_id).ty.sty {
                 ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (),
-                _ => return false
+                _ => return false,
             }
             cx.tcx.item_name(def_id).as_str() == "transmute"
         }
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index 47d248fe2f2..74483b89cea 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -48,10 +48,10 @@ extern crate rustc_back;
 extern crate rustc_const_eval;
 extern crate syntax_pos;
 
-pub use rustc::lint as lint;
-pub use rustc::middle as middle;
-pub use rustc::session as session;
-pub use rustc::util as util;
+pub use rustc::lint;
+pub use rustc::middle;
+pub use rustc::session;
+pub use rustc::util;
 
 use session::Session;
 use lint::LintId;
@@ -139,13 +139,24 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
                           MissingDebugImplementations,
                           );
 
-    add_lint_group!(sess, "bad_style",
-                    NON_CAMEL_CASE_TYPES, NON_SNAKE_CASE, NON_UPPER_CASE_GLOBALS);
-
-    add_lint_group!(sess, "unused",
-                    UNUSED_IMPORTS, UNUSED_VARIABLES, UNUSED_ASSIGNMENTS, DEAD_CODE,
-                    UNUSED_MUT, UNREACHABLE_CODE, UNUSED_MUST_USE,
-                    UNUSED_UNSAFE, PATH_STATEMENTS, UNUSED_ATTRIBUTES);
+    add_lint_group!(sess,
+                    "bad_style",
+                    NON_CAMEL_CASE_TYPES,
+                    NON_SNAKE_CASE,
+                    NON_UPPER_CASE_GLOBALS);
+
+    add_lint_group!(sess,
+                    "unused",
+                    UNUSED_IMPORTS,
+                    UNUSED_VARIABLES,
+                    UNUSED_ASSIGNMENTS,
+                    DEAD_CODE,
+                    UNUSED_MUT,
+                    UNREACHABLE_CODE,
+                    UNUSED_MUST_USE,
+                    UNUSED_UNSAFE,
+                    PATH_STATEMENTS,
+                    UNUSED_ATTRIBUTES);
 
     // Guidelines for creating a future incompatibility lint:
     //
@@ -155,7 +166,8 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
     //   and include the full URL.
     // - Later, change lint to error
     // - Eventually, remove lint
-    store.register_future_incompatible(sess, vec![
+    store.register_future_incompatible(sess,
+                                       vec![
         FutureIncompatibleInfo {
             id: LintId::of(PRIVATE_IN_PUBLIC),
             reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
@@ -204,11 +216,13 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
 
     // Register renamed and removed lints
     store.register_renamed("unknown_features", "unused_features");
-    store.register_removed("unsigned_negation", "replaced by negate_unsigned feature gate");
+    store.register_removed("unsigned_negation",
+                           "replaced by negate_unsigned feature gate");
     store.register_removed("negate_unsigned", "cast a signed value instead");
     store.register_removed("raw_pointer_derive", "using derive with raw pointers is ok");
     // This was renamed to raw_pointer_derive, which was then removed,
     // so it is also considered removed
-    store.register_removed("raw_pointer_deriving", "using derive with raw pointers is ok");
+    store.register_removed("raw_pointer_deriving",
+                           "using derive with raw pointers is ok");
     store.register_removed("drop_with_repr_extern", "drop flags have been removed");
 }
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index 4caf7a04fe0..9464bf30b69 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -18,7 +18,7 @@ use rustc::traits::Reveal;
 use middle::const_val::ConstVal;
 use rustc_const_eval::eval_const_expr_partial;
 use rustc_const_eval::EvalHint::ExprTypeChecked;
-use util::nodemap::{FnvHashSet};
+use util::nodemap::FnvHashSet;
 use lint::{LateContext, LintContext, LintArray};
 use lint::{LintPass, LateLintPass};
 
@@ -91,15 +91,15 @@ pub struct TypeLimits {
 
 impl TypeLimits {
     pub fn new() -> TypeLimits {
-        TypeLimits {
-            negated_expr_id: ast::DUMMY_NODE_ID,
-        }
+        TypeLimits { negated_expr_id: ast::DUMMY_NODE_ID }
     }
 }
 
 impl LintPass for TypeLimits {
     fn get_lints(&self) -> LintArray {
-        lint_array!(UNUSED_COMPARISONS, OVERFLOWING_LITERALS, EXCEEDING_BITSHIFTS)
+        lint_array!(UNUSED_COMPARISONS,
+                    OVERFLOWING_LITERALS,
+                    EXCEEDING_BITSHIFTS)
     }
 }
 
@@ -111,13 +111,13 @@ impl LateLintPass for TypeLimits {
                     match lit.node {
                         ast::LitKind::Int(_, ast::LitIntType::Unsigned(_)) => {
                             forbid_unsigned_negation(cx, e.span);
-                        },
+                        }
                         ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => {
                             if let ty::TyUint(_) = cx.tcx.node_id_to_type(e.id).sty {
                                 forbid_unsigned_negation(cx, e.span);
                             }
-                        },
-                        _ => ()
+                        }
+                        _ => (),
                     }
                 } else {
                     let t = cx.tcx.node_id_to_type(expr.id);
@@ -129,10 +129,11 @@ impl LateLintPass for TypeLimits {
                 if self.negated_expr_id != e.id {
                     self.negated_expr_id = expr.id;
                 }
-            },
+            }
             hir::ExprBinary(binop, ref l, ref r) => {
                 if is_comparison(binop) && !check_limits(cx.tcx, binop, &l, &r) {
-                    cx.span_lint(UNUSED_COMPARISONS, e.span,
+                    cx.span_lint(UNUSED_COMPARISONS,
+                                 e.span,
                                  "comparison is useless due to type limits");
                 }
 
@@ -140,30 +141,35 @@ impl LateLintPass for TypeLimits {
                     let opt_ty_bits = match cx.tcx.node_id_to_type(l.id).sty {
                         ty::TyInt(t) => Some(int_ty_bits(t, cx.sess().target.int_type)),
                         ty::TyUint(t) => Some(uint_ty_bits(t, cx.sess().target.uint_type)),
-                        _ => None
+                        _ => None,
                     };
 
                     if let Some(bits) = opt_ty_bits {
                         let exceeding = if let hir::ExprLit(ref lit) = r.node {
-                            if let ast::LitKind::Int(shift, _) = lit.node { shift >= bits }
-                            else { false }
+                            if let ast::LitKind::Int(shift, _) = lit.node {
+                                shift >= bits
+                            } else {
+                                false
+                            }
                         } else {
                             match eval_const_expr_partial(cx.tcx, &r, ExprTypeChecked, None) {
                                 Ok(ConstVal::Integral(i)) => {
-                                    i.is_negative() || i.to_u64()
-                                                        .map(|i| i >= bits)
-                                                        .unwrap_or(true)
-                                },
-                                _ => { false }
+                                    i.is_negative() ||
+                                    i.to_u64()
+                                        .map(|i| i >= bits)
+                                        .unwrap_or(true)
+                                }
+                                _ => false,
                             }
                         };
                         if exceeding {
-                            cx.span_lint(EXCEEDING_BITSHIFTS, e.span,
+                            cx.span_lint(EXCEEDING_BITSHIFTS,
+                                         e.span,
                                          "bitshift exceeds the type's number of bits");
                         }
                     };
                 }
-            },
+            }
             hir::ExprLit(ref lit) => {
                 match cx.tcx.node_id_to_type(e.id).sty {
                     ty::TyInt(t) => {
@@ -182,14 +188,15 @@ impl LateLintPass for TypeLimits {
                                 // avoiding use of -min to prevent overflow/panic
                                 if (negative && v > max as u64 + 1) ||
                                    (!negative && v > max as u64) {
-                                    cx.span_lint(OVERFLOWING_LITERALS, e.span,
+                                    cx.span_lint(OVERFLOWING_LITERALS,
+                                                 e.span,
                                                  &format!("literal out of range for {:?}", t));
                                     return;
                                 }
                             }
-                            _ => bug!()
+                            _ => bug!(),
                         };
-                    },
+                    }
                     ty::TyUint(t) => {
                         let uint_type = if let ast::UintTy::Us = t {
                             cx.sess().target.uint_type
@@ -201,13 +208,14 @@ impl LateLintPass for TypeLimits {
                             // _v is u8, within range by definition
                             ast::LitKind::Byte(_v) => return,
                             ast::LitKind::Int(v, _) => v,
-                            _ => bug!()
+                            _ => bug!(),
                         };
                         if lit_val < min || lit_val > max {
-                            cx.span_lint(OVERFLOWING_LITERALS, e.span,
+                            cx.span_lint(OVERFLOWING_LITERALS,
+                                         e.span,
                                          &format!("literal out of range for {:?}", t));
                         }
-                    },
+                    }
                     ty::TyFloat(t) => {
                         let (min, max) = float_ty_range(t);
                         let lit_val: f64 = match lit.node {
@@ -215,70 +223,71 @@ impl LateLintPass for TypeLimits {
                             ast::LitKind::FloatUnsuffixed(ref v) => {
                                 match v.parse() {
                                     Ok(f) => f,
-                                    Err(_) => return
+                                    Err(_) => return,
                                 }
                             }
-                            _ => bug!()
+                            _ => bug!(),
                         };
                         if lit_val < min || lit_val > max {
-                            cx.span_lint(OVERFLOWING_LITERALS, e.span,
+                            cx.span_lint(OVERFLOWING_LITERALS,
+                                         e.span,
                                          &format!("literal out of range for {:?}", t));
                         }
-                    },
-                    _ => ()
+                    }
+                    _ => (),
                 };
-            },
-            _ => ()
+            }
+            _ => (),
         };
 
-        fn is_valid<T:cmp::PartialOrd>(binop: hir::BinOp, v: T,
-                                min: T, max: T) -> bool {
+        fn is_valid<T: cmp::PartialOrd>(binop: hir::BinOp, v: T, min: T, max: T) -> bool {
             match binop.node {
-                hir::BiLt => v >  min && v <= max,
-                hir::BiLe => v >= min && v <  max,
-                hir::BiGt => v >= min && v <  max,
-                hir::BiGe => v >  min && v <= max,
+                hir::BiLt => v > min && v <= max,
+                hir::BiLe => v >= min && v < max,
+                hir::BiGt => v >= min && v < max,
+                hir::BiGe => v > min && v <= max,
                 hir::BiEq | hir::BiNe => v >= min && v <= max,
-                _ => bug!()
+                _ => bug!(),
             }
         }
 
         fn rev_binop(binop: hir::BinOp) -> hir::BinOp {
-            codemap::respan(binop.span, match binop.node {
-                hir::BiLt => hir::BiGt,
-                hir::BiLe => hir::BiGe,
-                hir::BiGt => hir::BiLt,
-                hir::BiGe => hir::BiLe,
-                _ => return binop
-            })
+            codemap::respan(binop.span,
+                            match binop.node {
+                                hir::BiLt => hir::BiGt,
+                                hir::BiLe => hir::BiGe,
+                                hir::BiGt => hir::BiLt,
+                                hir::BiGe => hir::BiLe,
+                                _ => return binop,
+                            })
         }
 
         // for isize & usize, be conservative with the warnings, so that the
         // warnings are consistent between 32- and 64-bit platforms
         fn int_ty_range(int_ty: ast::IntTy) -> (i64, i64) {
             match int_ty {
-                ast::IntTy::Is => (i64::MIN,        i64::MAX),
-                ast::IntTy::I8 =>    (i8::MIN  as i64, i8::MAX  as i64),
-                ast::IntTy::I16 =>   (i16::MIN as i64, i16::MAX as i64),
-                ast::IntTy::I32 =>   (i32::MIN as i64, i32::MAX as i64),
-                ast::IntTy::I64 =>   (i64::MIN,        i64::MAX)
+                ast::IntTy::Is => (i64::MIN, i64::MAX),
+                ast::IntTy::I8 => (i8::MIN as i64, i8::MAX as i64),
+                ast::IntTy::I16 => (i16::MIN as i64, i16::MAX as i64),
+                ast::IntTy::I32 => (i32::MIN as i64, i32::MAX as i64),
+                ast::IntTy::I64 => (i64::MIN, i64::MAX),
             }
         }
 
         fn uint_ty_range(uint_ty: ast::UintTy) -> (u64, u64) {
             match uint_ty {
-                ast::UintTy::Us => (u64::MIN,         u64::MAX),
-                ast::UintTy::U8 =>    (u8::MIN   as u64, u8::MAX   as u64),
-                ast::UintTy::U16 =>   (u16::MIN  as u64, u16::MAX  as u64),
-                ast::UintTy::U32 =>   (u32::MIN  as u64, u32::MAX  as u64),
-                ast::UintTy::U64 =>   (u64::MIN,         u64::MAX)
+                ast::UintTy::Us => (u64::MIN, u64::MAX),
+                ast::UintTy::U8 => (u8::MIN as u64, u8::MAX as u64),
+                ast::UintTy::U16 => (u16::MIN as u64, u16::MAX as u64),
+                ast::UintTy::U32 => (u32::MIN as u64, u32::MAX as u64),
+                ast::UintTy::U64 => (u64::MIN, u64::MAX),
             }
         }
 
         fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) {
             match float_ty {
                 ast::FloatTy::F32 => (f32::MIN as f64, f32::MAX as f64),
-                ast::FloatTy::F64 => (f64::MIN,        f64::MAX)
+                ast::FloatTy::F64 => (f64::MIN, f64::MAX),
             }
         }
 
@@ -305,60 +314,60 @@ impl LateLintPass for TypeLimits {
         fn check_limits<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                   binop: hir::BinOp,
                                   l: &hir::Expr,
-                                  r: &hir::Expr) -> bool {
+                                  r: &hir::Expr)
+                                  -> bool {
             let (lit, expr, swap) = match (&l.node, &r.node) {
                 (&hir::ExprLit(_), _) => (l, r, true),
                 (_, &hir::ExprLit(_)) => (r, l, false),
-                _ => return true
+                _ => return true,
             };
             // Normalize the binop so that the literal is always on the RHS in
             // the comparison
-            let norm_binop = if swap {
-                rev_binop(binop)
-            } else {
-                binop
-            };
+            let norm_binop = if swap { rev_binop(binop) } else { binop };
             match tcx.node_id_to_type(expr.id).sty {
                 ty::TyInt(int_ty) => {
                     let (min, max) = int_ty_range(int_ty);
                     let lit_val: i64 = match lit.node {
-                        hir::ExprLit(ref li) => match li.node {
-                            ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
-                            ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64,
-                            _ => return true
-                        },
-                        _ => bug!()
+                        hir::ExprLit(ref li) => {
+                            match li.node {
+                                ast::LitKind::Int(v, ast::LitIntType::Signed(_)) |
+                                ast::LitKind::Int(v, ast::LitIntType::Unsuffixed) => v as i64,
+                                _ => return true,
+                            }
+                        }
+                        _ => bug!(),
                     };
                     is_valid(norm_binop, lit_val, min, max)
                 }
                 ty::TyUint(uint_ty) => {
                     let (min, max): (u64, u64) = uint_ty_range(uint_ty);
                     let lit_val: u64 = match lit.node {
-                        hir::ExprLit(ref li) => match li.node {
-                            ast::LitKind::Int(v, _) => v,
-                            _ => return true
-                        },
-                        _ => bug!()
+                        hir::ExprLit(ref li) => {
+                            match li.node {
+                                ast::LitKind::Int(v, _) => v,
+                                _ => return true,
+                            }
+                        }
+                        _ => bug!(),
                     };
                     is_valid(norm_binop, lit_val, min, max)
                 }
-                _ => true
+                _ => true,
             }
         }
 
         fn is_comparison(binop: hir::BinOp) -> bool {
             match binop.node {
-                hir::BiEq | hir::BiLt | hir::BiLe |
-                hir::BiNe | hir::BiGe | hir::BiGt => true,
-                _ => false
+                hir::BiEq | hir::BiLt | hir::BiLe | hir::BiNe | hir::BiGe | hir::BiGt => true,
+                _ => false,
             }
         }
 
         fn forbid_unsigned_negation(cx: &LateContext, span: Span) {
             cx.sess()
-              .struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
-              .span_help(span, "use a cast or the `!` operator")
-              .emit();
+                .struct_span_err_with_code(span, "unary negation of unsigned integer", "E0519")
+                .span_help(span, "use a cast or the `!` operator")
+                .emit();
         }
     }
 }
@@ -370,7 +379,7 @@ declare_lint! {
 }
 
 struct ImproperCTypesVisitor<'a, 'tcx: 'a> {
-    cx: &'a LateContext<'a, 'tcx>
+    cx: &'a LateContext<'a, 'tcx>,
 }
 
 enum FfiResult {
@@ -403,9 +412,13 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
         if def.variants[data_idx].fields.len() == 1 {
             match def.variants[data_idx].fields[0].ty(tcx, substs).sty {
-                ty::TyFnPtr(_) => { return true; }
-                ty::TyRef(..) => { return true; }
-                _ => { }
+                ty::TyFnPtr(_) => {
+                    return true;
+                }
+                ty::TyRef(..) => {
+                    return true;
+                }
+                _ => {}
             }
         }
     }
@@ -415,10 +428,7 @@ fn is_repr_nullable_ptr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     /// Check if the given type is "ffi-safe" (has a stable, well-defined
     /// representation which can be exported to C code).
-    fn check_type_for_ffi(&self,
-                          cache: &mut FnvHashSet<Ty<'tcx>>,
-                          ty: Ty<'tcx>)
-                          -> FfiResult {
+    fn check_type_for_ffi(&self, cache: &mut FnvHashSet<Ty<'tcx>>, ty: Ty<'tcx>) -> FfiResult {
         use self::FfiResult::*;
         let cx = self.cx.tcx;
 
@@ -431,112 +441,118 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
         }
 
         match ty.sty {
-            ty::TyAdt(def, substs) => match def.adt_kind() {
-                AdtKind::Struct => {
-                    if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
-                        return FfiUnsafe(
-                            "found struct without foreign-function-safe \
-                            representation annotation in foreign module, \
-                            consider adding a #[repr(C)] attribute to \
-                            the type");
-                    }
+            ty::TyAdt(def, substs) => {
+                match def.adt_kind() {
+                    AdtKind::Struct => {
+                        if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+                            return FfiUnsafe("found struct without foreign-function-safe \
+                                              representation annotation in foreign module, \
+                                              consider adding a #[repr(C)] attribute to the type");
+                        }
 
-                    // We can't completely trust repr(C) markings; make sure the
-                    // fields are actually safe.
-                    if def.struct_variant().fields.is_empty() {
-                        return FfiUnsafe(
-                            "found zero-size struct in foreign module, consider \
-                            adding a member to this struct");
-                    }
+                        // We can't completely trust repr(C) markings; make sure the
+                        // fields are actually safe.
+                        if def.struct_variant().fields.is_empty() {
+                            return FfiUnsafe("found zero-size struct in foreign module, consider \
+                                              adding a member to this struct");
+                        }
 
-                    for field in &def.struct_variant().fields {
-                        let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
-                        let r = self.check_type_for_ffi(cache, field_ty);
-                        match r {
-                            FfiSafe => {}
-                            FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
-                            FfiUnsafe(s) => { return FfiBadStruct(def.did, s); }
+                        for field in &def.struct_variant().fields {
+                            let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
+                            let r = self.check_type_for_ffi(cache, field_ty);
+                            match r {
+                                FfiSafe => {}
+                                FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
+                                    return r;
+                                }
+                                FfiUnsafe(s) => {
+                                    return FfiBadStruct(def.did, s);
+                                }
+                            }
                         }
+                        FfiSafe
                     }
-                    FfiSafe
-                }
-                AdtKind::Union => {
-                    if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
-                        return FfiUnsafe(
-                            "found union without foreign-function-safe \
-                            representation annotation in foreign module, \
-                            consider adding a #[repr(C)] attribute to \
-                            the type");
-                    }
+                    AdtKind::Union => {
+                        if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+                            return FfiUnsafe("found union without foreign-function-safe \
+                                              representation annotation in foreign module, \
+                                              consider adding a #[repr(C)] attribute to the type");
+                        }
 
-                    for field in &def.struct_variant().fields {
-                        let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
-                        let r = self.check_type_for_ffi(cache, field_ty);
-                        match r {
-                            FfiSafe => {}
-                            FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
-                            FfiUnsafe(s) => { return FfiBadUnion(def.did, s); }
+                        for field in &def.struct_variant().fields {
+                            let field_ty = cx.normalize_associated_type(&field.ty(cx, substs));
+                            let r = self.check_type_for_ffi(cache, field_ty);
+                            match r {
+                                FfiSafe => {}
+                                FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
+                                    return r;
+                                }
+                                FfiUnsafe(s) => {
+                                    return FfiBadUnion(def.did, s);
+                                }
+                            }
                         }
+                        FfiSafe
                     }
-                    FfiSafe
-                }
-                AdtKind::Enum => {
-                    if def.variants.is_empty() {
-                        // Empty enums are okay... although sort of useless.
-                        return FfiSafe
-                    }
+                    AdtKind::Enum => {
+                        if def.variants.is_empty() {
+                            // Empty enums are okay... although sort of useless.
+                            return FfiSafe;
+                        }
 
-                    // Check for a repr() attribute to specify the size of the
-                    // discriminant.
-                    let repr_hints = cx.lookup_repr_hints(def.did);
-                    match &repr_hints[..] {
-                        &[] => {
-                            // Special-case types like `Option<extern fn()>`.
-                            if !is_repr_nullable_ptr(cx, def, substs) {
-                                return FfiUnsafe(
-                                    "found enum without foreign-function-safe \
-                                    representation annotation in foreign module, \
-                                    consider adding a #[repr(...)] attribute to \
-                                    the type")
+                        // Check for a repr() attribute to specify the size of the
+                        // discriminant.
+                        let repr_hints = cx.lookup_repr_hints(def.did);
+                        match &repr_hints[..] {
+                            &[] => {
+                                // Special-case types like `Option<extern fn()>`.
+                                if !is_repr_nullable_ptr(cx, def, substs) {
+                                    return FfiUnsafe("found enum without foreign-function-safe \
+                                                      representation annotation in foreign \
+                                                      module, consider adding a #[repr(...)] \
+                                                      attribute to the type");
+                                }
                             }
-                        }
-                        &[ref hint] => {
-                            if !hint.is_ffi_safe() {
+                            &[ref hint] => {
+                                if !hint.is_ffi_safe() {
+                                    // FIXME: This shouldn't be reachable: we should check
+                                    // this earlier.
+                                    return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
+                                }
+
+                                // Enum with an explicitly sized discriminant; either
+                                // a C-style enum or a discriminated union.
+
+                                // The layout of enum variants is implicitly repr(C).
+                                // FIXME: Is that correct?
+                            }
+                            _ => {
                                 // FIXME: This shouldn't be reachable: we should check
                                 // this earlier.
-                                return FfiUnsafe(
-                                    "enum has unexpected #[repr(...)] attribute")
+                                return FfiUnsafe("enum has too many #[repr(...)] attributes");
                             }
-
-                            // Enum with an explicitly sized discriminant; either
-                            // a C-style enum or a discriminated union.
-
-                            // The layout of enum variants is implicitly repr(C).
-                            // FIXME: Is that correct?
                         }
-                        _ => {
-                            // FIXME: This shouldn't be reachable: we should check
-                            // this earlier.
-                            return FfiUnsafe(
-                                "enum has too many #[repr(...)] attributes");
-                        }
-                    }
 
-                    // Check the contained variants.
-                    for variant in &def.variants {
-                        for field in &variant.fields {
-                            let arg = cx.normalize_associated_type(&field.ty(cx, substs));
-                            let r = self.check_type_for_ffi(cache, arg);
-                            match r {
-                                FfiSafe => {}
-                                FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => { return r; }
-                                FfiUnsafe(s) => { return FfiBadEnum(def.did, s); }
+                        // Check the contained variants.
+                        for variant in &def.variants {
+                            for field in &variant.fields {
+                                let arg = cx.normalize_associated_type(&field.ty(cx, substs));
+                                let r = self.check_type_for_ffi(cache, arg);
+                                match r {
+                                    FfiSafe => {}
+                                    FfiBadStruct(..) | FfiBadUnion(..) | FfiBadEnum(..) => {
+                                        return r;
+                                    }
+                                    FfiUnsafe(s) => {
+                                        return FfiBadEnum(def.did, s);
+                                    }
+                                }
                             }
                         }
+                        FfiSafe
                     }
-                    FfiSafe
                 }
-            },
+            }
 
             ty::TyChar => {
                 FfiUnsafe("found Rust type `char` in foreign module, while \
@@ -544,8 +560,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             }
 
             // Primitive types with a stable representation.
-            ty::TyBool | ty::TyInt(..) | ty::TyUint(..) |
-            ty::TyFloat(..) | ty::TyNever => FfiSafe,
+            ty::TyBool | ty::TyInt(..) | ty::TyUint(..) | ty::TyFloat(..) | ty::TyNever => FfiSafe,
 
             ty::TyBox(..) => {
                 FfiUnsafe("found Rust type Box<_> in foreign module, \
@@ -572,24 +587,17 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                            consider using a struct instead")
             }
 
-            ty::TyRawPtr(ref m) | ty::TyRef(_, ref m) => {
-                self.check_type_for_ffi(cache, m.ty)
-            }
+            ty::TyRawPtr(ref m) |
+            ty::TyRef(_, ref m) => self.check_type_for_ffi(cache, m.ty),
 
-            ty::TyArray(ty, _) => {
-                self.check_type_for_ffi(cache, ty)
-            }
+            ty::TyArray(ty, _) => self.check_type_for_ffi(cache, ty),
 
             ty::TyFnPtr(bare_fn) => {
                 match bare_fn.abi {
-                    Abi::Rust |
-                    Abi::RustIntrinsic |
-                    Abi::PlatformIntrinsic |
-                    Abi::RustCall => {
-                        return FfiUnsafe(
-                            "found function pointer with Rust calling \
-                             convention in foreign module; consider using an \
-                             `extern` function pointer")
+                    Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
+                        return FfiUnsafe("found function pointer with Rust calling convention in \
+                                          foreign module; consider using an `extern` function \
+                                          pointer")
                     }
                     _ => {}
                 }
@@ -599,24 +607,30 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
                     let r = self.check_type_for_ffi(cache, sig.output);
                     match r {
                         FfiSafe => {}
-                        _ => { return r; }
+                        _ => {
+                            return r;
+                        }
                     }
                 }
                 for arg in sig.inputs {
                     let r = self.check_type_for_ffi(cache, arg);
                     match r {
                         FfiSafe => {}
-                        _ => { return r; }
+                        _ => {
+                            return r;
+                        }
                     }
                 }
                 FfiSafe
             }
 
-            ty::TyParam(..) | ty::TyInfer(..) | ty::TyError |
-            ty::TyClosure(..) | ty::TyProjection(..) | ty::TyAnon(..) |
-            ty::TyFnDef(..) => {
-                bug!("Unexpected type in foreign function")
-            }
+            ty::TyParam(..) |
+            ty::TyInfer(..) |
+            ty::TyError |
+            ty::TyClosure(..) |
+            ty::TyProjection(..) |
+            ty::TyAnon(..) |
+            ty::TyFnDef(..) => bug!("Unexpected type in foreign function"),
         }
     }
 
@@ -633,23 +647,28 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
             FfiResult::FfiBadStruct(_, s) => {
                 // FIXME: This diagnostic is difficult to read, and doesn't
                 // point at the relevant field.
-                self.cx.span_lint(IMPROPER_CTYPES, sp,
-                    &format!("found non-foreign-function-safe member in \
-                              struct marked #[repr(C)]: {}", s));
+                self.cx.span_lint(IMPROPER_CTYPES,
+                                  sp,
+                                  &format!("found non-foreign-function-safe member in struct \
+                                            marked #[repr(C)]: {}",
+                                           s));
             }
             FfiResult::FfiBadUnion(_, s) => {
                 // FIXME: This diagnostic is difficult to read, and doesn't
                 // point at the relevant field.
-                self.cx.span_lint(IMPROPER_CTYPES, sp,
-                    &format!("found non-foreign-function-safe member in \
-                              union marked #[repr(C)]: {}", s));
+                self.cx.span_lint(IMPROPER_CTYPES,
+                                  sp,
+                                  &format!("found non-foreign-function-safe member in union \
+                                            marked #[repr(C)]: {}",
+                                           s));
             }
             FfiResult::FfiBadEnum(_, s) => {
                 // FIXME: This diagnostic is difficult to read, and doesn't
                 // point at the relevant variant.
-                self.cx.span_lint(IMPROPER_CTYPES, sp,
-                    &format!("found non-foreign-function-safe member in \
-                              enum: {}", s));
+                self.cx.span_lint(IMPROPER_CTYPES,
+                                  sp,
+                                  &format!("found non-foreign-function-safe member in enum: {}",
+                                           s));
             }
         }
     }
@@ -719,13 +738,13 @@ impl LintPass for VariantSizeDifferences {
 impl LateLintPass for VariantSizeDifferences {
     fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
         if let hir::ItemEnum(ref enum_definition, ref gens) = it.node {
-            if gens.ty_params.is_empty() {  // sizes only make sense for non-generic types
+            if gens.ty_params.is_empty() {
+                // sizes only make sense for non-generic types
                 let t = cx.tcx.node_id_to_type(it.id);
                 let layout = cx.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
                     let ty = cx.tcx.erase_regions(&t);
-                    ty.layout(&infcx).unwrap_or_else(|e| {
-                        bug!("failed to get layout for `{}`: {}", t, e)
-                    })
+                    ty.layout(&infcx)
+                        .unwrap_or_else(|e| bug!("failed to get layout for `{}`: {}", t, e))
                 });
 
                 if let Layout::General { ref variants, ref size, discr, .. } = *layout {
@@ -738,23 +757,21 @@ impl LateLintPass for VariantSizeDifferences {
                         .zip(variants)
                         .map(|(variant, variant_layout)| {
                             // Subtract the size of the enum discriminant
-                            let bytes = variant_layout.min_size.bytes()
-                                                                 .saturating_sub(discr_size);
+                            let bytes = variant_layout.min_size
+                                .bytes()
+                                .saturating_sub(discr_size);
 
                             debug!("- variant `{}` is {} bytes large", variant.node.name, bytes);
                             bytes
                         })
                         .enumerate()
-                        .fold((0, 0, 0),
-                            |(l, s, li), (idx, size)|
-                                if size > l {
-                                    (size, l, idx)
-                                } else if size > s {
-                                    (l, size, li)
-                                } else {
-                                    (l, s, li)
-                                }
-                        );
+                        .fold((0, 0, 0), |(l, s, li), (idx, size)| if size > l {
+                            (size, l, idx)
+                        } else if size > s {
+                            (l, size, li)
+                        } else {
+                            (l, s, li)
+                        });
 
                     // we only warn if the largest variant is at least thrice as large as
                     // the second-largest.
@@ -762,7 +779,8 @@ impl LateLintPass for VariantSizeDifferences {
                         cx.span_lint(VARIANT_SIZE_DIFFERENCES,
                                      enum_definition.variants[largest_index].span,
                                      &format!("enum variant is more than three times larger \
-                                               ({} bytes) than the next largest", largest));
+                                               ({} bytes) than the next largest",
+                                              largest));
                     }
                 }
             }
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index d31f16df693..a29ff18ab53 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -49,8 +49,12 @@ impl UnusedMut {
                 if let hir::BindByValue(hir::MutMutable) = mode {
                     if !name.as_str().starts_with("_") {
                         match mutables.entry(name.0 as usize) {
-                            Vacant(entry) => { entry.insert(vec![id]); },
-                            Occupied(mut entry) => { entry.get_mut().push(id); },
+                            Vacant(entry) => {
+                                entry.insert(vec![id]);
+                            }
+                            Occupied(mut entry) => {
+                                entry.get_mut().push(id);
+                            }
                         }
                     }
                 }
@@ -60,7 +64,8 @@ impl UnusedMut {
         let used_mutables = cx.tcx.used_mut_nodes.borrow();
         for (_, v) in &mutables {
             if !v.iter().any(|e| used_mutables.contains(e)) {
-                cx.span_lint(UNUSED_MUT, cx.tcx.map.span(v[0]),
+                cx.span_lint(UNUSED_MUT,
+                             cx.tcx.map.span(v[0]),
                              "variable does not need to be mutable");
             }
         }
@@ -90,9 +95,13 @@ impl LateLintPass for UnusedMut {
         }
     }
 
-    fn check_fn(&mut self, cx: &LateContext,
-                _: FnKind, decl: &hir::FnDecl,
-                _: &hir::Block, _: Span, _: ast::NodeId) {
+    fn check_fn(&mut self,
+                cx: &LateContext,
+                _: FnKind,
+                decl: &hir::FnDecl,
+                _: &hir::Block,
+                _: Span,
+                _: ast::NodeId) {
         for a in &decl.inputs {
             self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
         }
@@ -124,7 +133,7 @@ impl LateLintPass for UnusedResults {
     fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
         let expr = match s.node {
             hir::StmtSemi(ref expr, _) => &**expr,
-            _ => return
+            _ => return,
         };
 
         if let hir::ExprRet(..) = expr.node {
@@ -184,8 +193,8 @@ impl LateLintPass for UnusedUnsafe {
         if let hir::ExprBlock(ref blk) = e.node {
             // Don't warn about generated blocks, that'll just pollute the output.
             if blk.rules == hir::UnsafeBlock(hir::UserProvided) &&
-                !cx.tcx.used_unsafe.borrow().contains(&blk.id) {
-                    cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block");
+               !cx.tcx.used_unsafe.borrow().contains(&blk.id) {
+                cx.span_lint(UNUSED_UNSAFE, blk.span, "unnecessary `unsafe` block");
             }
         }
     }
@@ -210,8 +219,7 @@ impl LateLintPass for PathStatements {
     fn check_stmt(&mut self, cx: &LateContext, s: &hir::Stmt) {
         if let hir::StmtSemi(ref expr, _) = s.node {
             if let hir::ExprPath(..) = expr.node {
-                cx.span_lint(PATH_STATEMENTS, s.span,
-                             "path statement with no effect");
+                cx.span_lint(PATH_STATEMENTS, s.span, "path statement with no effect");
             }
         }
     }
@@ -242,8 +250,8 @@ impl LateLintPass for UnusedAttributes {
                 AttributeType::Whitelisted if attr.check_name(name) => {
                     debug!("{:?} is Whitelisted", name);
                     break;
-                },
-                _ => ()
+                }
+                _ => (),
             }
         }
 
@@ -259,24 +267,22 @@ impl LateLintPass for UnusedAttributes {
             debug!("Emitting warning for: {:?}", attr);
             cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
             // Is it a builtin attribute that must be used at the crate level?
-            let known_crate = KNOWN_ATTRIBUTES.iter().find(|&&(name, ty, _)| {
-                attr.name() == name &&
-                ty == AttributeType::CrateLevel
-            }).is_some();
+            let known_crate = KNOWN_ATTRIBUTES.iter()
+                .find(|&&(name, ty, _)| attr.name() == name && ty == AttributeType::CrateLevel)
+                .is_some();
 
             // Has a plugin registered this attribute as one which must be used at
             // the crate level?
             let plugin_crate = plugin_attributes.iter()
-                                                .find(|&&(ref x, t)| {
-                                                        &*attr.name() == x &&
-                                                        AttributeType::CrateLevel == t
-                                                    }).is_some();
-            if  known_crate || plugin_crate {
+                .find(|&&(ref x, t)| &*attr.name() == x && AttributeType::CrateLevel == t)
+                .is_some();
+            if known_crate || plugin_crate {
                 let msg = match attr.node.style {
-                    ast::AttrStyle::Outer => "crate-level attribute should be an inner \
-                                              attribute: add an exclamation mark: #![foo]",
-                    ast::AttrStyle::Inner => "crate-level attribute should be in the \
-                                              root module",
+                    ast::AttrStyle::Outer => {
+                        "crate-level attribute should be an inner attribute: add an exclamation \
+                         mark: #![foo]"
+                    }
+                    ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
                 };
                 cx.span_lint(UNUSED_ATTRIBUTES, attr.span, msg);
             }
@@ -296,12 +302,16 @@ declare_lint! {
 pub struct UnusedParens;
 
 impl UnusedParens {
-    fn check_unused_parens_core(&self, cx: &EarlyContext, value: &ast::Expr, msg: &str,
+    fn check_unused_parens_core(&self,
+                                cx: &EarlyContext,
+                                value: &ast::Expr,
+                                msg: &str,
                                 struct_lit_needs_parens: bool) {
         if let ast::ExprKind::Paren(ref inner) = value.node {
             let necessary = struct_lit_needs_parens && contains_exterior_struct_lit(&inner);
             if !necessary {
-                cx.span_lint(UNUSED_PARENS, value.span,
+                cx.span_lint(UNUSED_PARENS,
+                             value.span,
                              &format!("unnecessary parentheses around {}", msg))
             }
         }
@@ -319,8 +329,7 @@ impl UnusedParens {
                 ast::ExprKind::AssignOp(_, ref lhs, ref rhs) |
                 ast::ExprKind::Binary(_, ref lhs, ref rhs) => {
                     // X { y: 1 } + X { y: 2 }
-                    contains_exterior_struct_lit(&lhs) ||
-                        contains_exterior_struct_lit(&rhs)
+                    contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs)
                 }
                 ast::ExprKind::Unary(_, ref x) |
                 ast::ExprKind::Cast(ref x, _) |
@@ -337,7 +346,7 @@ impl UnusedParens {
                     contains_exterior_struct_lit(&exprs[0])
                 }
 
-                _ => false
+                _ => false,
             }
         }
     }
@@ -363,18 +372,20 @@ impl EarlyLintPass for UnusedParens {
             Assign(_, ref value) => (value, "assigned value", false),
             AssignOp(.., ref value) => (value, "assigned value", false),
             InPlace(_, ref value) => (value, "emplacement value", false),
-            _ => return
+            _ => return,
         };
         self.check_unused_parens_core(cx, &value, msg, struct_lit_needs_parens);
     }
 
     fn check_stmt(&mut self, cx: &EarlyContext, s: &ast::Stmt) {
         let (value, msg) = match s.node {
-            ast::StmtKind::Local(ref local) => match local.init {
-                Some(ref value) => (value, "assigned value"),
-                None => return
-            },
-            _ => return
+            ast::StmtKind::Local(ref local) => {
+                match local.init {
+                    Some(ref value) => (value, "assigned value"),
+                    None => return,
+                }
+            }
+            _ => return,
         };
         self.check_unused_parens_core(cx, &value, msg, false);
     }
@@ -427,23 +438,24 @@ impl LateLintPass for UnusedAllocation {
     fn check_expr(&mut self, cx: &LateContext, e: &hir::Expr) {
         match e.node {
             hir::ExprBox(_) => {}
-            _ => return
+            _ => return,
         }
 
         if let Some(adjustment) = cx.tcx.tables.borrow().adjustments.get(&e.id) {
-            if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef {
-                ref autoref, ..
-            }) = *adjustment {
+            if let adjustment::AdjustDerefRef(adjustment::AutoDerefRef { ref autoref, .. }) =
+                *adjustment {
                 match autoref {
                     &Some(adjustment::AutoPtr(_, hir::MutImmutable)) => {
-                        cx.span_lint(UNUSED_ALLOCATION, e.span,
+                        cx.span_lint(UNUSED_ALLOCATION,
+                                     e.span,
                                      "unnecessary allocation, use & instead");
                     }
                     &Some(adjustment::AutoPtr(_, hir::MutMutable)) => {
-                        cx.span_lint(UNUSED_ALLOCATION, e.span,
+                        cx.span_lint(UNUSED_ALLOCATION,
+                                     e.span,
                                      "unnecessary allocation, use &mut instead");
                     }
-                    _ => ()
+                    _ => (),
                 }
             }
         }
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index 50c68d5e75e..302c0ce6c54 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -1817,8 +1817,6 @@ extern {
                                            Ty: DIType,
                                            AlwaysPreserve: bool,
                                            Flags: c_uint,
-                                           AddrOps: *const i64,
-                                           AddrOpsCount: c_uint,
                                            ArgNo: c_uint)
                                            -> DIVariable;
 
@@ -1855,15 +1853,6 @@ extern {
                                                InsertAtEnd: BasicBlockRef)
                                                -> ValueRef;
 
-    pub fn LLVMRustDIBuilderInsertDeclareBefore(Builder: DIBuilderRef,
-                                                Val: ValueRef,
-                                                VarInfo: DIVariable,
-                                                AddrOps: *const i64,
-                                                AddrOpsCount: c_uint,
-                                                DL: ValueRef,
-                                                InsertBefore: ValueRef)
-                                                -> ValueRef;
-
     pub fn LLVMRustDIBuilderCreateEnumerator(Builder: DIBuilderRef,
                                              Name: *const c_char,
                                              Val: u64)
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index a57207dc089..f97df67c445 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -582,7 +582,7 @@ impl<'a> CrateReader<'a> {
                     unreachable!();
                 }
             };
-            let local_span = mk_sp(lo, p.last_span.hi);
+            let local_span = mk_sp(lo, p.prev_span.hi);
 
             // Mark the attrs as used
             for attr in &def.attrs {
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 579a97138f2..bdb4d383cee 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -32,6 +32,7 @@ use rustc_const_math::ConstInt;
 
 use rustc::mir::repr::Mir;
 
+use std::borrow::Cow;
 use std::cell::Ref;
 use std::io;
 use std::mem;
@@ -202,7 +203,7 @@ impl<'doc, 'tcx> Decoder for DecodeContext<'doc, 'tcx> {
         read_f64 -> f64;
         read_f32 -> f32;
         read_char -> char;
-        read_str -> String;
+        read_str -> Cow<str>;
     }
 
     fn error(&mut self, err: &str) -> Self::Error {
diff --git a/src/librustc_metadata/lib.rs b/src/librustc_metadata/lib.rs
index acaafb35425..3d8a10f6c31 100644
--- a/src/librustc_metadata/lib.rs
+++ b/src/librustc_metadata/lib.rs
@@ -23,7 +23,7 @@
 #![feature(dotdot_in_tuple_patterns)]
 #![feature(proc_macro_internals)]
 #![feature(proc_macro_lib)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![feature(quote)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs
index 12f1eb8535a..02f15602d70 100644
--- a/src/librustc_mir/lib.rs
+++ b/src/librustc_mir/lib.rs
@@ -26,7 +26,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 
 #[macro_use] extern crate log;
 extern crate graphviz as dot;
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index 9149202c1c1..5600669d45f 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -13,7 +13,7 @@
 //! Here we build the "reduced graph": the graph of the module tree without
 //! any imports resolved.
 
-use macros;
+use macros::{InvocationData, LegacyScope};
 use resolve_imports::ImportDirectiveSubclass::{self, GlobImport};
 use {Module, ModuleS, ModuleKind};
 use Namespace::{self, TypeNS, ValueNS};
@@ -200,16 +200,16 @@ impl<'b> Resolver<'b> {
                         LoadedMacroKind::Def(mut def) => {
                             let name = def.ident.name;
                             if def.use_locally {
-                                let ext = macro_rules::compile(&self.session.parse_sess, &def);
-                                let shadowing =
-                                    self.resolve_macro_name(Mark::root(), name, false).is_some();
-                                self.expansion_data[&Mark::root()].module.macros.borrow_mut()
-                                    .insert(name, macros::NameBinding {
-                                        ext: Rc::new(ext),
-                                        expansion: expansion,
-                                        shadowing: shadowing,
-                                        span: loaded_macro.import_site,
-                                    });
+                                let ext =
+                                    Rc::new(macro_rules::compile(&self.session.parse_sess, &def));
+                                if self.builtin_macros.insert(name, ext).is_some() &&
+                                   expansion != Mark::root() {
+                                    let msg = format!("`{}` is already in scope", name);
+                                    self.session.struct_span_err(loaded_macro.import_site, &msg)
+                                        .note("macro-expanded `#[macro_use]`s may not shadow \
+                                               existing macros (see RFC 1560)")
+                                        .emit();
+                                }
                                 self.macro_names.insert(name);
                             }
                             if def.export {
@@ -250,7 +250,6 @@ impl<'b> Resolver<'b> {
                         attr::contains_name(&item.attrs, "no_implicit_prelude")
                     },
                     normal_ancestor_id: Some(item.id),
-                    macros_escape: self.contains_macro_use(&item.attrs),
                     ..ModuleS::new(Some(parent), ModuleKind::Def(def, name))
                 });
                 self.define(parent, name, TypeNS, (module, sp, vis));
@@ -520,22 +519,26 @@ impl<'b> Resolver<'b> {
 
 pub struct BuildReducedGraphVisitor<'a, 'b: 'a> {
     pub resolver: &'a mut Resolver<'b>,
+    pub legacy_scope: LegacyScope<'b>,
     pub expansion: Mark,
 }
 
 impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
-    fn visit_invoc(&mut self, id: ast::NodeId) {
-        self.resolver.expansion_data.get_mut(&Mark::from_placeholder_id(id)).unwrap().module =
-            self.resolver.current_module;
+    fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> {
+        let invocation = self.resolver.invocations[&Mark::from_placeholder_id(id)];
+        invocation.module.set(self.resolver.current_module);
+        invocation.legacy_scope.set(self.legacy_scope);
+        invocation
     }
 }
 
 macro_rules! method {
     ($visit:ident: $ty:ty, $invoc:path, $walk:ident) => {
         fn $visit(&mut self, node: &$ty) {
-            match node.node {
-                $invoc(..) => self.visit_invoc(node.id),
-                _ => visit::$walk(self, node),
+            if let $invoc(..) = node.node {
+                self.visit_invoc(node.id);
+            } else {
+                visit::$walk(self, node);
             }
         }
     }
@@ -543,22 +546,35 @@ macro_rules! method {
 
 impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
     method!(visit_impl_item: ast::ImplItem, ast::ImplItemKind::Macro, walk_impl_item);
-    method!(visit_stmt:      ast::Stmt,     ast::StmtKind::Mac,       walk_stmt);
     method!(visit_expr:      ast::Expr,     ast::ExprKind::Mac,       walk_expr);
     method!(visit_pat:       ast::Pat,      ast::PatKind::Mac,        walk_pat);
     method!(visit_ty:        ast::Ty,       ast::TyKind::Mac,         walk_ty);
 
     fn visit_item(&mut self, item: &Item) {
-        match item.node {
+        let macro_use = match item.node {
             ItemKind::Mac(..) if item.id == ast::DUMMY_NODE_ID => return, // Scope placeholder
-            ItemKind::Mac(..) => return self.visit_invoc(item.id),
-            _ => {}
-        }
+            ItemKind::Mac(..) => {
+                return self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(item.id));
+            }
+            ItemKind::Mod(..) => self.resolver.contains_macro_use(&item.attrs),
+            _ => false,
+        };
 
-        let parent = self.resolver.current_module;
+        let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
         self.resolver.build_reduced_graph_for_item(item, self.expansion);
         visit::walk_item(self, item);
         self.resolver.current_module = parent;
+        if !macro_use {
+            self.legacy_scope = legacy_scope;
+        }
+    }
+
+    fn visit_stmt(&mut self, stmt: &ast::Stmt) {
+        if let ast::StmtKind::Mac(..) = stmt.node {
+            self.legacy_scope = LegacyScope::Expansion(self.visit_invoc(stmt.id));
+        } else {
+            visit::walk_stmt(self, stmt);
+        }
     }
 
     fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
@@ -567,10 +583,11 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
     }
 
     fn visit_block(&mut self, block: &Block) {
-        let parent = self.resolver.current_module;
+        let (parent, legacy_scope) = (self.resolver.current_module, self.legacy_scope);
         self.resolver.build_reduced_graph_for_block(block);
         visit::walk_block(self, block);
         self.resolver.current_module = parent;
+        self.legacy_scope = legacy_scope;
     }
 
     fn visit_trait_item(&mut self, item: &TraitItem) {
@@ -578,7 +595,8 @@ impl<'a, 'b> Visitor for BuildReducedGraphVisitor<'a, 'b> {
         let def_id = parent.def_id().unwrap();
 
         if let TraitItemKind::Macro(_) = item.node {
-            return self.visit_invoc(item.id);
+            self.visit_invoc(item.id);
+            return
         }
 
         // Add the item to the trait info.
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index b573a78d3b3..83e66fdd3bc 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -57,6 +57,7 @@ use syntax::ext::base::MultiItemModifier;
 use syntax::ext::hygiene::Mark;
 use syntax::ast::{self, FloatTy};
 use syntax::ast::{CRATE_NODE_ID, Name, NodeId, IntTy, UintTy};
+use syntax::ext::base::SyntaxExtension;
 use syntax::parse::token::{self, keywords};
 use syntax::util::lev_distance::find_best_match_for_name;
 
@@ -77,6 +78,7 @@ use std::mem::replace;
 use std::rc::Rc;
 
 use resolve_imports::{ImportDirective, NameResolution};
+use macros::{InvocationData, LegacyBinding, LegacyScope};
 
 // NB: This module needs to be declared first so diagnostics are
 // registered before they are used.
@@ -274,13 +276,15 @@ fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
             err
         }
         ResolutionError::VariableNotBoundInPattern(variable_name, from, to) => {
-            struct_span_err!(resolver.session,
+            let mut err = struct_span_err!(resolver.session,
                              span,
                              E0408,
                              "variable `{}` from pattern #{} is not bound in pattern #{}",
                              variable_name,
                              from,
-                             to)
+                             to);
+            err.span_label(span, &format!("pattern doesn't bind `{}`", variable_name));
+            err
         }
         ResolutionError::VariableBoundWithDifferentMode(variable_name,
                                                         pattern_number,
@@ -791,9 +795,6 @@ pub struct ModuleS<'a> {
     // access the children must be preceded with a
     // `populate_module_if_necessary` call.
     populated: Cell<bool>,
-
-    macros: RefCell<FnvHashMap<Name, macros::NameBinding>>,
-    macros_escape: bool,
 }
 
 pub type Module<'a> = &'a ModuleS<'a>;
@@ -811,8 +812,6 @@ impl<'a> ModuleS<'a> {
             globs: RefCell::new((Vec::new())),
             traits: RefCell::new(None),
             populated: Cell::new(true),
-            macros: RefCell::new(FnvHashMap()),
-            macros_escape: false,
         }
     }
 
@@ -1076,7 +1075,7 @@ pub struct Resolver<'a> {
 
     privacy_errors: Vec<PrivacyError<'a>>,
     ambiguity_errors: Vec<AmbiguityError<'a>>,
-    macro_shadowing_errors: FnvHashSet<Span>,
+    disallowed_shadowing: Vec<(Name, Span, LegacyScope<'a>)>,
 
     arenas: &'a ResolverArenas<'a>,
     dummy_binding: &'a NameBinding<'a>,
@@ -1086,9 +1085,10 @@ pub struct Resolver<'a> {
     pub derive_modes: FnvHashMap<Name, Rc<MultiItemModifier>>,
     crate_loader: &'a mut CrateLoader,
     macro_names: FnvHashSet<Name>,
+    builtin_macros: FnvHashMap<Name, Rc<SyntaxExtension>>,
 
     // Maps the `Mark` of an expansion to its containing module or block.
-    expansion_data: FnvHashMap<Mark, macros::ExpansionData<'a>>,
+    invocations: FnvHashMap<Mark, &'a InvocationData<'a>>,
 }
 
 pub struct ResolverArenas<'a> {
@@ -1097,6 +1097,8 @@ pub struct ResolverArenas<'a> {
     name_bindings: arena::TypedArena<NameBinding<'a>>,
     import_directives: arena::TypedArena<ImportDirective<'a>>,
     name_resolutions: arena::TypedArena<RefCell<NameResolution<'a>>>,
+    invocation_data: arena::TypedArena<InvocationData<'a>>,
+    legacy_bindings: arena::TypedArena<LegacyBinding<'a>>,
 }
 
 impl<'a> ResolverArenas<'a> {
@@ -1120,6 +1122,13 @@ impl<'a> ResolverArenas<'a> {
     fn alloc_name_resolution(&'a self) -> &'a RefCell<NameResolution<'a>> {
         self.name_resolutions.alloc(Default::default())
     }
+    fn alloc_invocation_data(&'a self, expansion_data: InvocationData<'a>)
+                             -> &'a InvocationData<'a> {
+        self.invocation_data.alloc(expansion_data)
+    }
+    fn alloc_legacy_binding(&'a self, binding: LegacyBinding<'a>) -> &'a LegacyBinding<'a> {
+        self.legacy_bindings.alloc(binding)
+    }
 }
 
 impl<'a> ty::NodeIdTree for Resolver<'a> {
@@ -1205,8 +1214,9 @@ impl<'a> Resolver<'a> {
         let mut definitions = Definitions::new();
         DefCollector::new(&mut definitions).collect_root();
 
-        let mut expansion_data = FnvHashMap();
-        expansion_data.insert(Mark::root(), macros::ExpansionData::root(graph_root));
+        let mut invocations = FnvHashMap();
+        invocations.insert(Mark::root(),
+                           arenas.alloc_invocation_data(InvocationData::root(graph_root)));
 
         Resolver {
             session: session,
@@ -1252,7 +1262,7 @@ impl<'a> Resolver<'a> {
 
             privacy_errors: Vec::new(),
             ambiguity_errors: Vec::new(),
-            macro_shadowing_errors: FnvHashSet(),
+            disallowed_shadowing: Vec::new(),
 
             arenas: arenas,
             dummy_binding: arenas.alloc_name_binding(NameBinding {
@@ -1266,7 +1276,8 @@ impl<'a> Resolver<'a> {
             derive_modes: FnvHashMap(),
             crate_loader: crate_loader,
             macro_names: FnvHashSet(),
-            expansion_data: expansion_data,
+            builtin_macros: FnvHashMap(),
+            invocations: invocations,
         }
     }
 
@@ -1277,6 +1288,8 @@ impl<'a> Resolver<'a> {
             name_bindings: arena::TypedArena::new(),
             import_directives: arena::TypedArena::new(),
             name_resolutions: arena::TypedArena::new(),
+            invocation_data: arena::TypedArena::new(),
+            legacy_bindings: arena::TypedArena::new(),
         }
     }
 
@@ -3338,7 +3351,8 @@ impl<'a> Resolver<'a> {
         vis.is_accessible_from(module.normal_ancestor_id.unwrap(), self)
     }
 
-    fn report_errors(&self) {
+    fn report_errors(&mut self) {
+        self.report_shadowing_errors();
         let mut reported_spans = FnvHashSet();
 
         for &AmbiguityError { span, name, b1, b2 } in &self.ambiguity_errors {
@@ -3366,6 +3380,20 @@ impl<'a> Resolver<'a> {
         }
     }
 
+    fn report_shadowing_errors(&mut self) {
+        let mut reported_errors = FnvHashSet();
+        for (name, span, scope) in replace(&mut self.disallowed_shadowing, Vec::new()) {
+            if self.resolve_macro_name(scope, name, false).is_some() &&
+               reported_errors.insert((name, span)) {
+                let msg = format!("`{}` is already in scope", name);
+                self.session.struct_span_err(span, &msg)
+                    .note("macro-expanded `macro_rules!`s may not shadow \
+                           existing macros (see RFC 1560)")
+                    .emit();
+            }
+        }
+    }
+
     fn report_conflict(&self,
                        parent: Module,
                        name: Name,
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 3f6c69278be..86ab077191e 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -12,47 +12,76 @@ use {Module, Resolver};
 use build_reduced_graph::BuildReducedGraphVisitor;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefIndex};
 use rustc::hir::map::{self, DefCollector};
+use rustc::util::nodemap::FnvHashMap;
+use std::cell::Cell;
 use std::rc::Rc;
 use syntax::ast;
 use syntax::errors::DiagnosticBuilder;
-use syntax::ext::base::{self, MultiModifier, MultiDecorator, MultiItemModifier};
+use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator, MultiItemModifier};
 use syntax::ext::base::{NormalTT, SyntaxExtension};
 use syntax::ext::expand::{Expansion, Invocation, InvocationKind};
-use syntax::ext::hygiene::{Mark, SyntaxContext};
+use syntax::ext::hygiene::Mark;
 use syntax::ext::tt::macro_rules;
 use syntax::parse::token::intern;
 use syntax::util::lev_distance::find_best_match_for_name;
-use syntax_pos::{Span, DUMMY_SP};
-
-// FIXME(jseyfried) Merge with `::NameBinding`.
-pub struct NameBinding {
-    pub ext: Rc<SyntaxExtension>,
-    pub expansion: Mark,
-    pub shadowing: bool,
-    pub span: Span,
-}
+use syntax_pos::Span;
 
 #[derive(Clone)]
-pub struct ExpansionData<'a> {
-    backtrace: SyntaxContext,
-    pub module: Module<'a>,
+pub struct InvocationData<'a> {
+    pub module: Cell<Module<'a>>,
     def_index: DefIndex,
     // True if this expansion is in a `const_integer` position, for example `[u32; m!()]`.
     // c.f. `DefCollector::visit_ast_const_integer`.
     const_integer: bool,
+    // The scope in which the invocation path is resolved.
+    pub legacy_scope: Cell<LegacyScope<'a>>,
+    // The smallest scope that includes this invocation's expansion,
+    // or `Empty` if this invocation has not been expanded yet.
+    pub expansion: Cell<LegacyScope<'a>>,
 }
 
-impl<'a> ExpansionData<'a> {
+impl<'a> InvocationData<'a> {
     pub fn root(graph_root: Module<'a>) -> Self {
-        ExpansionData {
-            backtrace: SyntaxContext::empty(),
-            module: graph_root,
+        InvocationData {
+            module: Cell::new(graph_root),
             def_index: CRATE_DEF_INDEX,
             const_integer: false,
+            legacy_scope: Cell::new(LegacyScope::Empty),
+            expansion: Cell::new(LegacyScope::Empty),
+        }
+    }
+}
+
+#[derive(Copy, Clone)]
+pub enum LegacyScope<'a> {
+    Empty,
+    Invocation(&'a InvocationData<'a>), // The scope of the invocation, not including its expansion
+    Expansion(&'a InvocationData<'a>), // The scope of the invocation, including its expansion
+    Binding(&'a LegacyBinding<'a>),
+}
+
+impl<'a> LegacyScope<'a> {
+    fn simplify_expansion(mut invoc: &'a InvocationData<'a>) -> Self {
+        while let LegacyScope::Invocation(_) = invoc.expansion.get() {
+            match invoc.legacy_scope.get() {
+                LegacyScope::Expansion(new_invoc) => invoc = new_invoc,
+                LegacyScope::Binding(_) => break,
+                scope @ _ => return scope,
+            }
         }
+        LegacyScope::Expansion(invoc)
     }
 }
 
+pub struct LegacyBinding<'a> {
+    parent: LegacyScope<'a>,
+    name: ast::Name,
+    ext: Rc<SyntaxExtension>,
+    span: Span,
+}
+
+pub type LegacyImports = FnvHashMap<ast::Name, (Rc<SyntaxExtension>, Span)>;
+
 impl<'a> base::Resolver for Resolver<'a> {
     fn next_node_id(&mut self) -> ast::NodeId {
         self.session.next_node_id()
@@ -61,19 +90,28 @@ impl<'a> base::Resolver for Resolver<'a> {
     fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
         let mark = Mark::fresh();
         let module = self.module_map[&id];
-        self.expansion_data.insert(mark, ExpansionData {
-            backtrace: SyntaxContext::empty(),
-            module: module,
+        self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData {
+            module: Cell::new(module),
             def_index: module.def_id().unwrap().index,
             const_integer: false,
-        });
+            legacy_scope: Cell::new(LegacyScope::Empty),
+            expansion: Cell::new(LegacyScope::Empty),
+        }));
         mark
     }
 
     fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
-        self.collect_def_ids(mark, expansion);
-        self.current_module = self.expansion_data[&mark].module;
-        expansion.visit_with(&mut BuildReducedGraphVisitor { resolver: self, expansion: mark });
+        let invocation = self.invocations[&mark];
+        self.collect_def_ids(invocation, expansion);
+
+        self.current_module = invocation.module.get();
+        let mut visitor = BuildReducedGraphVisitor {
+            resolver: self,
+            legacy_scope: LegacyScope::Invocation(invocation),
+            expansion: mark,
+        };
+        expansion.visit_with(&mut visitor);
+        invocation.expansion.set(visitor.legacy_scope);
     }
 
     fn add_macro(&mut self, scope: Mark, mut def: ast::MacroDef) {
@@ -81,17 +119,14 @@ impl<'a> base::Resolver for Resolver<'a> {
             self.session.span_err(def.span, "user-defined macros may not be named `macro_rules`");
         }
         if def.use_locally {
-            let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope];
-            while module.macros_escape {
-                module = module.parent.unwrap();
-            }
-            let binding = NameBinding {
+            let invocation = self.invocations[&scope];
+            let binding = self.arenas.alloc_legacy_binding(LegacyBinding {
+                parent: invocation.legacy_scope.get(),
+                name: def.ident.name,
                 ext: Rc::new(macro_rules::compile(&self.session.parse_sess, &def)),
-                expansion: backtrace.data().prev_ctxt.data().outer_mark,
-                shadowing: self.resolve_macro_name(scope, def.ident.name, false).is_some(),
                 span: def.span,
-            };
-            module.macros.borrow_mut().insert(def.ident.name, binding);
+            });
+            invocation.legacy_scope.set(LegacyScope::Binding(binding));
             self.macro_names.insert(def.ident.name);
         }
         if def.export {
@@ -104,12 +139,7 @@ impl<'a> base::Resolver for Resolver<'a> {
         if let NormalTT(..) = *ext {
             self.macro_names.insert(ident.name);
         }
-        self.graph_root.macros.borrow_mut().insert(ident.name, NameBinding {
-            ext: ext,
-            expansion: Mark::root(),
-            shadowing: false,
-            span: DUMMY_SP,
-        });
+        self.builtin_macros.insert(ident.name, ext);
     }
 
     fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>) {
@@ -119,8 +149,8 @@ impl<'a> base::Resolver for Resolver<'a> {
     fn find_attr_invoc(&mut self, attrs: &mut Vec<ast::Attribute>) -> Option<ast::Attribute> {
         for i in 0..attrs.len() {
             let name = intern(&attrs[i].name());
-            match self.expansion_data[&Mark::root()].module.macros.borrow().get(&name) {
-                Some(binding) => match *binding.ext {
+            match self.builtin_macros.get(&name) {
+                Some(ext) => match **ext {
                     MultiModifier(..) | MultiDecorator(..) | SyntaxExtension::AttrProcMacro(..) => {
                         return Some(attrs.remove(i))
                     }
@@ -132,7 +162,8 @@ impl<'a> base::Resolver for Resolver<'a> {
         None
     }
 
-    fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
+    fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
+                     -> Result<Rc<SyntaxExtension>, Determinacy> {
         let (name, span) = match invoc.kind {
             InvocationKind::Bang { ref mac, .. } => {
                 let path = &mac.node.path;
@@ -140,19 +171,27 @@ impl<'a> base::Resolver for Resolver<'a> {
                    !path.segments[0].parameters.is_empty() {
                     self.session.span_err(path.span,
                                           "expected macro name without module separators");
-                    return None;
+                    return Err(Determinacy::Determined);
                 }
                 (path.segments[0].identifier.name, path.span)
             }
             InvocationKind::Attr { ref attr, .. } => (intern(&*attr.name()), attr.span),
         };
 
-        self.resolve_macro_name(scope, name, true).or_else(|| {
-            let mut err =
-                self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
-            self.suggest_macro_name(&name.as_str(), &mut err);
-            err.emit();
-            None
+        let invocation = self.invocations[&scope];
+        if let LegacyScope::Expansion(parent) = invocation.legacy_scope.get() {
+            invocation.legacy_scope.set(LegacyScope::simplify_expansion(parent));
+        }
+        self.resolve_macro_name(invocation.legacy_scope.get(), name, true).ok_or_else(|| {
+            if force {
+                let mut err =
+                    self.session.struct_span_err(span, &format!("macro undefined: '{}!'", name));
+                self.suggest_macro_name(&name.as_str(), &mut err);
+                err.emit();
+                Determinacy::Determined
+            } else {
+                Determinacy::Undetermined
+            }
         })
     }
 
@@ -162,36 +201,40 @@ impl<'a> base::Resolver for Resolver<'a> {
 }
 
 impl<'a> Resolver<'a> {
-    pub fn resolve_macro_name(&mut self, scope: Mark, name: ast::Name, record_used: bool)
+    pub fn resolve_macro_name(&mut self,
+                              mut scope: LegacyScope<'a>,
+                              name: ast::Name,
+                              record_used: bool)
                               -> Option<Rc<SyntaxExtension>> {
-        let ExpansionData { mut module, backtrace, .. } = self.expansion_data[&scope];
+        let mut relative_depth: u32 = 0;
         loop {
-            if let Some(binding) = module.macros.borrow().get(&name) {
-                let mut backtrace = backtrace.data();
-                while binding.expansion != backtrace.outer_mark {
-                    if backtrace.outer_mark != Mark::root() {
-                        backtrace = backtrace.prev_ctxt.data();
-                        continue
+            scope = match scope {
+                LegacyScope::Empty => break,
+                LegacyScope::Expansion(invocation) => {
+                    if let LegacyScope::Empty = invocation.expansion.get() {
+                        invocation.legacy_scope.get()
+                    } else {
+                        relative_depth += 1;
+                        invocation.expansion.get()
                     }
-
-                    if record_used && binding.shadowing &&
-                       self.macro_shadowing_errors.insert(binding.span) {
-                        let msg = format!("`{}` is already in scope", name);
-                        self.session.struct_span_err(binding.span, &msg)
-                            .note("macro-expanded `macro_rules!`s and `#[macro_use]`s \
-                                   may not shadow existing macros (see RFC 1560)")
-                            .emit();
+                }
+                LegacyScope::Invocation(invocation) => {
+                    relative_depth = relative_depth.saturating_sub(1);
+                    invocation.legacy_scope.get()
+                }
+                LegacyScope::Binding(binding) => {
+                    if binding.name == name {
+                        if record_used && relative_depth > 0 {
+                            self.disallowed_shadowing.push((name, binding.span, binding.parent));
+                        }
+                        return Some(binding.ext.clone());
                     }
-                    break
+                    binding.parent
                 }
-                return Some(binding.ext.clone());
-            }
-            match module.parent {
-                Some(parent) => module = parent,
-                None => break,
-            }
+            };
         }
-        None
+
+        self.builtin_macros.get(&name).cloned()
     }
 
     fn suggest_macro_name(&mut self, name: &str, err: &mut DiagnosticBuilder<'a>) {
@@ -204,15 +247,19 @@ impl<'a> Resolver<'a> {
         }
     }
 
-    fn collect_def_ids(&mut self, mark: Mark, expansion: &Expansion) {
-        let expansion_data = &mut self.expansion_data;
-        let ExpansionData { backtrace, def_index, const_integer, module } = expansion_data[&mark];
+    fn collect_def_ids(&mut self, invocation: &'a InvocationData<'a>, expansion: &Expansion) {
+        let Resolver { ref mut invocations, arenas, graph_root, .. } = *self;
+        let InvocationData { def_index, const_integer, .. } = *invocation;
+
         let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| {
-            expansion_data.entry(invoc.mark).or_insert(ExpansionData {
-                backtrace: backtrace.apply_mark(invoc.mark),
-                def_index: invoc.def_index,
-                const_integer: invoc.const_integer,
-                module: module,
+            invocations.entry(invoc.mark).or_insert_with(|| {
+                arenas.alloc_invocation_data(InvocationData {
+                    def_index: invoc.def_index,
+                    const_integer: invoc.const_integer,
+                    module: Cell::new(graph_root),
+                    expansion: Cell::new(LegacyScope::Empty),
+                    legacy_scope: Cell::new(LegacyScope::Empty),
+                })
             });
         };
 
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 4689c4ded5c..0939e6f1644 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use self::Determinacy::*;
 use self::ImportDirectiveSubclass::*;
 
 use Module;
@@ -26,6 +25,7 @@ use rustc::lint::builtin::PRIVATE_IN_PUBLIC;
 use rustc::hir::def::*;
 
 use syntax::ast::{NodeId, Name};
+use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
 use syntax::util::lev_distance::find_best_match_for_name;
 use syntax_pos::Span;
 
@@ -37,12 +37,6 @@ impl<'a> Resolver<'a> {
     }
 }
 
-#[derive(Copy, Clone, Debug)]
-pub enum Determinacy {
-    Determined,
-    Undetermined,
-}
-
 /// Contains data for specific types of import directives.
 #[derive(Clone, Debug)]
 pub enum ImportDirectiveSubclass<'a> {
@@ -197,7 +191,8 @@ impl<'a> Resolver<'a> {
         // If the resolution doesn't depend on glob definability, check privacy and return.
         if let Some(result) = self.try_result(&resolution, ns) {
             return result.and_then(|binding| {
-                if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) {
+                if self.is_accessible(binding.vis) && !is_disallowed_private_import(binding) ||
+                   binding.is_extern_crate() { // c.f. issue #37020
                     Success(binding)
                 } else {
                     Failed(None)
diff --git a/src/librustc_save_analysis/span_utils.rs b/src/librustc_save_analysis/span_utils.rs
index 953c6554919..22c087aba80 100644
--- a/src/librustc_save_analysis/span_utils.rs
+++ b/src/librustc_save_analysis/span_utils.rs
@@ -139,9 +139,9 @@ impl<'a> SpanUtils<'a> {
         let mut prev = toks.real_token();
         let mut result = None;
         let mut bracket_count = 0;
-        let mut last_span = None;
+        let mut prev_span = None;
         while prev.tok != token::Eof {
-            last_span = None;
+            prev_span = None;
             let mut next = toks.real_token();
 
             if (next.tok == token::OpenDelim(token::Paren) || next.tok == token::Lt) &&
@@ -166,12 +166,12 @@ impl<'a> SpanUtils<'a> {
             };
 
             if prev.tok.is_ident() && bracket_count == 0 {
-                last_span = Some(prev.sp);
+                prev_span = Some(prev.sp);
             }
             prev = next;
         }
-        if result.is_none() && last_span.is_some() {
-            return self.make_sub_span(span, last_span);
+        if result.is_none() && prev_span.is_some() {
+            return self.make_sub_span(span, prev_span);
         }
         return self.make_sub_span(span, result);
     }
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index e0e808f2dcc..3caf8c9e4c3 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -1050,8 +1050,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
     let fn_ty = ccx.tcx().erase_regions(&fn_ty);
     let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
 
-    let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig());
-    let sig = ccx.tcx().normalize_associated_type(&sig);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_ty.fn_sig());
     let abi = fn_ty.fn_abi();
 
     let lldecl = match ccx.instances().borrow().get(&instance) {
@@ -1073,8 +1072,7 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let ctor_ty = ccx.tcx().lookup_item_type(def_id).ty;
     let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty);
 
-    let sig = ccx.tcx().erase_late_bound_regions(&ctor_ty.fn_sig());
-    let sig = ccx.tcx().normalize_associated_type(&sig);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig());
     let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
 
     let (arena, fcx): (TypedArena<_>, FunctionContext);
diff --git a/src/librustc_trans/builder.rs b/src/librustc_trans/builder.rs
index 90f96af5496..8556e95903c 100644
--- a/src/librustc_trans/builder.rs
+++ b/src/librustc_trans/builder.rs
@@ -22,6 +22,7 @@ use value::Value;
 use util::nodemap::FnvHashMap;
 use libc::{c_uint, c_char};
 
+use std::borrow::Cow;
 use std::ffi::CString;
 use std::ptr;
 use syntax_pos::Span;
@@ -175,8 +176,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                    .collect::<Vec<String>>()
                    .join(", "));
 
-        check_call("invoke", llfn, args);
-
+        let args = self.check_call("invoke", llfn, args);
         let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut());
 
         unsafe {
@@ -543,6 +543,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
         assert!(!self.llbuilder.is_null());
         self.count_insn("store");
+        let ptr = self.check_store(val, ptr);
         unsafe {
             llvm::LLVMBuildStore(self.llbuilder, val, ptr)
         }
@@ -552,6 +553,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
         assert!(!self.llbuilder.is_null());
         self.count_insn("store.volatile");
+        let ptr = self.check_store(val, ptr);
         unsafe {
             let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr);
             llvm::LLVMSetVolatile(insn, llvm::True);
@@ -562,6 +564,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, order: AtomicOrdering) {
         debug!("Store {:?} -> {:?}", Value(val), Value(ptr));
         self.count_insn("store.atomic");
+        let ptr = self.check_store(val, ptr);
         unsafe {
             let ty = Type::from_ref(llvm::LLVMTypeOf(ptr));
             let align = llalign_of_pref(self.ccx, ty.element_type());
@@ -857,8 +860,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                    .collect::<Vec<String>>()
                    .join(", "));
 
-        check_call("call", llfn, args);
-
+        let args = self.check_call("call", llfn, args);
         let bundle = bundle.as_ref().map(|b| b.raw()).unwrap_or(ptr::null_mut());
 
         unsafe {
@@ -1100,10 +1102,32 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             llvm::LLVMRustBuildAtomicFence(self.llbuilder, order, scope);
         }
     }
-}
 
-fn check_call(typ: &str, llfn: ValueRef, args: &[ValueRef]) {
-    if cfg!(debug_assertions) {
+    /// Returns the ptr value that should be used for storing `val`.
+    fn check_store<'b>(&self,
+                       val: ValueRef,
+                       ptr: ValueRef) -> ValueRef {
+        let dest_ptr_ty = val_ty(ptr);
+        let stored_ty = val_ty(val);
+        let stored_ptr_ty = stored_ty.ptr_to();
+
+        assert_eq!(dest_ptr_ty.kind(), llvm::TypeKind::Pointer);
+
+        if dest_ptr_ty == stored_ptr_ty {
+            ptr
+        } else {
+            debug!("Type mismatch in store. \
+                    Expected {:?}, got {:?}; inserting bitcast",
+                   dest_ptr_ty, stored_ptr_ty);
+            self.bitcast(ptr, stored_ptr_ty)
+        }
+    }
+
+    /// Returns the args that should be used for a call to `llfn`.
+    fn check_call<'b>(&self,
+                      typ: &str,
+                      llfn: ValueRef,
+                      args: &'b [ValueRef]) -> Cow<'b, [ValueRef]> {
         let mut fn_ty = val_ty(llfn);
         // Strip off pointers
         while fn_ty.kind() == llvm::TypeKind::Pointer {
@@ -1115,16 +1139,31 @@ fn check_call(typ: &str, llfn: ValueRef, args: &[ValueRef]) {
 
         let param_tys = fn_ty.func_params();
 
-        let iter = param_tys.into_iter()
-            .zip(args.iter().map(|&v| val_ty(v)));
-        for (i, (expected_ty, actual_ty)) in iter.enumerate() {
-            if expected_ty != actual_ty {
-                bug!("Type mismatch in function call of {:?}. \
-                      Expected {:?} for param {}, got {:?}",
-                     Value(llfn),
-                     expected_ty, i, actual_ty);
+        let all_args_match = param_tys.iter()
+            .zip(args.iter().map(|&v| val_ty(v)))
+            .all(|(expected_ty, actual_ty)| *expected_ty == actual_ty);
+
+        if all_args_match {
+            return Cow::Borrowed(args);
+        }
+
+        let casted_args: Vec<_> = param_tys.into_iter()
+            .zip(args.iter())
+            .enumerate()
+            .map(|(i, (expected_ty, &actual_val))| {
+                let actual_ty = val_ty(actual_val);
+                if expected_ty != actual_ty {
+                    debug!("Type mismatch in function call of {:?}. \
+                            Expected {:?} for param {}, got {:?}; injecting bitcast",
+                           Value(llfn),
+                           expected_ty, i, actual_ty);
+                    self.bitcast(actual_val, expected_ty)
+                } else {
+                    actual_val
+                }
+            })
+            .collect();
 
-            }
-        }
+        return Cow::Owned(casted_args);
     }
 }
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 8822287a0e7..05e22896c40 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -184,8 +184,7 @@ impl<'tcx> Callee<'tcx> {
     pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
                               extra_args: &[Ty<'tcx>]) -> FnType {
         let abi = self.ty.fn_abi();
-        let sig = ccx.tcx().erase_late_bound_regions(self.ty.fn_sig());
-        let sig = ccx.tcx().normalize_associated_type(&sig);
+        let sig = ccx.tcx().erase_late_bound_regions_and_normalize(self.ty.fn_sig());
         let mut fn_ty = FnType::unadjusted(ccx, abi, &sig, extra_args);
         if let Virtual(_) = self.data {
             // Don't pass the vtable, it's not an argument of the virtual fn.
@@ -327,8 +326,7 @@ fn trans_fn_pointer_shim<'a, 'tcx>(
                  bare_fn_ty);
         }
     };
-    let sig = tcx.erase_late_bound_regions(sig);
-    let sig = ccx.tcx().normalize_associated_type(&sig);
+    let sig = tcx.erase_late_bound_regions_and_normalize(sig);
     let tuple_input_ty = tcx.mk_tup(sig.inputs.to_vec());
     let sig = ty::FnSig {
         inputs: vec![bare_fn_ty_maybe_ref,
diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs
index c87497384ad..a1d645fb993 100644
--- a/src/librustc_trans/closure.rs
+++ b/src/librustc_trans/closure.rs
@@ -61,8 +61,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     // Compute the rust-call form of the closure call method.
     let sig = &tcx.closure_type(closure_id, substs).sig;
-    let sig = tcx.erase_late_bound_regions(sig);
-    let sig = tcx.normalize_associated_type(&sig);
+    let sig = tcx.erase_late_bound_regions_and_normalize(sig);
     let closure_type = tcx.mk_closure_from_closure_substs(closure_id, substs);
     let function_type = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
         unsafety: hir::Unsafety::Normal,
@@ -126,8 +125,7 @@ pub fn trans_closure_body_via_mir<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         // of the closure expression.
 
         let sig = &tcx.closure_type(closure_def_id, closure_substs).sig;
-        let sig = tcx.erase_late_bound_regions(sig);
-        let sig = tcx.normalize_associated_type(&sig);
+        let sig = tcx.erase_late_bound_regions_and_normalize(sig);
 
         let closure_type = tcx.mk_closure_from_closure_substs(closure_def_id,
                                                               closure_substs);
@@ -249,8 +247,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     assert_eq!(abi, Abi::RustCall);
     sig.0.inputs[0] = closure_ty;
 
-    let sig = tcx.erase_late_bound_regions(&sig);
-    let sig = tcx.normalize_associated_type(&sig);
+    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
     let fn_ty = FnType::new(ccx, abi, &sig, &[]);
 
     let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 765c128c30b..570b844f80a 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -128,7 +128,7 @@ impl<'tcx> TypeMap<'tcx> {
 
     // Get the string representation of a UniqueTypeId. This method will fail if
     // the id is unknown.
-    fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> Rc<String> {
+    fn get_unique_type_id_as_string(&self, unique_type_id: UniqueTypeId) -> Rc<str> {
         let UniqueTypeId(interner_key) = unique_type_id;
         self.unique_id_interner.get(interner_key)
     }
@@ -236,7 +236,8 @@ impl<'tcx> TypeMap<'tcx> {
             ty::TyTrait(ref trait_data) => {
                 unique_type_id.push_str("trait ");
 
-                let principal = cx.tcx().erase_late_bound_regions(&trait_data.principal);
+                let principal = cx.tcx().erase_late_bound_regions_and_normalize(
+                    &trait_data.principal);
 
                 from_def_id_and_substs(self,
                                        cx,
@@ -254,8 +255,7 @@ impl<'tcx> TypeMap<'tcx> {
 
                 unique_type_id.push_str(" fn(");
 
-                let sig = cx.tcx().erase_late_bound_regions(sig);
-                let sig = cx.tcx().normalize_associated_type(&sig);
+                let sig = cx.tcx().erase_late_bound_regions_and_normalize(sig);
 
                 for &parameter_type in &sig.inputs {
                     let parameter_type_id =
@@ -299,7 +299,7 @@ impl<'tcx> TypeMap<'tcx> {
         // Trim to size before storing permanently
         unique_type_id.shrink_to_fit();
 
-        let key = self.unique_id_interner.intern(unique_type_id);
+        let key = self.unique_id_interner.intern(&unique_type_id);
         self.type_to_unique_id.insert(type_, UniqueTypeId(key));
 
         return UniqueTypeId(key);
@@ -367,7 +367,7 @@ impl<'tcx> TypeMap<'tcx> {
         let enum_variant_type_id = format!("{}::{}",
                                            &self.get_unique_type_id_as_string(enum_type_id),
                                            variant_name);
-        let interner_key = self.unique_id_interner.intern(enum_variant_type_id);
+        let interner_key = self.unique_id_interner.intern(&enum_variant_type_id);
         UniqueTypeId(interner_key)
     }
 }
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index a23fd3ab8b3..813915bfd6e 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -482,8 +482,6 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                     type_metadata,
                     cx.sess().opts.optimize != config::OptLevel::No,
                     0,
-                    address_operations.as_ptr(),
-                    address_operations.len() as c_uint,
                     argument_index)
             };
             source_loc::set_debug_location(cx, None,
diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_trans/debuginfo/type_names.rs
index 7f021bee371..956402edc11 100644
--- a/src/librustc_trans/debuginfo/type_names.rs
+++ b/src/librustc_trans/debuginfo/type_names.rs
@@ -94,7 +94,8 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             output.push(']');
         },
         ty::TyTrait(ref trait_data) => {
-            let principal = cx.tcx().erase_late_bound_regions(&trait_data.principal);
+            let principal = cx.tcx().erase_late_bound_regions_and_normalize(
+                &trait_data.principal);
             push_item_name(cx, principal.def_id, false, output);
             push_type_params(cx, principal.substs, output);
         },
@@ -112,8 +113,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
             output.push_str("fn(");
 
-            let sig = cx.tcx().erase_late_bound_regions(sig);
-            let sig = cx.tcx().normalize_associated_type(&sig);
+            let sig = cx.tcx().erase_late_bound_regions_and_normalize(sig);
             if !sig.inputs.is_empty() {
                 for &parameter_type in &sig.inputs {
                     push_debuginfo_type_name(cx, parameter_type, true, output);
diff --git a/src/librustc_trans/declare.rs b/src/librustc_trans/declare.rs
index 0c1156a9874..1ec5ca4a563 100644
--- a/src/librustc_trans/declare.rs
+++ b/src/librustc_trans/declare.rs
@@ -104,8 +104,7 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
                             fn_type: ty::Ty<'tcx>) -> ValueRef {
     debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
     let abi = fn_type.fn_abi();
-    let sig = ccx.tcx().erase_late_bound_regions(fn_type.fn_sig());
-    let sig = ccx.tcx().normalize_associated_type(&sig);
+    let sig = ccx.tcx().erase_late_bound_regions_and_normalize(fn_type.fn_sig());
     debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
 
     let fty = FnType::new(ccx, abi, &sig, &[]);
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index 4cacbc0f35e..b1b09d3ca20 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -99,13 +99,12 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
     let _icx = push_ctxt("trans_intrinsic_call");
 
-    let (def_id, substs, sig) = match callee_ty.sty {
-        ty::TyFnDef(def_id, substs, fty) => {
-            let sig = tcx.erase_late_bound_regions(&fty.sig);
-            (def_id, substs, tcx.normalize_associated_type(&sig))
-        }
+    let (def_id, substs, fty) = match callee_ty.sty {
+        ty::TyFnDef(def_id, substs, ref fty) => (def_id, substs, fty),
         _ => bug!("expected fn item type, found {}", callee_ty)
     };
+
+    let sig = tcx.erase_late_bound_regions_and_normalize(&fty.sig);
     let arg_tys = sig.inputs;
     let ret_ty = sig.output;
     let name = tcx.item_name(def_id).as_str();
@@ -1108,8 +1107,7 @@ fn generic_simd_intrinsic<'blk, 'tcx, 'a>
 
 
     let tcx = bcx.tcx();
-    let sig = tcx.erase_late_bound_regions(callee_ty.fn_sig());
-    let sig = tcx.normalize_associated_type(&sig);
+    let sig = tcx.erase_late_bound_regions_and_normalize(callee_ty.fn_sig());
     let arg_tys = sig.inputs;
 
     // every intrinsic takes a SIMD vector as its first argument
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 41c8d565d41..81c0c184f66 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -36,7 +36,7 @@
 #![feature(slice_patterns)]
 #![feature(staged_api)]
 #![feature(unicode)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 
 use rustc::dep_graph::WorkProduct;
 
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index e8dcaf71f2d..dac70d4a1de 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -80,8 +80,7 @@ pub fn trans_object_shim<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
         _ => bug!()
     };
 
-    let sig = tcx.erase_late_bound_regions(sig);
-    let sig = tcx.normalize_associated_type(&sig);
+    let sig = tcx.erase_late_bound_regions_and_normalize(sig);
     let fn_ty = FnType::new(ccx, abi, &sig, &[]);
 
     let llfn = declare::define_internal_fn(ccx, &function_name, callee.ty);
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 9edb489decc..d60dc3fe843 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -418,7 +418,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     _ => bug!("{} is not callable", callee.ty)
                 };
 
-                let sig = bcx.tcx().erase_late_bound_regions(sig);
+                let sig = bcx.tcx().erase_late_bound_regions_and_normalize(sig);
 
                 // Handle intrinsics old trans wants Expr's for, ourselves.
                 let intrinsic = match (&callee.ty.sty, &callee.data) {
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index d5828f7c56c..b0c7d26c47e 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -371,7 +371,6 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
                 _ => bug!("spread argument isn't a tuple?!")
             };
 
-            let lltuplety = type_of::type_of(bcx.ccx(), arg_ty);
             let lltemp = bcx.with_block(|bcx| {
                 base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index))
             });
@@ -391,27 +390,20 @@ fn arg_local_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
                 } else {
                     arg.store_fn_arg(bcx, &mut llarg_idx, dst);
                 }
-
-                bcx.with_block(|bcx| arg_scope.map(|scope| {
-                    let byte_offset_of_var_in_tuple =
-                        machine::llelement_offset(bcx.ccx(), lltuplety, i);
-
-                    let ops = unsafe {
-                        [llvm::LLVMRustDIBuilderCreateOpDeref(),
-                         llvm::LLVMRustDIBuilderCreateOpPlus(),
-                         byte_offset_of_var_in_tuple as i64]
-                    };
-
-                    let variable_access = VariableAccess::IndirectVariable {
-                        alloca: lltemp,
-                        address_operations: &ops
-                    };
-                    declare_local(bcx, keywords::Invalid.name(),
-                                  tupled_arg_ty, scope, variable_access,
-                                  VariableKind::ArgumentVariable(arg_index + i + 1),
-                                  bcx.fcx().span.unwrap_or(DUMMY_SP));
-                }));
             }
+
+            // Now that we have one alloca that contains the aggregate value,
+            // we can create one debuginfo entry for the argument.
+            bcx.with_block(|bcx| arg_scope.map(|scope| {
+                let variable_access = VariableAccess::DirectVariable {
+                    alloca: lltemp
+                };
+                declare_local(bcx, arg_decl.name.unwrap_or(keywords::Invalid.name()),
+                              arg_ty, scope, variable_access,
+                              VariableKind::ArgumentVariable(arg_index + 1),
+                              bcx.fcx().span.unwrap_or(DUMMY_SP));
+            }));
+
             return LocalRef::Lvalue(LvalueRef::new_sized(lltemp, LvalueTy::from_ty(arg_ty)));
         }
 
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 5c7cbbbd88d..6c317eb9948 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -28,7 +28,6 @@ use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::subst::Substs;
 use rustc_const_eval::fatal_const_eval_err;
-use std::hash::{Hash, Hasher};
 use syntax::ast::{self, NodeId};
 use syntax::attr;
 use type_of;
@@ -36,33 +35,13 @@ use glue;
 use abi::{Abi, FnType};
 use back::symbol_names;
 
-#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
 pub enum TransItem<'tcx> {
     DropGlue(DropGlueKind<'tcx>),
     Fn(Instance<'tcx>),
     Static(NodeId)
 }
 
-impl<'tcx> Hash for TransItem<'tcx> {
-    fn hash<H: Hasher>(&self, s: &mut H) {
-        match *self {
-            TransItem::DropGlue(t) => {
-                0u8.hash(s);
-                t.hash(s);
-            },
-            TransItem::Fn(instance) => {
-                1u8.hash(s);
-                instance.def.hash(s);
-                (instance.substs as *const _ as usize).hash(s);
-            }
-            TransItem::Static(node_id) => {
-                2u8.hash(s);
-                node_id.hash(s);
-            }
-        };
-    }
-}
-
 impl<'a, 'tcx> TransItem<'tcx> {
 
     pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
@@ -359,7 +338,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
             TransItem::Fn(instance) => {
                 format!("Fn({:?}, {})",
                          instance.def,
-                         instance.substs as *const _ as usize)
+                         instance.substs.as_ptr() as usize)
             }
             TransItem::Static(id) => {
                 format!("Static({:?})", id)
@@ -473,7 +452,7 @@ pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             output.push_str("fn(");
 
-            let sig = tcx.erase_late_bound_regions(sig);
+            let sig = tcx.erase_late_bound_regions_and_normalize(sig);
             if !sig.inputs.is_empty() {
                 for &parameter_type in &sig.inputs {
                     push_unique_type_name(tcx, parameter_type, output);
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 8183639ae22..132b0a910b9 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -264,8 +264,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
 
       ty::TyFnDef(..) => Type::nil(cx),
       ty::TyFnPtr(f) => {
-        let sig = cx.tcx().erase_late_bound_regions(&f.sig);
-        let sig = cx.tcx().normalize_associated_type(&sig);
+        let sig = cx.tcx().erase_late_bound_regions_and_normalize(&f.sig);
         FnType::new(cx, f.abi, &sig, &[]).llvm_type(cx).ptr_to()
       }
       ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index eebb5c6af6f..d58b8f083e2 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -55,7 +55,7 @@ use hir::def_id::DefId;
 use hir::print as pprust;
 use middle::resolve_lifetime as rl;
 use rustc::lint;
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, ToPredicate, TypeFoldable};
 use rustc::ty::wf::object_region_bounds;
@@ -124,7 +124,7 @@ pub trait AstConv<'gcx, 'tcx> {
     /// Same as ty_infer, but with a known type parameter definition.
     fn ty_infer_for_def(&self,
                         _def: &ty::TypeParameterDef<'tcx>,
-                        _substs: &Substs<'tcx>,
+                        _substs: &[Kind<'tcx>],
                         span: Span) -> Ty<'tcx> {
         self.ty_infer(span)
     }
@@ -629,7 +629,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
     fn convert_parenthesized_parameters(&self,
                                         rscope: &RegionScope,
-                                        region_substs: &Substs<'tcx>,
+                                        region_substs: &[Kind<'tcx>],
                                         data: &hir::ParenthesizedParameterData)
                                         -> (Ty<'tcx>, ConvertedBinding<'tcx>)
     {
@@ -1441,7 +1441,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
     fn ast_ty_arg_to_ty(&self,
                         rscope: &RegionScope,
                         def: Option<&ty::TypeParameterDef<'tcx>>,
-                        region_substs: &Substs<'tcx>,
+                        region_substs: &[Kind<'tcx>],
                         ast_ty: &hir::Ty)
                         -> Ty<'tcx>
     {
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 155a858c1bb..2224b747210 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -87,7 +87,7 @@ use hir::def::{Def, CtorKind, PathResolution};
 use hir::def_id::{DefId, LOCAL_CRATE};
 use hir::pat_util;
 use rustc::infer::{self, InferCtxt, InferOk, TypeOrigin, TypeTrace, type_variable};
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::traits::{self, Reveal};
 use rustc::ty::{ParamTy, ParameterEnvironment};
 use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
@@ -1361,7 +1361,7 @@ impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
 
     fn ty_infer_for_def(&self,
                         ty_param_def: &ty::TypeParameterDef<'tcx>,
-                        substs: &Substs<'tcx>,
+                        substs: &[Kind<'tcx>],
                         span: Span) -> Ty<'tcx> {
         self.type_var_for_def(span, ty_param_def, substs)
     }
@@ -1458,7 +1458,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    pub fn param_env(&self) -> &ty::ParameterEnvironment<'tcx> {
+    pub fn param_env(&self) -> &ty::ParameterEnvironment<'gcx> {
         &self.parameter_environment
     }
 
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index 1f34cee5143..cb9b162cabe 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -82,7 +82,7 @@ This API is completely unstable and subject to change.
 #![feature(rustc_diagnostic_macros)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 
 #[macro_use] extern crate log;
 #[macro_use] extern crate syntax;
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index 2ecb071fcc2..d78f00497ca 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -11,64 +11,79 @@
 use std::fs::File;
 use std::io::prelude::*;
 use std::io;
-use std::path::{PathBuf, Path};
+use std::path::Path;
 use std::str;
 
 #[derive(Clone)]
 pub struct ExternalHtml{
+    /// Content that will be included inline in the <head> section of a
+    /// rendered Markdown file or generated documentation
     pub in_header: String,
+    /// Content that will be included inline between <body> and the content of
+    /// a rendered Markdown file or generated documentation
     pub before_content: String,
+    /// Content that will be included inline between the content and </body> of
+    /// a rendered Markdown file or generated documentation
     pub after_content: String
 }
 
 impl ExternalHtml {
     pub fn load(in_header: &[String], before_content: &[String], after_content: &[String])
             -> Option<ExternalHtml> {
-        match (load_external_files(in_header),
-               load_external_files(before_content),
-               load_external_files(after_content)) {
-            (Some(ih), Some(bc), Some(ac)) => Some(ExternalHtml {
-                in_header: ih,
-                before_content: bc,
-                after_content: ac
-            }),
-            _ => None
-        }
+        load_external_files(in_header)
+            .and_then(|ih|
+                load_external_files(before_content)
+                    .map(|bc| (ih, bc))
+            )
+            .and_then(|(ih, bc)|
+                load_external_files(after_content)
+                    .map(|ac| (ih, bc, ac))
+            )
+            .map(|(ih, bc, ac)|
+                ExternalHtml {
+                    in_header: ih,
+                    before_content: bc,
+                    after_content: ac,
+                }
+            )
     }
 }
 
-pub fn load_string(input: &Path) -> io::Result<Option<String>> {
-    let mut f = File::open(input)?;
-    let mut d = Vec::new();
-    f.read_to_end(&mut d)?;
-    Ok(str::from_utf8(&d).map(|s| s.to_string()).ok())
+pub enum LoadStringError {
+    ReadFail,
+    BadUtf8,
 }
 
-macro_rules! load_or_return {
-    ($input: expr, $cant_read: expr, $not_utf8: expr) => {
-        {
-            let input = PathBuf::from(&$input[..]);
-            match ::externalfiles::load_string(&input) {
-                Err(e) => {
-                    let _ = writeln!(&mut io::stderr(),
-                                     "error reading `{}`: {}", input.display(), e);
-                    return $cant_read;
-                }
-                Ok(None) => {
-                    let _ = writeln!(&mut io::stderr(),
-                                     "error reading `{}`: not UTF-8", input.display());
-                    return $not_utf8;
-                }
-                Ok(Some(s)) => s
-            }
+pub fn load_string<P: AsRef<Path>>(file_path: P) -> Result<String, LoadStringError> {
+    let file_path = file_path.as_ref();
+    let mut contents = vec![];
+    let result = File::open(file_path)
+                      .and_then(|mut f| f.read_to_end(&mut contents));
+    if let Err(e) = result {
+        let _ = writeln!(&mut io::stderr(),
+                         "error reading `{}`: {}",
+                         file_path.display(), e);
+        return Err(LoadStringError::ReadFail);
+    }
+    match str::from_utf8(&contents) {
+        Ok(s) => Ok(s.to_string()),
+        Err(_) => {
+            let _ = writeln!(&mut io::stderr(),
+                             "error reading `{}`: not UTF-8",
+                             file_path.display());
+            Err(LoadStringError::BadUtf8)
         }
     }
 }
 
-pub fn load_external_files(names: &[String]) -> Option<String> {
+fn load_external_files(names: &[String]) -> Option<String> {
     let mut out = String::new();
     for name in names {
-        out.push_str(&*load_or_return!(&name, None, None));
+        let s = match load_string(name) {
+            Ok(s) => s,
+            Err(_) => return None,
+        };
+        out.push_str(&s);
         out.push('\n');
     }
     Some(out)
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index 881352cb73e..d1fe7853445 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -104,6 +104,7 @@ pub enum Class {
     Lifetime,
     PreludeTy,
     PreludeVal,
+    QuestionMark,
 }
 
 /// Trait that controls writing the output of syntax highlighting. Users should
@@ -237,8 +238,10 @@ impl<'a> Classifier<'a> {
             token::Dot | token::DotDot | token::DotDotDot | token::Comma | token::Semi |
                 token::Colon | token::ModSep | token::LArrow | token::OpenDelim(_) |
                 token::CloseDelim(token::Brace) | token::CloseDelim(token::Paren) |
-                token::CloseDelim(token::NoDelim) |
-                token::Question => Class::None,
+                token::CloseDelim(token::NoDelim) => Class::None,
+
+            token::Question => Class::QuestionMark,
+
             token::Dollar => {
                 if self.lexer.peek().tok.is_ident() {
                     self.in_macro_nonterminal = true;
@@ -348,6 +351,7 @@ impl Class {
             Class::Lifetime => "lifetime",
             Class::PreludeTy => "prelude-ty",
             Class::PreludeVal => "prelude-val",
+            Class::QuestionMark => "question-mark"
         }
     }
 }
diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs
index b7c5876c4f9..5353642e294 100644
--- a/src/librustdoc/html/layout.rs
+++ b/src/librustdoc/html/layout.rs
@@ -19,7 +19,6 @@ pub struct Layout {
     pub favicon: String,
     pub external_html: ExternalHtml,
     pub krate: String,
-    pub playground_url: String,
 }
 
 pub struct Page<'a> {
@@ -136,11 +135,9 @@ r##"<!DOCTYPE html>
     <script>
         window.rootPath = "{root_path}";
         window.currentCrate = "{krate}";
-        window.playgroundUrl = "{play_url}";
     </script>
     <script src="{root_path}jquery.js"></script>
     <script src="{root_path}main.js"></script>
-    {play_js}
     <script defer src="{root_path}search-index.js"></script>
 </body>
 </html>"##,
@@ -174,12 +171,6 @@ r##"<!DOCTYPE html>
     after_content = layout.external_html.after_content,
     sidebar   = *sidebar,
     krate     = layout.krate,
-    play_url  = layout.playground_url,
-    play_js   = if layout.playground_url.is_empty() {
-        format!(r#"<script src="{}extra.js"></script>"#, page.root_path)
-    } else {
-        format!(r#"<script src="{}playpen.js"></script>"#, page.root_path)
-    }
     )
 }
 
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index e9a1f650c9b..f12349e5b7c 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -31,7 +31,7 @@ use std::ascii::AsciiExt;
 use std::cell::RefCell;
 use std::default::Default;
 use std::ffi::CString;
-use std::fmt;
+use std::fmt::{self, Write};
 use std::slice;
 use std::str;
 use syntax::feature_gate::UnstableFeatures;
@@ -214,7 +214,9 @@ fn collapse_whitespace(s: &str) -> String {
     s.split_whitespace().collect::<Vec<_>>().join(" ")
 }
 
-thread_local!(pub static PLAYGROUND_KRATE: RefCell<Option<Option<String>>> = {
+// Information about the playground if a URL has been specified, containing an
+// optional crate name and the URL.
+thread_local!(pub static PLAYGROUND: RefCell<Option<(Option<String>, String)>> = {
     RefCell::new(None)
 });
 
@@ -248,24 +250,53 @@ pub fn render(w: &mut fmt::Formatter, s: &str, print_toc: bool) -> fmt::Result {
             });
             let text = lines.collect::<Vec<&str>>().join("\n");
             if rendered { return }
-            PLAYGROUND_KRATE.with(|krate| {
+            PLAYGROUND.with(|play| {
                 // insert newline to clearly separate it from the
                 // previous block so we can shorten the html output
                 let mut s = String::from("\n");
-                krate.borrow().as_ref().map(|krate| {
+                let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| {
+                    if url.is_empty() {
+                        return None;
+                    }
                     let test = origtext.lines().map(|l| {
                         stripped_filtered_line(l).unwrap_or(l)
                     }).collect::<Vec<&str>>().join("\n");
                     let krate = krate.as_ref().map(|s| &**s);
                     let test = test::maketest(&test, krate, false,
                                               &Default::default());
-                    s.push_str(&format!("<span class='rusttest'>{}</span>", Escape(&test)));
+                    let channel = if test.contains("#![feature(") {
+                        "&amp;version=nightly"
+                    } else {
+                        ""
+                    };
+                    // These characters don't need to be escaped in a URI.
+                    // FIXME: use a library function for percent encoding.
+                    fn dont_escape(c: u8) -> bool {
+                        (b'a' <= c && c <= b'z') ||
+                        (b'A' <= c && c <= b'Z') ||
+                        (b'0' <= c && c <= b'9') ||
+                        c == b'-' || c == b'_' || c == b'.' ||
+                        c == b'~' || c == b'!' || c == b'\'' ||
+                        c == b'(' || c == b')' || c == b'*'
+                    }
+                    let mut test_escaped = String::new();
+                    for b in test.bytes() {
+                        if dont_escape(b) {
+                            test_escaped.push(char::from(b));
+                        } else {
+                            write!(test_escaped, "%{:02X}", b).unwrap();
+                        }
+                    }
+                    Some(format!(
+                        r#"<a class="test-arrow" target="_blank" href="{}?code={}{}">Run</a>"#,
+                        url, test_escaped, channel
+                    ))
                 });
                 s.push_str(&highlight::render_with_highlighting(
                                &text,
                                Some("rust-example-rendered"),
                                None,
-                               Some("<a class='test-arrow' target='_blank' href=''>Run</a>")));
+                               playground_button.as_ref().map(String::as_str)));
                 let output = CString::new(s).unwrap();
                 hoedown_buffer_puts(ob, output.as_ptr());
             })
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index d8dba00e7d5..77a5ff3243a 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -449,7 +449,6 @@ pub fn run(mut krate: clean::Crate,
             favicon: "".to_string(),
             external_html: external_html.clone(),
             krate: krate.name.clone(),
-            playground_url: "".to_string(),
         },
         css_file_extension: css_file_extension.clone(),
     };
@@ -469,11 +468,10 @@ pub fn run(mut krate: clean::Crate,
                 }
                 clean::NameValue(ref x, ref s)
                         if "html_playground_url" == *x => {
-                    scx.layout.playground_url = s.to_string();
-                    markdown::PLAYGROUND_KRATE.with(|slot| {
+                    markdown::PLAYGROUND.with(|slot| {
                         if slot.borrow().is_none() {
                             let name = krate.name.clone();
-                            *slot.borrow_mut() = Some(Some(name));
+                            *slot.borrow_mut() = Some((Some(name), s.clone()));
                         }
                     });
                 }
@@ -659,8 +657,6 @@ fn write_shared(cx: &Context,
           include_bytes!("static/jquery-2.1.4.min.js"))?;
     write(cx.dst.join("main.js"),
           include_bytes!("static/main.js"))?;
-    write(cx.dst.join("playpen.js"),
-          include_bytes!("static/playpen.js"))?;
     write(cx.dst.join("rustdoc.css"),
           include_bytes!("static/rustdoc.css"))?;
     write(cx.dst.join("main.css"),
diff --git a/src/librustdoc/html/static/extra.js b/src/librustdoc/html/static/extra.js
deleted file mode 100644
index d9d97d9b883..00000000000
--- a/src/librustdoc/html/static/extra.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 2014-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.
-
-/*jslint browser: true, es5: true */
-/*globals $: true, rootPath: true */
-
-document.addEventListener('DOMContentLoaded', function() {
-    'use strict';
-
-    if (!window.playgroundUrl) {
-        var runButtons = document.querySelectorAll(".test-arrow");
-
-        for (var i = 0; i < runButtons.length; i++) {
-            runButtons[i].classList.remove("test-arrow");
-        }
-        return;
-    }
-});
diff --git a/src/librustdoc/html/static/playpen.js b/src/librustdoc/html/static/playpen.js
deleted file mode 100644
index 8d8953d56e1..00000000000
--- a/src/librustdoc/html/static/playpen.js
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-/*jslint browser: true, es5: true */
-/*globals $: true, rootPath: true */
-
-document.addEventListener('DOMContentLoaded', function() {
-    'use strict';
-
-    if (!window.playgroundUrl) {
-        var runButtons = document.querySelectorAll(".test-arrow");
-
-        for (var i = 0; i < runButtons.length; i++) {
-            runButtons[i].classList.remove("test-arrow");
-        }
-        return;
-    }
-
-    var featureRegexp = new RegExp('^\s*#!\\[feature\\(\.*?\\)\\]');
-    var elements = document.querySelectorAll('pre.rust-example-rendered');
-
-    Array.prototype.forEach.call(elements, function(el) {
-        el.onmouseover = function(e) {
-            if (el.contains(e.relatedTarget)) {
-                return;
-            }
-
-            var a = el.querySelectorAll('a.test-arrow')[0];
-
-            var code = el.previousElementSibling.textContent;
-
-            var channel = '';
-            if (featureRegexp.test(code)) {
-                channel = '&version=nightly';
-            }
-
-            a.setAttribute('href', window.playgroundUrl + '?code=' +
-                           encodeURIComponent(code) + channel);
-        };
-    });
-});
diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css
index f8133ea49ce..f49b8556f66 100644
--- a/src/librustdoc/html/static/rustdoc.css
+++ b/src/librustdoc/html/static/rustdoc.css
@@ -570,8 +570,11 @@ pre.rust .self, pre.rust .bool-val, pre.rust .prelude-val,
 pre.rust .attribute, pre.rust .attribute .ident { color: #C82829; }
 pre.rust .macro, pre.rust .macro-nonterminal { color: #3E999F; }
 pre.rust .lifetime { color: #B76514; }
+pre.rust .question-mark {
+    color: #ff9011;
+    font-weight: bold;
+}
 
-.rusttest { display: none; }
 pre.rust { position: relative; }
 a.test-arrow {
     background-color: rgba(78, 139, 202, 0.2);
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 006dda7d661..0be36eb3a85 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -28,7 +28,7 @@
 #![feature(staged_api)]
 #![feature(test)]
 #![feature(unicode)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 
 extern crate arena;
 extern crate getopts;
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 1421a3c78fc..b617acfabbb 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -19,7 +19,7 @@ use testing;
 use rustc::session::search_paths::SearchPaths;
 use rustc::session::config::Externs;
 
-use externalfiles::ExternalHtml;
+use externalfiles::{ExternalHtml, LoadStringError, load_string};
 
 use html::render::reset_ids;
 use html::escape::Escape;
@@ -58,12 +58,14 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
         css.push_str(&s)
     }
 
-    let input_str = load_or_return!(input, 1, 2);
-    let playground = matches.opt_str("markdown-playground-url");
-    if playground.is_some() {
-        markdown::PLAYGROUND_KRATE.with(|s| { *s.borrow_mut() = Some(None); });
+    let input_str = match load_string(input) {
+        Ok(s) => s,
+        Err(LoadStringError::ReadFail) => return 1,
+        Err(LoadStringError::BadUtf8) => return 2,
+    };
+    if let Some(playground) = matches.opt_str("markdown-playground-url") {
+        markdown::PLAYGROUND.with(|s| { *s.borrow_mut() = Some((None, playground)); });
     }
-    let playground = playground.unwrap_or("".to_string());
 
     let mut out = match File::create(&output) {
         Err(e) => {
@@ -115,9 +117,6 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
     {before_content}
     <h1 class="title">{title}</h1>
     {text}
-    <script type="text/javascript">
-        window.playgroundUrl = "{playground}";
-    </script>
     {after_content}
 </body>
 </html>"#,
@@ -127,7 +126,6 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
         before_content = external_html.before_content,
         text = rendered,
         after_content = external_html.after_content,
-        playground = playground,
         );
 
     match err {
@@ -144,7 +142,11 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
 /// Run any tests/code examples in the markdown file `input`.
 pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
             mut test_args: Vec<String>) -> isize {
-    let input_str = load_or_return!(input, 1, 2);
+    let input_str = match load_string(input) {
+        Ok(s) => s,
+        Err(LoadStringError::ReadFail) => return 1,
+        Err(LoadStringError::BadUtf8) => return 2,
+    };
 
     let mut opts = TestOptions::default();
     opts.no_crate_inject = true;
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index 15fdb0341cb..d1d2b14806f 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -355,7 +355,7 @@ pub fn maketest(s: &str, cratename: Option<&str>, dont_insert_main: bool,
     if dont_insert_main || s.contains("fn main") {
         prog.push_str(&everything_else);
     } else {
-        prog.push_str("fn main() {\n    ");
+        prog.push_str("fn main() {\n");
         prog.push_str(&everything_else);
         prog = prog.trim().into();
         prog.push_str("\n}");
diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs
index 5e25c61bae9..3e976c90628 100644
--- a/src/libserialize/json.rs
+++ b/src/libserialize/json.rs
@@ -199,6 +199,7 @@ use self::DecoderError::*;
 use self::ParserState::*;
 use self::InternalStackElement::*;
 
+use std::borrow::Cow;
 use std::collections::{HashMap, BTreeMap};
 use std::io::prelude::*;
 use std::io;
@@ -2081,9 +2082,7 @@ impl Decoder {
     pub fn new(json: Json) -> Decoder {
         Decoder { stack: vec![json] }
     }
-}
 
-impl Decoder {
     fn pop(&mut self) -> Json {
         self.stack.pop().unwrap()
     }
@@ -2182,8 +2181,8 @@ impl ::Decoder for Decoder {
         Err(ExpectedError("single character string".to_owned(), format!("{}", s)))
     }
 
-    fn read_str(&mut self) -> DecodeResult<string::String> {
-        expect!(self.pop(), String)
+    fn read_str(&mut self) -> DecodeResult<Cow<str>> {
+        expect!(self.pop(), String).map(Cow::Owned)
     }
 
     fn read_enum<T, F>(&mut self, _name: &str, f: F) -> DecodeResult<T> where
diff --git a/src/libserialize/leb128.rs b/src/libserialize/leb128.rs
index 0c5356c0222..8e8e03f1f8e 100644
--- a/src/libserialize/leb128.rs
+++ b/src/libserialize/leb128.rs
@@ -38,6 +38,7 @@ pub fn write_unsigned_leb128(out: &mut Vec<u8>, start_position: usize, mut value
     return position - start_position;
 }
 
+#[inline]
 pub fn read_unsigned_leb128(data: &[u8], start_position: usize) -> (u64, usize) {
     let mut result = 0;
     let mut shift = 0;
@@ -78,6 +79,7 @@ pub fn write_signed_leb128(out: &mut Vec<u8>, start_position: usize, mut value:
     return position - start_position;
 }
 
+#[inline]
 pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i64, usize) {
     let mut result = 0;
     let mut shift = 0;
diff --git a/src/libserialize/lib.rs b/src/libserialize/lib.rs
index 7cb02e2412c..884f24ddc4c 100644
--- a/src/libserialize/lib.rs
+++ b/src/libserialize/lib.rs
@@ -35,7 +35,7 @@ Core encoding and decoding interfaces.
 #![feature(specialization)]
 #![feature(staged_api)]
 #![feature(unicode)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![cfg_attr(test, feature(test))]
 
 // test harness access
diff --git a/src/libserialize/opaque.rs b/src/libserialize/opaque.rs
index e97834f63ce..87b6ed2ed40 100644
--- a/src/libserialize/opaque.rs
+++ b/src/libserialize/opaque.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 use leb128::{read_signed_leb128, read_unsigned_leb128, write_signed_leb128, write_unsigned_leb128};
+use std::borrow::Cow;
 use std::io::{self, Write};
 use serialize;
 
@@ -178,79 +179,95 @@ macro_rules! read_sleb128 {
 impl<'a> serialize::Decoder for Decoder<'a> {
     type Error = String;
 
+    #[inline]
     fn read_nil(&mut self) -> Result<(), Self::Error> {
         Ok(())
     }
 
+    #[inline]
     fn read_u64(&mut self) -> Result<u64, Self::Error> {
         read_uleb128!(self, u64)
     }
 
+    #[inline]
     fn read_u32(&mut self) -> Result<u32, Self::Error> {
         read_uleb128!(self, u32)
     }
 
+    #[inline]
     fn read_u16(&mut self) -> Result<u16, Self::Error> {
         read_uleb128!(self, u16)
     }
 
+    #[inline]
     fn read_u8(&mut self) -> Result<u8, Self::Error> {
         let value = self.data[self.position];
         self.position += 1;
         Ok(value)
     }
 
+    #[inline]
     fn read_usize(&mut self) -> Result<usize, Self::Error> {
         read_uleb128!(self, usize)
     }
 
+    #[inline]
     fn read_i64(&mut self) -> Result<i64, Self::Error> {
         read_sleb128!(self, i64)
     }
 
+    #[inline]
     fn read_i32(&mut self) -> Result<i32, Self::Error> {
         read_sleb128!(self, i32)
     }
 
+    #[inline]
     fn read_i16(&mut self) -> Result<i16, Self::Error> {
         read_sleb128!(self, i16)
     }
 
+    #[inline]
     fn read_i8(&mut self) -> Result<i8, Self::Error> {
         let as_u8 = self.data[self.position];
         self.position += 1;
         unsafe { Ok(::std::mem::transmute(as_u8)) }
     }
 
+    #[inline]
     fn read_isize(&mut self) -> Result<isize, Self::Error> {
         read_sleb128!(self, isize)
     }
 
+    #[inline]
     fn read_bool(&mut self) -> Result<bool, Self::Error> {
         let value = self.read_u8()?;
         Ok(value != 0)
     }
 
+    #[inline]
     fn read_f64(&mut self) -> Result<f64, Self::Error> {
         let bits = self.read_u64()?;
         Ok(unsafe { ::std::mem::transmute(bits) })
     }
 
+    #[inline]
     fn read_f32(&mut self) -> Result<f32, Self::Error> {
         let bits = self.read_u32()?;
         Ok(unsafe { ::std::mem::transmute(bits) })
     }
 
+    #[inline]
     fn read_char(&mut self) -> Result<char, Self::Error> {
         let bits = self.read_u32()?;
         Ok(::std::char::from_u32(bits).unwrap())
     }
 
-    fn read_str(&mut self) -> Result<String, Self::Error> {
+    #[inline]
+    fn read_str(&mut self) -> Result<Cow<str>, Self::Error> {
         let len = self.read_usize()?;
         let s = ::std::str::from_utf8(&self.data[self.position..self.position + len]).unwrap();
         self.position += len;
-        Ok(s.to_string())
+        Ok(Cow::Borrowed(s))
     }
 
     fn error(&mut self, err: &str) -> Self::Error {
diff --git a/src/libserialize/serialize.rs b/src/libserialize/serialize.rs
index 6650a981884..c4613c661a8 100644
--- a/src/libserialize/serialize.rs
+++ b/src/libserialize/serialize.rs
@@ -14,6 +14,7 @@
 Core encoding and decoding interfaces.
 */
 
+use std::borrow::Cow;
 use std::intrinsics;
 use std::path;
 use std::rc::Rc;
@@ -156,7 +157,7 @@ pub trait Decoder {
     fn read_f64(&mut self) -> Result<f64, Self::Error>;
     fn read_f32(&mut self) -> Result<f32, Self::Error>;
     fn read_char(&mut self) -> Result<char, Self::Error>;
-    fn read_str(&mut self) -> Result<String, Self::Error>;
+    fn read_str(&mut self) -> Result<Cow<str>, Self::Error>;
 
     // Compound types:
     fn read_enum<T, F>(&mut self, _name: &str, f: F) -> Result<T, Self::Error>
@@ -401,7 +402,7 @@ impl Encodable for String {
 
 impl Decodable for String {
     fn decode<D: Decoder>(d: &mut D) -> Result<String, D::Error> {
-        d.read_str()
+        Ok(d.read_str()?.into_owned())
     }
 }
 
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index b12f132a3a9..b357bc3552a 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -24,10 +24,10 @@ use self::BucketState::*;
 const EMPTY_BUCKET: u64 = 0;
 
 /// The raw hashtable, providing safe-ish access to the unzipped and highly
-/// optimized arrays of hashes, keys, and values.
+/// optimized arrays of hashes, and key-value pairs.
 ///
-/// This design uses less memory and is a lot faster than the naive
-/// `Vec<Option<u64, K, V>>`, because we don't pay for the overhead of an
+/// This design is a lot faster than the naive
+/// `Vec<Option<(u64, K, V)>>`, because we don't pay for the overhead of an
 /// option on every element, and we get a generally more cache-aware design.
 ///
 /// Essential invariants of this structure:
@@ -48,17 +48,19 @@ const EMPTY_BUCKET: u64 = 0;
 ///     which will likely map to the same bucket, while not being confused
 ///     with "empty".
 ///
-///   - All three "arrays represented by pointers" are the same length:
+///   - Both "arrays represented by pointers" are the same length:
 ///     `capacity`. This is set at creation and never changes. The arrays
-///     are unzipped to save space (we don't have to pay for the padding
-///     between odd sized elements, such as in a map from u64 to u8), and
-///     be more cache aware (scanning through 8 hashes brings in at most
-///     2 cache lines, since they're all right beside each other).
+///     are unzipped and are more cache aware (scanning through 8 hashes
+///     brings in at most 2 cache lines, since they're all right beside each
+///     other). This layout may waste space in padding such as in a map from
+///     u64 to u8, but is a more cache conscious layout as the key-value pairs
+///     are only very shortly probed and the desired value will be in the same
+///     or next cache line.
 ///
 /// You can kind of think of this module/data structure as a safe wrapper
 /// around just the "table" part of the hashtable. It enforces some
 /// invariants at the type level and employs some performance trickery,
-/// but in general is just a tricked out `Vec<Option<u64, K, V>>`.
+/// but in general is just a tricked out `Vec<Option<(u64, K, V)>>`.
 pub struct RawTable<K, V> {
     capacity: usize,
     size: usize,
@@ -74,10 +76,8 @@ unsafe impl<K: Sync, V: Sync> Sync for RawTable<K, V> {}
 
 struct RawBucket<K, V> {
     hash: *mut u64,
-
     // We use *const to ensure covariance with respect to K and V
-    key: *const K,
-    val: *const V,
+    pair: *const (K, V),
     _marker: marker::PhantomData<(K, V)>,
 }
 
@@ -181,8 +181,7 @@ impl<K, V> RawBucket<K, V> {
     unsafe fn offset(self, count: isize) -> RawBucket<K, V> {
         RawBucket {
             hash: self.hash.offset(count),
-            key: self.key.offset(count),
-            val: self.val.offset(count),
+            pair: self.pair.offset(count),
             _marker: marker::PhantomData,
         }
     }
@@ -370,8 +369,7 @@ impl<K, V, M> EmptyBucket<K, V, M>
     pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket<K, V, M> {
         unsafe {
             *self.raw.hash = hash.inspect();
-            ptr::write(self.raw.key as *mut K, key);
-            ptr::write(self.raw.val as *mut V, value);
+            ptr::write(self.raw.pair as *mut (K, V), (key, value));
 
             self.table.borrow_table_mut().size += 1;
         }
@@ -430,7 +428,7 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> {
 
     /// Gets references to the key and value at a given index.
     pub fn read(&self) -> (&K, &V) {
-        unsafe { (&*self.raw.key, &*self.raw.val) }
+        unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) }
     }
 }
 
@@ -447,13 +445,14 @@ impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> {
 
         unsafe {
             *self.raw.hash = EMPTY_BUCKET;
+            let (k, v) = ptr::read(self.raw.pair);
             (EmptyBucket {
                  raw: self.raw,
                  idx: self.idx,
                  table: self.table,
              },
-             ptr::read(self.raw.key),
-             ptr::read(self.raw.val))
+            k,
+            v)
         }
     }
 }
@@ -466,8 +465,7 @@ impl<K, V, M> FullBucket<K, V, M>
     pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) {
         unsafe {
             let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h);
-            let old_key = ptr::replace(self.raw.key as *mut K, k);
-            let old_val = ptr::replace(self.raw.val as *mut V, v);
+            let (old_key, old_val) = ptr::replace(self.raw.pair as *mut (K, V), (k, v));
 
             (old_hash, old_key, old_val)
         }
@@ -479,7 +477,8 @@ impl<K, V, M> FullBucket<K, V, M>
 {
     /// Gets mutable references to the key and value at a given index.
     pub fn read_mut(&mut self) -> (&mut K, &mut V) {
-        unsafe { (&mut *(self.raw.key as *mut K), &mut *(self.raw.val as *mut V)) }
+        let pair_mut = self.raw.pair as *mut (K, V);
+        unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) }
     }
 }
 
@@ -492,7 +491,7 @@ impl<'t, K, V, M> FullBucket<K, V, M>
     /// in exchange for this, the returned references have a longer lifetime
     /// than the references returned by `read()`.
     pub fn into_refs(self) -> (&'t K, &'t V) {
-        unsafe { (&*self.raw.key, &*self.raw.val) }
+        unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) }
     }
 }
 
@@ -502,7 +501,8 @@ impl<'t, K, V, M> FullBucket<K, V, M>
     /// This works similarly to `into_refs`, exchanging a bucket state
     /// for mutable references into the table.
     pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) {
-        unsafe { (&mut *(self.raw.key as *mut K), &mut *(self.raw.val as *mut V)) }
+        let pair_mut = self.raw.pair as *mut (K, V);
+        unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) }
     }
 }
 
@@ -517,8 +517,7 @@ impl<K, V, M> GapThenFull<K, V, M>
     pub fn shift(mut self) -> Option<GapThenFull<K, V, M>> {
         unsafe {
             *self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET);
-            ptr::copy_nonoverlapping(self.full.raw.key, self.gap.raw.key as *mut K, 1);
-            ptr::copy_nonoverlapping(self.full.raw.val, self.gap.raw.val as *mut V, 1);
+            ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1);
         }
 
         let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full;
@@ -560,49 +559,42 @@ fn test_rounding() {
     assert_eq!(round_up_to_next(5, 4), 8);
 }
 
-// Returns a tuple of (key_offset, val_offset),
+// Returns a tuple of (pairs_offset, end_of_pairs_offset),
 // from the start of a mallocated array.
 #[inline]
 fn calculate_offsets(hashes_size: usize,
-                     keys_size: usize,
-                     keys_align: usize,
-                     vals_align: usize)
+                     pairs_size: usize,
+                     pairs_align: usize)
                      -> (usize, usize, bool) {
-    let keys_offset = round_up_to_next(hashes_size, keys_align);
-    let (end_of_keys, oflo) = keys_offset.overflowing_add(keys_size);
-
-    let vals_offset = round_up_to_next(end_of_keys, vals_align);
+    let pairs_offset = round_up_to_next(hashes_size, pairs_align);
+    let (end_of_pairs, oflo) = pairs_offset.overflowing_add(pairs_size);
 
-    (keys_offset, vals_offset, oflo)
+    (pairs_offset, end_of_pairs, oflo)
 }
 
 // Returns a tuple of (minimum required malloc alignment, hash_offset,
 // array_size), from the start of a mallocated array.
 fn calculate_allocation(hash_size: usize,
                         hash_align: usize,
-                        keys_size: usize,
-                        keys_align: usize,
-                        vals_size: usize,
-                        vals_align: usize)
+                        pairs_size: usize,
+                        pairs_align: usize)
                         -> (usize, usize, usize, bool) {
     let hash_offset = 0;
-    let (_, vals_offset, oflo) = calculate_offsets(hash_size, keys_size, keys_align, vals_align);
-    let (end_of_vals, oflo2) = vals_offset.overflowing_add(vals_size);
+    let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align);
 
-    let align = cmp::max(hash_align, cmp::max(keys_align, vals_align));
+    let align = cmp::max(hash_align, pairs_align);
 
-    (align, hash_offset, end_of_vals, oflo || oflo2)
+    (align, hash_offset, end_of_pairs, oflo)
 }
 
 #[test]
 fn test_offset_calculation() {
-    assert_eq!(calculate_allocation(128, 8, 15, 1, 4, 4),
-               (8, 0, 148, false));
-    assert_eq!(calculate_allocation(3, 1, 2, 1, 1, 1), (1, 0, 6, false));
-    assert_eq!(calculate_allocation(6, 2, 12, 4, 24, 8), (8, 0, 48, false));
-    assert_eq!(calculate_offsets(128, 15, 1, 4), (128, 144, false));
-    assert_eq!(calculate_offsets(3, 2, 1, 1), (3, 5, false));
-    assert_eq!(calculate_offsets(6, 12, 4, 8), (8, 24, false));
+    assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 0, 144, false));
+    assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 0, 5, false));
+    assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 0, 20, false));
+    assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false));
+    assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false));
+    assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false));
 }
 
 impl<K, V> RawTable<K, V> {
@@ -620,11 +612,10 @@ impl<K, V> RawTable<K, V> {
 
         // No need for `checked_mul` before a more restrictive check performed
         // later in this method.
-        let hashes_size = capacity * size_of::<u64>();
-        let keys_size = capacity * size_of::<K>();
-        let vals_size = capacity * size_of::<V>();
+        let hashes_size = capacity.wrapping_mul(size_of::<u64>());
+        let pairs_size = capacity.wrapping_mul(size_of::<(K, V)>());
 
-        // Allocating hashmaps is a little tricky. We need to allocate three
+        // Allocating hashmaps is a little tricky. We need to allocate two
         // arrays, but since we know their sizes and alignments up front,
         // we just allocate a single array, and then have the subarrays
         // point into it.
@@ -632,27 +623,20 @@ impl<K, V> RawTable<K, V> {
         // This is great in theory, but in practice getting the alignment
         // right is a little subtle. Therefore, calculating offsets has been
         // factored out into a different function.
-        let (malloc_alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size,
-                                                                               align_of::<u64>(),
-                                                                               keys_size,
-                                                                               align_of::<K>(),
-                                                                               vals_size,
-                                                                               align_of::<V>());
-
+        let (alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size,
+                                                                        align_of::<u64>(),
+                                                                        pairs_size,
+                                                                        align_of::<(K, V)>());
         assert!(!oflo, "capacity overflow");
 
         // One check for overflow that covers calculation and rounding of size.
-        let size_of_bucket = size_of::<u64>()
-            .checked_add(size_of::<K>())
-            .unwrap()
-            .checked_add(size_of::<V>())
-            .unwrap();
+        let size_of_bucket = size_of::<u64>().checked_add(size_of::<(K, V)>()).unwrap();
         assert!(size >=
                 capacity.checked_mul(size_of_bucket)
                     .expect("capacity overflow"),
                 "capacity overflow");
 
-        let buffer = allocate(size, malloc_alignment);
+        let buffer = allocate(size, alignment);
         if buffer.is_null() {
             ::alloc::oom()
         }
@@ -669,17 +653,16 @@ impl<K, V> RawTable<K, V> {
 
     fn first_bucket_raw(&self) -> RawBucket<K, V> {
         let hashes_size = self.capacity * size_of::<u64>();
-        let keys_size = self.capacity * size_of::<K>();
+        let pairs_size = self.capacity * size_of::<(K, V)>();
 
-        let buffer = *self.hashes as *const u8;
-        let (keys_offset, vals_offset, oflo) =
-            calculate_offsets(hashes_size, keys_size, align_of::<K>(), align_of::<V>());
+        let buffer = *self.hashes as *mut u8;
+        let (pairs_offset, _, oflo) =
+            calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>());
         debug_assert!(!oflo, "capacity overflow");
         unsafe {
             RawBucket {
                 hash: *self.hashes,
-                key: buffer.offset(keys_offset as isize) as *const K,
-                val: buffer.offset(vals_offset as isize) as *const V,
+                pair: buffer.offset(pairs_offset as isize) as *const _,
                 _marker: marker::PhantomData,
             }
         }
@@ -844,7 +827,7 @@ impl<'a, K, V> Iterator for RevMoveBuckets<'a, K, V> {
 
                 if *self.raw.hash != EMPTY_BUCKET {
                     self.elems_left -= 1;
-                    return Some((ptr::read(self.raw.key), ptr::read(self.raw.val)));
+                    return Some(ptr::read(self.raw.pair));
                 }
             }
         }
@@ -909,7 +892,7 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> {
     fn next(&mut self) -> Option<(&'a K, &'a V)> {
         self.iter.next().map(|bucket| {
             self.elems_left -= 1;
-            unsafe { (&*bucket.key, &*bucket.val) }
+            unsafe { (&(*bucket.pair).0, &(*bucket.pair).1) }
         })
     }
 
@@ -929,7 +912,8 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> {
     fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
         self.iter.next().map(|bucket| {
             self.elems_left -= 1;
-            unsafe { (&*bucket.key, &mut *(bucket.val as *mut V)) }
+            let pair_mut = bucket.pair as *mut (K, V);
+            unsafe { (&(*pair_mut).0, &mut (*pair_mut).1) }
         })
     }
 
@@ -950,7 +934,8 @@ impl<K, V> Iterator for IntoIter<K, V> {
         self.iter.next().map(|bucket| {
             self.table.size -= 1;
             unsafe {
-                (SafeHash { hash: *bucket.hash }, ptr::read(bucket.key), ptr::read(bucket.val))
+                let (k, v) = ptr::read(bucket.pair);
+                (SafeHash { hash: *bucket.hash }, k, v)
             }
         })
     }
@@ -974,9 +959,8 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> {
         self.iter.next().map(|bucket| {
             unsafe {
                 (**self.table).size -= 1;
-                (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) },
-                 ptr::read(bucket.key),
-                 ptr::read(bucket.val))
+                let (k, v) = ptr::read(bucket.pair);
+                (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v)
             }
         })
     }
@@ -1015,8 +999,7 @@ impl<K: Clone, V: Clone> Clone for RawTable<K, V> {
                                 (full.hash(), k.clone(), v.clone())
                             };
                             *new_buckets.raw.hash = h.inspect();
-                            ptr::write(new_buckets.raw.key as *mut K, k);
-                            ptr::write(new_buckets.raw.val as *mut V, v);
+                            ptr::write(new_buckets.raw.pair as *mut (K, V), (k, v));
                         }
                         Empty(..) => {
                             *new_buckets.raw.hash = EMPTY_BUCKET;
@@ -1054,14 +1037,11 @@ impl<K, V> Drop for RawTable<K, V> {
         }
 
         let hashes_size = self.capacity * size_of::<u64>();
-        let keys_size = self.capacity * size_of::<K>();
-        let vals_size = self.capacity * size_of::<V>();
+        let pairs_size = self.capacity * size_of::<(K, V)>();
         let (align, _, size, oflo) = calculate_allocation(hashes_size,
                                                           align_of::<u64>(),
-                                                          keys_size,
-                                                          align_of::<K>(),
-                                                          vals_size,
-                                                          align_of::<V>());
+                                                          pairs_size,
+                                                          align_of::<(K, V)>());
 
         debug_assert!(!oflo, "should be impossible");
 
diff --git a/src/libstd/error.rs b/src/libstd/error.rs
index f1f62bc24c5..a1909b0f957 100644
--- a/src/libstd/error.rs
+++ b/src/libstd/error.rs
@@ -55,7 +55,6 @@ use any::TypeId;
 use cell;
 use char;
 use fmt::{self, Debug, Display};
-use marker::Reflect;
 use mem::transmute;
 use num;
 use str;
@@ -63,12 +62,14 @@ use string;
 
 /// Base functionality for all errors in Rust.
 #[stable(feature = "rust1", since = "1.0.0")]
-pub trait Error: Debug + Display + Reflect {
+pub trait Error: Debug + Display {
     /// A short description of the error.
     ///
-    /// The description should not contain newlines or sentence-ending
-    /// punctuation, to facilitate embedding in larger user-facing
-    /// strings.
+    /// The description should only be used for a simple message.
+    /// It should not contain newlines or sentence-ending punctuation,
+    /// to facilitate embedding in larger user-facing strings.
+    /// For showing formatted error messages with more information see
+    /// [Display](https://doc.rust-lang.org/std/fmt/trait.Display.html).
     ///
     /// # Examples
     ///
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index 2f2969b110d..5bb5183fd6a 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -1904,6 +1904,130 @@ mod tests {
     }
 
     #[test]
+    fn file_test_io_eof() {
+        let tmpdir = tmpdir();
+        let filename = tmpdir.join("file_rt_io_file_test_eof.txt");
+        let mut buf = [0; 256];
+        {
+            let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+            let mut rw = check!(oo.open(&filename));
+            assert_eq!(check!(rw.read(&mut buf)), 0);
+            assert_eq!(check!(rw.read(&mut buf)), 0);
+        }
+        check!(fs::remove_file(&filename));
+    }
+
+    #[test]
+    #[cfg(unix)]
+    fn file_test_io_read_write_at() {
+        use os::unix::fs::FileExt;
+
+        let tmpdir = tmpdir();
+        let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt");
+        let mut buf = [0; 256];
+        let write1 = "asdf";
+        let write2 = "qwer-";
+        let write3 = "-zxcv";
+        let content = "qwer-asdf-zxcv";
+        {
+            let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+            let mut rw = check!(oo.open(&filename));
+            assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len());
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
+            assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len());
+            assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
+            assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
+            assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0"));
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0);
+            assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
+            assert_eq!(check!(rw.read(&mut buf)), write1.len());
+            assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+            assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len());
+            assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+            assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len());
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+        }
+        {
+            let mut read = check!(File::open(&filename));
+            assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
+            assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+            assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0);
+            assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
+            assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
+            assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+            assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9);
+            assert_eq!(check!(read.read(&mut buf)), write3.len());
+            assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
+            assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+            assert_eq!(check!(read.read_at(&mut buf, 0)), content.len());
+            assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+            assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+            assert_eq!(check!(read.read_at(&mut buf, 14)), 0);
+            assert_eq!(check!(read.read_at(&mut buf, 15)), 0);
+            assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+        }
+        check!(fs::remove_file(&filename));
+    }
+
+    #[test]
+    #[cfg(windows)]
+    fn file_test_io_seek_read_write() {
+        use os::windows::fs::FileExt;
+
+        let tmpdir = tmpdir();
+        let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt");
+        let mut buf = [0; 256];
+        let write1 = "asdf";
+        let write2 = "qwer-";
+        let write3 = "-zxcv";
+        let content = "qwer-asdf-zxcv";
+        {
+            let oo = OpenOptions::new().create_new(true).write(true).read(true).clone();
+            let mut rw = check!(oo.open(&filename));
+            assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len());
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+            assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len());
+            assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+            assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0);
+            assert_eq!(check!(rw.write(write2.as_bytes())), write2.len());
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
+            assert_eq!(check!(rw.read(&mut buf)), write1.len());
+            assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1));
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9);
+            assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len());
+            assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2));
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5);
+            assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len());
+            assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14);
+        }
+        {
+            let mut read = check!(File::open(&filename));
+            assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
+            assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+            assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+            assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
+            assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
+            assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+            assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+            assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9);
+            assert_eq!(check!(read.read(&mut buf)), write3.len());
+            assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3));
+            assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+            assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len());
+            assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content));
+            assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14);
+            assert_eq!(check!(read.seek_read(&mut buf, 14)), 0);
+            assert_eq!(check!(read.seek_read(&mut buf, 15)), 0);
+        }
+        check!(fs::remove_file(&filename));
+    }
+
+    #[test]
     fn file_test_stat_is_correct_on_is_file() {
         let tmpdir = tmpdir();
         let filename = &tmpdir.join("file_stat_correct_on_is_file.txt");
@@ -2221,8 +2345,8 @@ mod tests {
         check!(fs::set_permissions(&out, attr.permissions()));
     }
 
-    #[cfg(windows)]
     #[test]
+    #[cfg(windows)]
     fn copy_file_preserves_streams() {
         let tmp = tmpdir();
         check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes()));
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index 93b2d34e27f..44dd4e9874a 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -12,7 +12,6 @@
 
 use io::prelude::*;
 
-use marker::Reflect;
 use cmp;
 use error;
 use fmt;
@@ -21,11 +20,15 @@ use memchr;
 
 /// The `BufReader` struct adds buffering to any reader.
 ///
-/// It can be excessively inefficient to work directly with a `Read` instance.
-/// For example, every call to `read` on `TcpStream` results in a system call.
-/// A `BufReader` performs large, infrequent reads on the underlying `Read`
+/// It can be excessively inefficient to work directly with a [`Read`] instance.
+/// For example, every call to [`read`] on [`TcpStream`] results in a system call.
+/// A `BufReader` performs large, infrequent reads on the underlying [`Read`]
 /// and maintains an in-memory buffer of the results.
 ///
+/// [`Read`]: ../../std/io/trait.Read.html
+/// [`read`]: ../../std/net/struct.TcpStream.html#method.read
+/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
+///
 /// # Examples
 ///
 /// ```
@@ -255,7 +258,7 @@ impl<R: Seek> Seek for BufReader<R> {
 /// Wraps a writer and buffers its output.
 ///
 /// It can be excessively inefficient to work directly with something that
-/// implements `Write`. For example, every call to `write` on `TcpStream`
+/// implements [`Write`]. For example, every call to [`write`] on [`TcpStream`]
 /// results in a system call. A `BufWriter` keeps an in-memory buffer of data
 /// and writes it to an underlying writer in large, infrequent batches.
 ///
@@ -263,7 +266,7 @@ impl<R: Seek> Seek for BufReader<R> {
 ///
 /// # Examples
 ///
-/// Let's write the numbers one through ten to a `TcpStream`:
+/// Let's write the numbers one through ten to a [`TcpStream`]:
 ///
 /// ```no_run
 /// use std::io::prelude::*;
@@ -295,6 +298,10 @@ impl<R: Seek> Seek for BufReader<R> {
 /// By wrapping the stream with a `BufWriter`, these ten writes are all grouped
 /// together by the buffer, and will all be written out in one system call when
 /// the `stream` is dropped.
+///
+/// [`Write`]: ../../std/io/trait.Write.html
+/// [`write`]: ../../std/net/struct.TcpStream.html#method.write
+/// [`TcpStream`]: ../../std/net/struct.TcpStream.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufWriter<W: Write> {
     inner: Option<W>,
@@ -578,7 +585,7 @@ impl<W> From<IntoInnerError<W>> for Error {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<W: Reflect + Send + fmt::Debug> error::Error for IntoInnerError<W> {
+impl<W: Send + fmt::Debug> error::Error for IntoInnerError<W> {
     fn description(&self) -> &str {
         error::Error::description(self.error())
     }
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 73105640cd2..14d046ab052 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -12,18 +12,15 @@
 //!
 //! The `std::io` module contains a number of common things you'll need
 //! when doing input and output. The most core part of this module is
-//! the [`Read`][read] and [`Write`][write] traits, which provide the
+//! the [`Read`] and [`Write`] traits, which provide the
 //! most general interface for reading and writing input and output.
 //!
-//! [read]: trait.Read.html
-//! [write]: trait.Write.html
-//!
 //! # Read and Write
 //!
-//! Because they are traits, `Read` and `Write` are implemented by a number
+//! Because they are traits, [`Read`] and [`Write`] are implemented by a number
 //! of other types, and you can implement them for your types too. As such,
 //! you'll see a few different types of I/O throughout the documentation in
-//! this module: `File`s, `TcpStream`s, and sometimes even `Vec<T>`s. For
+//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
 //! example, `Read` adds a `read()` method, which we can use on `File`s:
 //!
 //! ```
@@ -43,15 +40,15 @@
 //! # }
 //! ```
 //!
-//! `Read` and `Write` are so important, implementors of the two traits have a
+//! [`Read`] and [`Write`] are so important, implementors of the two traits have a
 //! nickname: readers and writers. So you'll sometimes see 'a reader' instead
-//! of 'a type that implements the `Read` trait'. Much easier!
+//! of 'a type that implements the [`Read`] trait'. Much easier!
 //!
 //! ## Seek and BufRead
 //!
-//! Beyond that, there are two important traits that are provided: [`Seek`][seek]
-//! and [`BufRead`][bufread]. Both of these build on top of a reader to control
-//! how the reading happens. `Seek` lets you control where the next byte is
+//! Beyond that, there are two important traits that are provided: [`Seek`]
+//! and [`BufRead`]. Both of these build on top of a reader to control
+//! how the reading happens. [`Seek`] lets you control where the next byte is
 //! coming from:
 //!
 //! ```
@@ -75,21 +72,18 @@
 //! # }
 //! ```
 //!
-//! [seek]: trait.Seek.html
-//! [bufread]: trait.BufRead.html
-//!
-//! `BufRead` uses an internal buffer to provide a number of other ways to read, but
+//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but
 //! to show it off, we'll need to talk about buffers in general. Keep reading!
 //!
 //! ## BufReader and BufWriter
 //!
 //! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be
 //! making near-constant calls to the operating system. To help with this,
-//! `std::io` comes with two structs, `BufReader` and `BufWriter`, which wrap
+//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap
 //! readers and writers. The wrapper uses a buffer, reducing the number of
 //! calls and providing nicer methods for accessing exactly what you want.
 //!
-//! For example, `BufReader` works with the `BufRead` trait to add extra
+//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra
 //! methods to any reader:
 //!
 //! ```
@@ -111,8 +105,8 @@
 //! # }
 //! ```
 //!
-//! `BufWriter` doesn't add any new ways of writing; it just buffers every call
-//! to [`write()`][write()]:
+//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
+//! to [`write()`]:
 //!
 //! ```
 //! use std::io;
@@ -134,8 +128,6 @@
 //! # }
 //! ```
 //!
-//! [write()]: trait.Write.html#tymethod.write
-//!
 //! ## Standard input and output
 //!
 //! A very common source of input is standard input:
@@ -165,13 +157,13 @@
 //! # }
 //! ```
 //!
-//! Of course, using `io::stdout()` directly is less common than something like
-//! `println!`.
+//! Of course, using [`io::stdout()`] directly is less common than something like
+//! [`println!`].
 //!
 //! ## Iterator types
 //!
 //! A large number of the structures provided by `std::io` are for various
-//! ways of iterating over I/O. For example, `Lines` is used to split over
+//! ways of iterating over I/O. For example, [`Lines`] is used to split over
 //! lines:
 //!
 //! ```
@@ -211,10 +203,10 @@
 //!
 //! ## io::Result
 //!
-//! Last, but certainly not least, is [`io::Result`][result]. This type is used
+//! Last, but certainly not least, is [`io::Result`]. This type is used
 //! as the return type of many `std::io` functions that can cause an error, and
 //! can be returned from your own functions as well. Many of the examples in this
-//! module use the [`try!`][try] macro:
+//! module use the [`try!`] macro:
 //!
 //! ```
 //! use std::io;
@@ -230,14 +222,11 @@
 //! }
 //! ```
 //!
-//! The return type of `read_input()`, `io::Result<()>`, is a very common type
-//! for functions which don't have a 'real' return value, but do want to return
-//! errors if they happen. In this case, the only purpose of this function is
+//! The return type of `read_input()`, [`io::Result<()>`][`io::Result`], is a very
+//! common type for functions which don't have a 'real' return value, but do want to
+//! return errors if they happen. In this case, the only purpose of this function is
 //! to read the line and print it, so we use `()`.
 //!
-//! [result]: type.Result.html
-//! [try]: ../macro.try.html
-//!
 //! ## Platform-specific behavior
 //!
 //! Many I/O functions throughout the standard library are documented to indicate
@@ -246,6 +235,22 @@
 //! any possibly unclear semantics. Note, however, that this is informative, not a binding
 //! contract. The implementation of many of these functions are subject to change over
 //! time and may call fewer or more syscalls/library functions.
+//!
+//! [`Read`]: trait.Read.html
+//! [`Write`]: trait.Write.html
+//! [`Seek`]: trait.Seek.html
+//! [`BufRead`]: trait.BufRead.html
+//! [`File`]: ../fs/struct.File.html
+//! [`TcpStream`]: ../net/struct.TcpStream.html
+//! [`Vec<T>`]: ../vec/struct.Vec.html
+//! [`BufReader`]: struct.BufReader.html
+//! [`BufWriter`]: struct.BufWriter.html
+//! [`write()`]: trait.Write.html#tymethod.write
+//! [`io::stdout()`]: fn.stdout.html
+//! [`println!`]: ../macro.println.html
+//! [`Lines`]: struct.Lines.html
+//! [`io::Result`]: type.Result.html
+//! [`try!`]: ../macro.try.html
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index eee85798841..c2f6a6f660c 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -255,10 +255,9 @@
 #![feature(panic_unwind)]
 #![feature(placement_in_syntax)]
 #![feature(prelude_import)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![feature(rand)]
 #![feature(raw)]
-#![feature(reflect_marker)]
 #![feature(repr_simd)]
 #![feature(rustc_attrs)]
 #![feature(shared)]
diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs
index 58daa7dbf8d..20dc5b3801b 100644
--- a/src/libstd/net/addr.rs
+++ b/src/libstd/net/addr.rs
@@ -93,6 +93,26 @@ impl SocketAddr {
             SocketAddr::V6(ref mut a) => a.set_port(new_port),
         }
     }
+
+    /// Returns true if the IP in this `SocketAddr` is a valid IPv4 address,
+    /// false if it's a valid IPv6 address.
+    #[unstable(feature = "sockaddr_checker", issue = "36949")]
+    pub fn is_ipv4(&self) -> bool {
+        match *self {
+            SocketAddr::V4(_) => true,
+            SocketAddr::V6(_) => false,
+        }
+    }
+
+    /// Returns true if the IP in this `SocketAddr` is a valid IPv6 address,
+    /// false if it's a valid IPv4 address.
+    #[unstable(feature = "sockaddr_checker", issue = "36949")]
+    pub fn is_ipv6(&self) -> bool {
+        match *self {
+            SocketAddr::V4(_) => false,
+            SocketAddr::V6(_) => true,
+        }
+    }
 }
 
 impl SocketAddrV4 {
@@ -631,4 +651,19 @@ mod tests {
         v6.set_scope_id(20);
         assert_eq!(v6.scope_id(), 20);
     }
+
+    #[test]
+    fn is_v4() {
+        let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80));
+        assert!(v4.is_ipv4());
+        assert!(!v4.is_ipv6());
+    }
+
+    #[test]
+    fn is_v6() {
+        let v6 = SocketAddr::V6(SocketAddrV6::new(
+                Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0));
+        assert!(!v6.is_ipv4());
+        assert!(v6.is_ipv6());
+    }
 }
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
index 6d37f160590..fce640e7c7a 100644
--- a/src/libstd/sync/mpsc/mod.rs
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -270,7 +270,6 @@ use error;
 use fmt;
 use mem;
 use cell::UnsafeCell;
-use marker::Reflect;
 use time::{Duration, Instant};
 
 #[unstable(feature = "mpsc_select", issue = "27800")]
@@ -1163,7 +1162,7 @@ impl<T> fmt::Display for SendError<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send + Reflect> error::Error for SendError<T> {
+impl<T: Send> error::Error for SendError<T> {
     fn description(&self) -> &str {
         "sending on a closed channel"
     }
@@ -1198,7 +1197,7 @@ impl<T> fmt::Display for TrySendError<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Send + Reflect> error::Error for TrySendError<T> {
+impl<T: Send> error::Error for TrySendError<T> {
 
     fn description(&self) -> &str {
         match *self {
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index ad9d0b37544..71e163321ae 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -387,7 +387,7 @@ mod tests {
     #[test]
     fn stampede_once() {
         static O: Once = Once::new();
-        static mut run: bool = false;
+        static mut RUN: bool = false;
 
         let (tx, rx) = channel();
         for _ in 0..10 {
@@ -396,10 +396,10 @@ mod tests {
                 for _ in 0..4 { thread::yield_now() }
                 unsafe {
                     O.call_once(|| {
-                        assert!(!run);
-                        run = true;
+                        assert!(!RUN);
+                        RUN = true;
                     });
-                    assert!(run);
+                    assert!(RUN);
                 }
                 tx.send(()).unwrap();
             });
@@ -407,10 +407,10 @@ mod tests {
 
         unsafe {
             O.call_once(|| {
-                assert!(!run);
-                run = true;
+                assert!(!RUN);
+                RUN = true;
             });
-            assert!(run);
+            assert!(RUN);
         }
 
         for _ in 0..10 {
diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs
index 48ecae185f9..f08b7641521 100644
--- a/src/libstd/sync/rwlock.rs
+++ b/src/libstd/sync/rwlock.rs
@@ -136,6 +136,10 @@ impl<T: ?Sized> RwLock<T> {
     /// This function will return an error if the RwLock is poisoned. An RwLock
     /// is poisoned whenever a writer panics while holding an exclusive lock.
     /// The failure will occur immediately after the lock has been acquired.
+    ///
+    /// # Panics
+    ///
+    /// This function might panic when called if the lock is already held by the current thread.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn read(&self) -> LockResult<RwLockReadGuard<T>> {
@@ -188,6 +192,10 @@ impl<T: ?Sized> RwLock<T> {
     /// This function will return an error if the RwLock is poisoned. An RwLock
     /// is poisoned whenever a writer panics while holding an exclusive lock.
     /// An error will be returned when the lock is acquired.
+    ///
+    /// # Panics
+    ///
+    /// This function might panic when called if the lock is already held by the current thread.
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn write(&self) -> LockResult<RwLockWriteGuard<T>> {
diff --git a/src/libstd/sys/common/poison.rs b/src/libstd/sys/common/poison.rs
index 55212bf35d6..bdc727f1dfc 100644
--- a/src/libstd/sys/common/poison.rs
+++ b/src/libstd/sys/common/poison.rs
@@ -10,7 +10,6 @@
 
 use error::{Error};
 use fmt;
-use marker::Reflect;
 use sync::atomic::{AtomicBool, Ordering};
 use thread;
 
@@ -117,7 +116,7 @@ impl<T> fmt::Display for PoisonError<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Reflect> Error for PoisonError<T> {
+impl<T> Error for PoisonError<T> {
     fn description(&self) -> &str {
         "poisoned lock: another task failed inside"
     }
@@ -174,7 +173,7 @@ impl<T> fmt::Display for TryLockError<T> {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl<T: Reflect> Error for TryLockError<T> {
+impl<T> Error for TryLockError<T> {
     fn description(&self) -> &str {
         match *self {
             TryLockError::Poisoned(ref p) => p.description(),
diff --git a/src/libstd/sys/unix/android.rs b/src/libstd/sys/unix/android.rs
index abbe3fc1846..10436723a81 100644
--- a/src/libstd/sys/unix/android.rs
+++ b/src/libstd/sys/unix/android.rs
@@ -28,10 +28,11 @@
 
 #![cfg(target_os = "android")]
 
-use libc::{c_int, sighandler_t};
+use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
+use libc::{ftruncate, pread, pwrite};
 
 use io;
-use sys::cvt_r;
+use super::{cvt, cvt_r};
 
 // The `log2` and `log2f` functions apparently appeared in android-18, or at
 // least you can see they're not present in the android-17 header [1] and they
@@ -96,13 +97,10 @@ pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t {
 //
 // If it doesn't we just fall back to `ftruncate`, generating an error for
 // too-large values.
+#[cfg(target_pointer_width = "32")]
 pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
     weak!(fn ftruncate64(c_int, i64) -> c_int);
 
-    extern {
-        fn ftruncate(fd: c_int, off: i32) -> c_int;
-    }
-
     unsafe {
         match ftruncate64.get() {
             Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()),
@@ -117,3 +115,56 @@ pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
         }
     }
 }
+
+#[cfg(target_pointer_width = "64")]
+pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
+    unsafe {
+        cvt_r(|| ftruncate(fd, size as i64)).map(|_| ())
+    }
+}
+
+#[cfg(target_pointer_width = "32")]
+pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
+    -> io::Result<ssize_t>
+{
+    use convert::TryInto;
+    weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
+    pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
+        if let Ok(o) = offset.try_into() {
+            cvt(pread(fd, buf, count, o))
+        } else {
+            Err(io::Error::new(io::ErrorKind::InvalidInput,
+                               "cannot pread >2GB"))
+        }
+    })
+}
+
+#[cfg(target_pointer_width = "32")]
+pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
+    -> io::Result<ssize_t>
+{
+    use convert::TryInto;
+    weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
+    pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
+        if let Ok(o) = offset.try_into() {
+            cvt(pwrite(fd, buf, count, o))
+        } else {
+            Err(io::Error::new(io::ErrorKind::InvalidInput,
+                               "cannot pwrite >2GB"))
+        }
+    })
+}
+
+#[cfg(target_pointer_width = "64")]
+pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
+    -> io::Result<ssize_t>
+{
+    cvt(pread(fd, buf, count, offset))
+}
+
+#[cfg(target_pointer_width = "64")]
+pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
+    -> io::Result<ssize_t>
+{
+    cvt(pwrite(fd, buf, count, offset))
+}
diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs
index 77587918ac9..fcfab051588 100644
--- a/src/libstd/sys/unix/ext/fs.rs
+++ b/src/libstd/sys/unix/ext/fs.rs
@@ -20,6 +20,51 @@ use sys;
 use sys_common::{FromInner, AsInner, AsInnerMut};
 use sys::platform::fs::MetadataExt as UnixMetadataExt;
 
+/// Unix-specific extensions to `File`
+#[unstable(feature = "file_offset", issue = "35918")]
+pub trait FileExt {
+    /// Reads a number of bytes starting from a given offset.
+    ///
+    /// Returns the number of bytes read.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// Note that similar to `File::read`, it is not an error to return with a
+    /// short read.
+    #[unstable(feature = "file_offset", issue = "35918")]
+    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+    /// Writes a number of bytes starting from a given offset.
+    ///
+    /// Returns the number of bytes written.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor.
+    ///
+    /// The current file cursor is not affected by this function.
+    ///
+    /// When writing beyond the end of the file, the file is appropiately
+    /// extended and the intermediate bytes are initialized with the value 0.
+    ///
+    /// Note that similar to `File::write`, it is not an error to return a
+    /// short write.
+    #[unstable(feature = "file_offset", issue = "35918")]
+    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+}
+
+#[unstable(feature = "file_offset", issue = "35918")]
+impl FileExt for fs::File {
+    fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        self.as_inner().read_at(buf, offset)
+    }
+    fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        self.as_inner().write_at(buf, offset)
+    }
+}
+
 /// Unix-specific extensions to `Permissions`
 #[stable(feature = "fs_ext", since = "1.1.0")]
 pub trait PermissionsExt {
diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs
index 1be3d75d866..b2483f4e209 100644
--- a/src/libstd/sys/unix/ext/mod.rs
+++ b/src/libstd/sys/unix/ext/mod.rs
@@ -50,6 +50,8 @@ pub mod prelude {
     pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
     #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::fs::DirEntryExt;
+    #[doc(no_inline)] #[unstable(feature = "file_offset", issue = "35918")]
+    pub use super::fs::FileExt;
     #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::thread::JoinHandleExt;
     #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs
index eadf98867a6..41bb96fed16 100644
--- a/src/libstd/sys/unix/fd.rs
+++ b/src/libstd/sys/unix/fd.rs
@@ -50,6 +50,30 @@ impl FileDesc {
         (&mut me).read_to_end(buf)
     }
 
+    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        #[cfg(target_os = "android")]
+        use super::android::cvt_pread64;
+
+        #[cfg(not(target_os = "android"))]
+        unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
+            -> io::Result<isize>
+        {
+            #[cfg(any(target_os = "linux", target_os = "emscripten"))]
+            use libc::pread64;
+            #[cfg(not(any(target_os = "linux", target_os = "emscripten")))]
+            use libc::pread as pread64;
+            cvt(pread64(fd, buf, count, offset))
+        }
+
+        unsafe {
+            cvt_pread64(self.fd,
+                        buf.as_mut_ptr() as *mut c_void,
+                        buf.len(),
+                        offset as i64)
+                .map(|n| n as usize)
+        }
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         let ret = cvt(unsafe {
             libc::write(self.fd,
@@ -59,6 +83,30 @@ impl FileDesc {
         Ok(ret as usize)
     }
 
+    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        #[cfg(target_os = "android")]
+        use super::android::cvt_pwrite64;
+
+        #[cfg(not(target_os = "android"))]
+        unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
+            -> io::Result<isize>
+        {
+            #[cfg(any(target_os = "linux", target_os = "emscripten"))]
+            use libc::pwrite64;
+            #[cfg(not(any(target_os = "linux", target_os = "emscripten")))]
+            use libc::pwrite as pwrite64;
+            cvt(pwrite64(fd, buf, count, offset))
+        }
+
+        unsafe {
+            cvt_pwrite64(self.fd,
+                         buf.as_ptr() as *const c_void,
+                         buf.len(),
+                         offset as i64)
+                .map(|n| n as usize)
+        }
+    }
+
     #[cfg(not(any(target_env = "newlib",
                   target_os = "solaris",
                   target_os = "emscripten",
diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs
index 606e2c2264a..fe8cbc84215 100644
--- a/src/libstd/sys/unix/fs.rs
+++ b/src/libstd/sys/unix/fs.rs
@@ -483,10 +483,18 @@ impl File {
         self.0.read_to_end(buf)
     }
 
+    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        self.0.read_at(buf, offset)
+    }
+
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
         self.0.write(buf)
     }
 
+    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        self.0.write_at(buf, offset)
+    }
+
     pub fn flush(&self) -> io::Result<()> { Ok(()) }
 
     pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs
index 4388a0bdff2..1e2b8bf38fa 100644
--- a/src/libstd/sys/windows/ext/fs.rs
+++ b/src/libstd/sys/windows/ext/fs.rs
@@ -12,12 +12,61 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
-use fs::{OpenOptions, Metadata};
+use fs::{self, OpenOptions, Metadata};
 use io;
 use path::Path;
 use sys;
 use sys_common::{AsInnerMut, AsInner};
 
+/// Windows-specific extensions to `File`
+#[unstable(feature = "file_offset", issue = "35918")]
+pub trait FileExt {
+    /// Seeks to a given position and reads a number of bytes.
+    ///
+    /// Returns the number of bytes read.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor. The current cursor **is** affected by this
+    /// function, it is set to the end of the read.
+    ///
+    /// Reading beyond the end of the file will always return with a length of
+    /// 0.
+    ///
+    /// Note that similar to `File::read`, it is not an error to return with a
+    /// short read. When returning from such a short read, the file pointer is
+    /// still updated.
+    #[unstable(feature = "file_offset", issue = "35918")]
+    fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+
+    /// Seeks to a given position and writes a number of bytes.
+    ///
+    /// Returns the number of bytes written.
+    ///
+    /// The offset is relative to the start of the file and thus independent
+    /// from the current cursor. The current cursor **is** affected by this
+    /// function, it is set to the end of the write.
+    ///
+    /// When writing beyond the end of the file, the file is appropiately
+    /// extended and the intermediate bytes are left uninitialized.
+    ///
+    /// Note that similar to `File::write`, it is not an error to return a
+    /// short write. When returning from such a short write, the file pointer
+    /// is still updated.
+    #[unstable(feature = "file_offset", issue = "35918")]
+    fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+}
+
+#[unstable(feature = "file_offset", issue = "35918")]
+impl FileExt for fs::File {
+    fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        self.as_inner().read_at(buf, offset)
+    }
+
+    fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        self.as_inner().write_at(buf, offset)
+    }
+}
+
 /// Windows-specific extensions to `OpenOptions`
 #[stable(feature = "open_options_ext", since = "1.10.0")]
 pub trait OpenOptionsExt {
diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs
index c3578fdfdb1..932bb5e9564 100644
--- a/src/libstd/sys/windows/ext/mod.rs
+++ b/src/libstd/sys/windows/ext/mod.rs
@@ -36,4 +36,6 @@ pub mod prelude {
     pub use super::ffi::{OsStrExt, OsStringExt};
     #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
     pub use super::fs::{OpenOptionsExt, MetadataExt};
+    #[doc(no_inline)] #[unstable(feature = "file_offset", issue = "35918")]
+    pub use super::fs::FileExt;
 }
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 90a16853d56..a927eae020d 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -311,6 +311,10 @@ impl File {
         self.handle.read(buf)
     }
 
+    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        self.handle.read_at(buf, offset)
+    }
+
     pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
         self.handle.read_to_end(buf)
     }
@@ -319,6 +323,10 @@ impl File {
         self.handle.write(buf)
     }
 
+    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        self.handle.write_at(buf, offset)
+    }
+
     pub fn flush(&self) -> io::Result<()> { Ok(()) }
 
     pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs
index 97e746ee345..10b86ba44bc 100644
--- a/src/libstd/sys/windows/handle.rs
+++ b/src/libstd/sys/windows/handle.rs
@@ -104,6 +104,23 @@ impl RawHandle {
         }
     }
 
+    pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
+        let mut read = 0;
+        let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+        let res = unsafe {
+            let mut overlapped: c::OVERLAPPED = mem::zeroed();
+            overlapped.Offset = offset as u32;
+            overlapped.OffsetHigh = (offset >> 32) as u32;
+            cvt(c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID,
+                            len, &mut read, &mut overlapped))
+        };
+        match res {
+            Ok(_) => Ok(read as usize),
+            Err(ref e) if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) => Ok(0),
+            Err(e) => Err(e),
+        }
+    }
+
     pub unsafe fn read_overlapped(&self,
                                   buf: &mut [u8],
                                   overlapped: *mut c::OVERLAPPED)
@@ -174,6 +191,19 @@ impl RawHandle {
         Ok(amt as usize)
     }
 
+    pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
+        let mut written = 0;
+        let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
+        unsafe {
+            let mut overlapped: c::OVERLAPPED = mem::zeroed();
+            overlapped.Offset = offset as u32;
+            overlapped.OffsetHigh = (offset >> 32) as u32;
+            cvt(c::WriteFile(self.0, buf.as_ptr() as c::LPVOID,
+                             len, &mut written, &mut overlapped))?;
+        }
+        Ok(written as usize)
+    }
+
     pub fn duplicate(&self, access: c::DWORD, inherit: bool,
                      options: c::DWORD) -> io::Result<Handle> {
         let mut ret = 0 as c::HANDLE;
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index fcf2d32ded9..30fc4c3dd80 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -71,7 +71,7 @@ impl Encodable for Name {
 
 impl Decodable for Name {
     fn decode<D: Decoder>(d: &mut D) -> Result<Name, D::Error> {
-        Ok(token::intern(&d.read_str()?[..]))
+        Ok(token::intern(&d.read_str()?))
     }
 }
 
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 6d68ce3646d..49012ad036a 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -804,7 +804,7 @@ impl CodeMap {
     }
 
     pub fn macro_backtrace(&self, span: Span) -> Vec<MacroBacktrace> {
-        let mut last_span = DUMMY_SP;
+        let mut prev_span = DUMMY_SP;
         let mut span = span;
         let mut result = vec![];
         loop {
@@ -827,14 +827,14 @@ impl CodeMap {
                 None => break,
                 Some((call_site, macro_decl_name, def_site_span)) => {
                     // Don't print recursive invocations
-                    if !call_site.source_equal(&last_span) {
+                    if !call_site.source_equal(&prev_span) {
                         result.push(MacroBacktrace {
                             call_site: call_site,
                             macro_decl_name: macro_decl_name,
                             def_site_span: def_site_span,
                         });
                     }
-                    last_span = span;
+                    prev_span = span;
                     span = call_site;
                 }
             }
diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs
index 94a7f6030b9..3b81ea4917f 100644
--- a/src/libsyntax/config.rs
+++ b/src/libsyntax/config.rs
@@ -153,7 +153,7 @@ impl<'a> StripUnconfigured<'a> {
     }
 
     // Visit attributes on expression and statements (but not attributes on items in blocks).
-    fn visit_stmt_or_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
+    fn visit_expr_attrs(&mut self, attrs: &[ast::Attribute]) {
         // flag the offending attributes
         for attr in attrs.iter() {
             if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
@@ -227,7 +227,7 @@ impl<'a> StripUnconfigured<'a> {
     }
 
     pub fn configure_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
-        self.visit_stmt_or_expr_attrs(expr.attrs());
+        self.visit_expr_attrs(expr.attrs());
 
         // If an expr is valid to cfg away it will have been removed by the
         // outer stmt or expression folder before descending in here.
@@ -245,7 +245,6 @@ impl<'a> StripUnconfigured<'a> {
     }
 
     pub fn configure_stmt(&mut self, stmt: ast::Stmt) -> Option<ast::Stmt> {
-        self.visit_stmt_or_expr_attrs(stmt.attrs());
         self.configure(stmt)
     }
 }
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index b56018e1e9d..f7c88073c9d 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -22,7 +22,6 @@ use parse::{self, parser};
 use parse::token;
 use parse::token::{InternedString, str_to_ident};
 use ptr::P;
-use std_inject;
 use util::small_vector::SmallVector;
 
 use std::path::PathBuf;
@@ -523,10 +522,17 @@ pub trait Resolver {
     fn add_expansions_at_stmt(&mut self, id: ast::NodeId, macros: Vec<Mark>);
 
     fn find_attr_invoc(&mut self, attrs: &mut Vec<Attribute>) -> Option<Attribute>;
-    fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation) -> Option<Rc<SyntaxExtension>>;
+    fn resolve_invoc(&mut self, scope: Mark, invoc: &Invocation, force: bool)
+                     -> Result<Rc<SyntaxExtension>, Determinacy>;
     fn resolve_derive_mode(&mut self, ident: ast::Ident) -> Option<Rc<MultiItemModifier>>;
 }
 
+#[derive(Copy, Clone, Debug)]
+pub enum Determinacy {
+    Determined,
+    Undetermined,
+}
+
 pub struct DummyResolver;
 
 impl Resolver for DummyResolver {
@@ -540,8 +546,9 @@ impl Resolver for DummyResolver {
 
     fn find_attr_invoc(&mut self, _attrs: &mut Vec<Attribute>) -> Option<Attribute> { None }
     fn resolve_derive_mode(&mut self, _ident: ast::Ident) -> Option<Rc<MultiItemModifier>> { None }
-    fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation) -> Option<Rc<SyntaxExtension>> {
-        None
+    fn resolve_invoc(&mut self, _scope: Mark, _invoc: &Invocation, _force: bool)
+                     -> Result<Rc<SyntaxExtension>, Determinacy> {
+        Err(Determinacy::Determined)
     }
 }
 
@@ -737,28 +744,6 @@ impl<'a> ExtCtxt<'a> {
     pub fn name_of(&self, st: &str) -> ast::Name {
         token::intern(st)
     }
-
-    pub fn initialize(&mut self, user_exts: Vec<NamedSyntaxExtension>, krate: &ast::Crate) {
-        if std_inject::no_core(&krate) {
-            self.crate_root = None;
-        } else if std_inject::no_std(&krate) {
-            self.crate_root = Some("core");
-        } else {
-            self.crate_root = Some("std");
-        }
-
-        for (name, extension) in user_exts {
-            let ident = ast::Ident::with_empty_ctxt(name);
-            self.resolver.add_ext(ident, Rc::new(extension));
-        }
-
-        let mut module = ModuleData {
-            mod_path: vec![token::str_to_ident(&self.ecfg.crate_name)],
-            directory: PathBuf::from(self.parse_sess.codemap().span_to_filename(krate.span)),
-        };
-        module.directory.pop();
-        self.current_expansion.module = Rc::new(module);
-    }
 }
 
 /// Extract a string literal from the macro expanded version of `expr`,
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 3abe7626efc..363ceebf0f4 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use ast::{Block, Crate, Ident, Mac_, PatKind};
+use ast::{Block, Ident, Mac_, PatKind};
 use ast::{Name, MacStmtStyle, StmtKind, ItemKind};
 use ast;
 use ext::hygiene::Mark;
@@ -26,6 +26,7 @@ use parse::parser::Parser;
 use parse::token::{self, intern, keywords};
 use print::pprust;
 use ptr::P;
+use std_inject;
 use tokenstream::{TokenTree, TokenStream};
 use util::small_vector::SmallVector;
 use visit::Visitor;
@@ -186,8 +187,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         MacroExpander { cx: cx, monotonic: monotonic }
     }
 
-    fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
-        let err_count = self.cx.parse_sess.span_diagnostic.err_count();
+    pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate {
+        self.cx.crate_root = std_inject::injected_crate_name(&krate);
+        let mut module = ModuleData {
+            mod_path: vec![token::str_to_ident(&self.cx.ecfg.crate_name)],
+            directory: PathBuf::from(self.cx.codemap().span_to_filename(krate.span)),
+        };
+        module.directory.pop();
+        self.cx.current_expansion.module = Rc::new(module);
 
         let krate_item = Expansion::Items(SmallVector::one(P(ast::Item {
             attrs: krate.attrs,
@@ -206,10 +213,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             _ => unreachable!(),
         };
 
-        if self.cx.parse_sess.span_diagnostic.err_count() - self.cx.resolve_err_count > err_count {
-            self.cx.parse_sess.span_diagnostic.abort_if_errors();
-        }
-
         krate
     }
 
@@ -221,25 +224,47 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let (expansion, mut invocations) = self.collect_invocations(expansion);
         invocations.reverse();
 
-        let mut expansions = vec![vec![(0, expansion)]];
-        while let Some(invoc) = invocations.pop() {
+        let mut expansions = Vec::new();
+        let mut undetermined_invocations = Vec::new();
+        let (mut progress, mut force) = (false, !self.monotonic);
+        loop {
+            let invoc = if let Some(invoc) = invocations.pop() {
+                invoc
+            } else if undetermined_invocations.is_empty() {
+                break
+            } else {
+                invocations = mem::replace(&mut undetermined_invocations, Vec::new());
+                force = !mem::replace(&mut progress, false);
+                continue
+            };
+
+            let scope =
+                if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark };
+            let ext = match self.cx.resolver.resolve_invoc(scope, &invoc, force) {
+                Ok(ext) => Some(ext),
+                Err(Determinacy::Determined) => None,
+                Err(Determinacy::Undetermined) => {
+                    undetermined_invocations.push(invoc);
+                    continue
+                }
+            };
+
+            progress = true;
             let ExpansionData { depth, mark, .. } = invoc.expansion_data;
             self.cx.current_expansion = invoc.expansion_data.clone();
 
-            let scope = if self.monotonic { mark } else { orig_expansion_data.mark };
             self.cx.current_expansion.mark = scope;
-            let expansion = match self.cx.resolver.resolve_invoc(scope, &invoc) {
+            let expansion = match ext {
                 Some(ext) => self.expand_invoc(invoc, ext),
                 None => invoc.expansion_kind.dummy(invoc.span()),
             };
 
-            self.cx.current_expansion.depth = depth + 1;
             let (expansion, new_invocations) = self.collect_invocations(expansion);
 
-            if expansions.len() == depth {
+            if expansions.len() < depth {
                 expansions.push(Vec::new());
             }
-            expansions[depth].push((mark.as_u32(), expansion));
+            expansions[depth - 1].push((mark.as_u32(), expansion));
             if !self.cx.ecfg.single_step {
                 invocations.extend(new_invocations.into_iter().rev());
             }
@@ -250,12 +275,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         let mut placeholder_expander = PlaceholderExpander::new(self.cx, self.monotonic);
         while let Some(expansions) = expansions.pop() {
             for (mark, expansion) in expansions.into_iter().rev() {
-                let expansion = expansion.fold_with(&mut placeholder_expander);
                 placeholder_expander.add(ast::NodeId::from_u32(mark), expansion);
             }
         }
 
-        placeholder_expander.remove(ast::NodeId::from_u32(0))
+        expansion.fold_with(&mut placeholder_expander)
     }
 
     fn collect_invocations(&mut self, expansion: Expansion) -> (Expansion, Vec<Invocation>) {
@@ -538,7 +562,11 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
         self.invocations.push(Invocation {
             kind: kind,
             expansion_kind: expansion_kind,
-            expansion_data: ExpansionData { mark: mark, ..self.cx.current_expansion.clone() },
+            expansion_data: ExpansionData {
+                mark: mark,
+                depth: self.cx.current_expansion.depth + 1,
+                ..self.cx.current_expansion.clone()
+            },
         });
         placeholder(expansion_kind, ast::NodeId::from_u32(mark.as_u32()))
     }
@@ -866,22 +894,6 @@ impl<'feat> ExpansionConfig<'feat> {
     }
 }
 
-pub fn expand_crate(cx: &mut ExtCtxt,
-                    user_exts: Vec<NamedSyntaxExtension>,
-                    c: Crate) -> Crate {
-    cx.initialize(user_exts, &c);
-    cx.monotonic_expander().expand_crate(c)
-}
-
-// Expands crate using supplied MacroExpander - allows for
-// non-standard expansion behaviour (e.g. step-wise).
-pub fn expand_crate_with_expander(expander: &mut MacroExpander,
-                                  user_exts: Vec<NamedSyntaxExtension>,
-                                  c: Crate) -> Crate {
-    expander.cx.initialize(user_exts, &c);
-    expander.expand_crate(c)
-}
-
 // A Marker adds the given mark to the syntax context and
 // sets spans' `expn_id` to the given expn_id (unless it is `None`).
 struct Marker { mark: Mark, expn_id: Option<ExpnId> }
diff --git a/src/libsyntax/ext/placeholders.rs b/src/libsyntax/ext/placeholders.rs
index 0ede6dd98e5..e323dd2f623 100644
--- a/src/libsyntax/ext/placeholders.rs
+++ b/src/libsyntax/ext/placeholders.rs
@@ -88,10 +88,11 @@ impl<'a, 'b> PlaceholderExpander<'a, 'b> {
     }
 
     pub fn add(&mut self, id: ast::NodeId, expansion: Expansion) {
+        let expansion = expansion.fold_with(self);
         self.expansions.insert(id, expansion);
     }
 
-    pub fn remove(&mut self, id: ast::NodeId) -> Expansion {
+    fn remove(&mut self, id: ast::NodeId) -> Expansion {
         self.expansions.remove(&id).unwrap()
     }
 }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 9eed1d61244..62b88888fc8 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -253,9 +253,6 @@ declare_features! (
     // a...b and ...b
     (active, inclusive_range_syntax, "1.7.0", Some(28237)),
 
-    // `expr?`
-    (active, question_mark, "1.9.0", Some(31436)),
-
     // impl specialization (RFC 1210)
     (active, specialization, "1.7.0", Some(31844)),
 
@@ -348,6 +345,8 @@ declare_features! (
     (accepted, while_let, "1.0.0", None),
     // Allows `#[deprecated]` attribute
     (accepted, deprecated, "1.9.0", Some(29935)),
+    // `expr?`
+    (accepted, question_mark, "1.14.0", Some(31436)),
 );
 // (changing above list without updating src/doc/reference.md makes @cmr sad)
 
@@ -1072,9 +1071,6 @@ impl<'a> Visitor for PostExpansionVisitor<'a> {
                                   e.span,
                                   "inclusive range syntax is experimental");
             }
-            ast::ExprKind::Try(..) => {
-                gate_feature_post!(&self, question_mark, e.span, "the `?` operator is not stable");
-            }
             ast::ExprKind::InPlace(..) => {
                 gate_feature_post!(&self, placement_in_syntax, e.span, EXPLAIN_PLACEMENT_IN);
             }
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index 118ceb17ab4..6e671c9efdc 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -31,7 +31,7 @@
 #![feature(staged_api)]
 #![feature(str_escape)]
 #![feature(unicode)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![feature(rustc_diagnostic_macros)]
 #![feature(specialization)]
 
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index 9eac024edb1..3cb34fa3c91 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -126,7 +126,7 @@ impl<'a> Parser<'a> {
                 self.expect(&token::OpenDelim(token::Bracket))?;
                 let meta_item = self.parse_meta_item()?;
                 self.expect(&token::CloseDelim(token::Bracket))?;
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
 
                 (mk_sp(lo, hi), meta_item, style)
             }
@@ -231,16 +231,16 @@ impl<'a> Parser<'a> {
             token::Eq => {
                 self.bump();
                 let lit = self.parse_unsuffixed_lit()?;
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
                 Ok(P(spanned(lo, hi, ast::MetaItemKind::NameValue(name, lit))))
             }
             token::OpenDelim(token::Paren) => {
                 let inner_items = self.parse_meta_seq()?;
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
                 Ok(P(spanned(lo, hi, ast::MetaItemKind::List(name, inner_items))))
             }
             _ => {
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
                 Ok(P(spanned(lo, hi, ast::MetaItemKind::Word(name))))
             }
         }
@@ -253,14 +253,14 @@ impl<'a> Parser<'a> {
 
         match self.parse_unsuffixed_lit() {
             Ok(lit) => {
-                return Ok(spanned(lo, self.last_span.hi, ast::NestedMetaItemKind::Literal(lit)))
+                return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::Literal(lit)))
             }
             Err(ref mut err) => self.diagnostic().cancel(err)
         }
 
         match self.parse_meta_item() {
             Ok(mi) => {
-                return Ok(spanned(lo, self.last_span.hi, ast::NestedMetaItemKind::MetaItem(mi)))
+                return Ok(spanned(lo, self.prev_span.hi, ast::NestedMetaItemKind::MetaItem(mi)))
             }
             Err(ref mut err) => self.diagnostic().cancel(err)
         }
diff --git a/src/libsyntax/parse/lexer/comments.rs b/src/libsyntax/parse/lexer/comments.rs
index 5eb5605ea71..38f811d54da 100644
--- a/src/libsyntax/parse/lexer/comments.rs
+++ b/src/libsyntax/parse/lexer/comments.rs
@@ -149,13 +149,13 @@ fn push_blank_line_comment(rdr: &StringReader, comments: &mut Vec<Comment>) {
     comments.push(Comment {
         style: BlankLine,
         lines: Vec::new(),
-        pos: rdr.last_pos,
+        pos: rdr.pos,
     });
 }
 
 fn consume_whitespace_counting_blank_lines(rdr: &mut StringReader, comments: &mut Vec<Comment>) {
-    while is_pattern_whitespace(rdr.curr) && !rdr.is_eof() {
-        if rdr.col == CharPos(0) && rdr.curr_is('\n') {
+    while is_pattern_whitespace(rdr.ch) && !rdr.is_eof() {
+        if rdr.col == CharPos(0) && rdr.ch_is('\n') {
             push_blank_line_comment(rdr, &mut *comments);
         }
         rdr.bump();
@@ -167,7 +167,7 @@ fn read_shebang_comment(rdr: &mut StringReader,
                         code_to_the_left: bool,
                         comments: &mut Vec<Comment>) {
     debug!(">>> shebang comment");
-    let p = rdr.last_pos;
+    let p = rdr.pos;
     debug!("<<< shebang comment");
     comments.push(Comment {
         style: if code_to_the_left { Trailing } else { Isolated },
@@ -180,9 +180,9 @@ fn read_line_comments(rdr: &mut StringReader,
                       code_to_the_left: bool,
                       comments: &mut Vec<Comment>) {
     debug!(">>> line comments");
-    let p = rdr.last_pos;
+    let p = rdr.pos;
     let mut lines: Vec<String> = Vec::new();
-    while rdr.curr_is('/') && rdr.nextch_is('/') {
+    while rdr.ch_is('/') && rdr.nextch_is('/') {
         let line = rdr.read_one_line_comment();
         debug!("{}", line);
         // Doc comments are not put in comments.
@@ -240,7 +240,7 @@ fn read_block_comment(rdr: &mut StringReader,
                       code_to_the_left: bool,
                       comments: &mut Vec<Comment>) {
     debug!(">>> block comment");
-    let p = rdr.last_pos;
+    let p = rdr.pos;
     let mut lines: Vec<String> = Vec::new();
     let col = rdr.col;
     rdr.bump();
@@ -249,9 +249,9 @@ fn read_block_comment(rdr: &mut StringReader,
     let mut curr_line = String::from("/*");
 
     // doc-comments are not really comments, they are attributes
-    if (rdr.curr_is('*') && !rdr.nextch_is('*')) || rdr.curr_is('!') {
-        while !(rdr.curr_is('*') && rdr.nextch_is('/')) && !rdr.is_eof() {
-            curr_line.push(rdr.curr.unwrap());
+    if (rdr.ch_is('*') && !rdr.nextch_is('*')) || rdr.ch_is('!') {
+        while !(rdr.ch_is('*') && rdr.nextch_is('/')) && !rdr.is_eof() {
+            curr_line.push(rdr.ch.unwrap());
             rdr.bump();
         }
         if !rdr.is_eof() {
@@ -271,19 +271,19 @@ fn read_block_comment(rdr: &mut StringReader,
             if rdr.is_eof() {
                 panic!(rdr.fatal("unterminated block comment"));
             }
-            if rdr.curr_is('\n') {
+            if rdr.ch_is('\n') {
                 trim_whitespace_prefix_and_push_line(&mut lines, curr_line, col);
                 curr_line = String::new();
                 rdr.bump();
             } else {
-                curr_line.push(rdr.curr.unwrap());
-                if rdr.curr_is('/') && rdr.nextch_is('*') {
+                curr_line.push(rdr.ch.unwrap());
+                if rdr.ch_is('/') && rdr.nextch_is('*') {
                     rdr.bump();
                     rdr.bump();
                     curr_line.push('*');
                     level += 1;
                 } else {
-                    if rdr.curr_is('*') && rdr.nextch_is('/') {
+                    if rdr.ch_is('*') && rdr.nextch_is('/') {
                         rdr.bump();
                         rdr.bump();
                         curr_line.push('/');
@@ -305,7 +305,7 @@ fn read_block_comment(rdr: &mut StringReader,
         Isolated
     };
     rdr.consume_non_eol_whitespace();
-    if !rdr.is_eof() && !rdr.curr_is('\n') && lines.len() == 1 {
+    if !rdr.is_eof() && !rdr.ch_is('\n') && lines.len() == 1 {
         style = Mixed;
     }
     debug!("<<< block comment");
@@ -319,11 +319,11 @@ fn read_block_comment(rdr: &mut StringReader,
 
 fn consume_comment(rdr: &mut StringReader, code_to_the_left: bool, comments: &mut Vec<Comment>) {
     debug!(">>> consume comment");
-    if rdr.curr_is('/') && rdr.nextch_is('/') {
+    if rdr.ch_is('/') && rdr.nextch_is('/') {
         read_line_comments(rdr, code_to_the_left, comments);
-    } else if rdr.curr_is('/') && rdr.nextch_is('*') {
+    } else if rdr.ch_is('/') && rdr.nextch_is('*') {
         read_block_comment(rdr, code_to_the_left, comments);
-    } else if rdr.curr_is('#') && rdr.nextch_is('!') {
+    } else if rdr.ch_is('#') && rdr.nextch_is('!') {
         read_shebang_comment(rdr, code_to_the_left, comments);
     } else {
         panic!();
@@ -357,7 +357,7 @@ pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler,
         loop {
             let mut code_to_the_left = !first_read;
             rdr.consume_non_eol_whitespace();
-            if rdr.curr_is('\n') {
+            if rdr.ch_is('\n') {
                 code_to_the_left = false;
                 consume_whitespace_counting_blank_lines(&mut rdr, &mut comments);
             }
@@ -369,7 +369,7 @@ pub fn gather_comments_and_literals(span_diagnostic: &errors::Handler,
         }
 
 
-        let bstart = rdr.last_pos;
+        let bstart = rdr.pos;
         rdr.next_token();
         // discard, and look ahead; we're working with internal state
         let TokenAndSpan { tok, sp } = rdr.peek();
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 0ba2db3310c..aca41bd7b59 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -77,13 +77,13 @@ pub struct TokenAndSpan {
 pub struct StringReader<'a> {
     pub span_diagnostic: &'a Handler,
     /// The absolute offset within the codemap of the next character to read
+    pub next_pos: BytePos,
+    /// The absolute offset within the codemap of the current character
     pub pos: BytePos,
-    /// The absolute offset within the codemap of the last character read(curr)
-    pub last_pos: BytePos,
     /// The column of the next character to read
     pub col: CharPos,
-    /// The last character to be read
-    pub curr: Option<char>,
+    /// The current character (which has been read from self.pos)
+    pub ch: Option<char>,
     pub filemap: Rc<syntax_pos::FileMap>,
     /// If Some, stop reading the source at this position (inclusive).
     pub terminator: Option<BytePos>,
@@ -102,12 +102,12 @@ pub struct StringReader<'a> {
 
 impl<'a> Reader for StringReader<'a> {
     fn is_eof(&self) -> bool {
-        if self.curr.is_none() {
+        if self.ch.is_none() {
             return true;
         }
 
         match self.terminator {
-            Some(t) => self.pos > t,
+            Some(t) => self.next_pos > t,
             None => false,
         }
     }
@@ -173,7 +173,7 @@ impl<'a> Reader for TtReader<'a> {
 }
 
 impl<'a> StringReader<'a> {
-    /// For comments.rs, which hackily pokes into pos and curr
+    /// For comments.rs, which hackily pokes into next_pos and ch
     pub fn new_raw<'b>(span_diagnostic: &'b Handler,
                        filemap: Rc<syntax_pos::FileMap>)
                        -> StringReader<'b> {
@@ -195,10 +195,10 @@ impl<'a> StringReader<'a> {
 
         StringReader {
             span_diagnostic: span_diagnostic,
+            next_pos: filemap.start_pos,
             pos: filemap.start_pos,
-            last_pos: filemap.start_pos,
             col: CharPos(0),
-            curr: Some('\n'),
+            ch: Some('\n'),
             filemap: filemap,
             terminator: None,
             save_new_lines: true,
@@ -221,8 +221,8 @@ impl<'a> StringReader<'a> {
         sr
     }
 
-    pub fn curr_is(&self, c: char) -> bool {
-        self.curr == Some(c)
+    pub fn ch_is(&self, c: char) -> bool {
+        self.ch == Some(c)
     }
 
     /// Report a fatal lexical error with a given span.
@@ -317,9 +317,9 @@ impl<'a> StringReader<'a> {
                     self.peek_tok = token::Eof;
                     self.peek_span = syntax_pos::mk_sp(self.filemap.end_pos, self.filemap.end_pos);
                 } else {
-                    let start_bytepos = self.last_pos;
+                    let start_bytepos = self.pos;
                     self.peek_tok = self.next_token_inner()?;
-                    self.peek_span = syntax_pos::mk_sp(start_bytepos, self.last_pos);
+                    self.peek_span = syntax_pos::mk_sp(start_bytepos, self.pos);
                 };
             }
         }
@@ -331,19 +331,19 @@ impl<'a> StringReader<'a> {
     }
 
     /// Calls `f` with a string slice of the source text spanning from `start`
-    /// up to but excluding `self.last_pos`, meaning the slice does not include
-    /// the character `self.curr`.
+    /// up to but excluding `self.pos`, meaning the slice does not include
+    /// the character `self.ch`.
     pub fn with_str_from<T, F>(&self, start: BytePos, f: F) -> T
         where F: FnOnce(&str) -> T
     {
-        self.with_str_from_to(start, self.last_pos, f)
+        self.with_str_from_to(start, self.pos, f)
     }
 
     /// Create a Name from a given offset to the current offset, each
     /// adjusted 1 towards each other (assumes that on either side there is a
     /// single-byte delimiter).
     pub fn name_from(&self, start: BytePos) -> ast::Name {
-        debug!("taking an ident from {:?} to {:?}", start, self.last_pos);
+        debug!("taking an ident from {:?} to {:?}", start, self.pos);
         self.with_str_from(start, token::intern)
     }
 
@@ -414,32 +414,35 @@ impl<'a> StringReader<'a> {
     /// Advance the StringReader by one character. If a newline is
     /// discovered, add it to the FileMap's list of line start offsets.
     pub fn bump(&mut self) {
-        self.last_pos = self.pos;
-        let current_byte_offset = self.byte_offset(self.pos).to_usize();
-        if current_byte_offset < self.source_text.len() {
-            let last_char = self.curr.unwrap();
-            let ch = char_at(&self.source_text, current_byte_offset);
-            let byte_offset_diff = ch.len_utf8();
-            self.pos = self.pos + Pos::from_usize(byte_offset_diff);
-            self.curr = Some(ch);
-            self.col = self.col + CharPos(1);
-            if last_char == '\n' {
+        let new_pos = self.next_pos;
+        let new_byte_offset = self.byte_offset(new_pos).to_usize();
+        if new_byte_offset < self.source_text.len() {
+            let old_ch_is_newline = self.ch.unwrap() == '\n';
+            let new_ch = char_at(&self.source_text, new_byte_offset);
+            let new_ch_len = new_ch.len_utf8();
+
+            self.ch = Some(new_ch);
+            self.pos = new_pos;
+            self.next_pos = new_pos + Pos::from_usize(new_ch_len);
+            if old_ch_is_newline {
                 if self.save_new_lines {
-                    self.filemap.next_line(self.last_pos);
+                    self.filemap.next_line(self.pos);
                 }
                 self.col = CharPos(0);
+            } else {
+                self.col = self.col + CharPos(1);
             }
-
-            if byte_offset_diff > 1 {
-                self.filemap.record_multibyte_char(self.last_pos, byte_offset_diff);
+            if new_ch_len > 1 {
+                self.filemap.record_multibyte_char(self.pos, new_ch_len);
             }
         } else {
-            self.curr = None;
+            self.ch = None;
+            self.pos = new_pos;
         }
     }
 
     pub fn nextch(&self) -> Option<char> {
-        let offset = self.byte_offset(self.pos).to_usize();
+        let offset = self.byte_offset(self.next_pos).to_usize();
         if offset < self.source_text.len() {
             Some(char_at(&self.source_text, offset))
         } else {
@@ -452,7 +455,7 @@ impl<'a> StringReader<'a> {
     }
 
     pub fn nextnextch(&self) -> Option<char> {
-        let offset = self.byte_offset(self.pos).to_usize();
+        let offset = self.byte_offset(self.next_pos).to_usize();
         let s = &self.source_text[..];
         if offset >= s.len() {
             return None;
@@ -471,11 +474,11 @@ impl<'a> StringReader<'a> {
 
     /// Eats <XID_start><XID_continue>*, if possible.
     fn scan_optional_raw_name(&mut self) -> Option<ast::Name> {
-        if !ident_start(self.curr) {
+        if !ident_start(self.ch) {
             return None;
         }
-        let start = self.last_pos;
-        while ident_continue(self.curr) {
+        let start = self.pos;
+        while ident_continue(self.ch) {
             self.bump();
         }
 
@@ -488,37 +491,37 @@ impl<'a> StringReader<'a> {
         })
     }
 
-    /// PRECONDITION: self.curr is not whitespace
+    /// PRECONDITION: self.ch is not whitespace
     /// Eats any kind of comment.
     fn scan_comment(&mut self) -> Option<TokenAndSpan> {
-        if let Some(c) = self.curr {
+        if let Some(c) = self.ch {
             if c.is_whitespace() {
-                self.span_diagnostic.span_err(syntax_pos::mk_sp(self.last_pos, self.last_pos),
+                self.span_diagnostic.span_err(syntax_pos::mk_sp(self.pos, self.pos),
                                               "called consume_any_line_comment, but there \
                                                was whitespace");
             }
         }
 
-        if self.curr_is('/') {
+        if self.ch_is('/') {
             match self.nextch() {
                 Some('/') => {
                     self.bump();
                     self.bump();
 
                     // line comments starting with "///" or "//!" are doc-comments
-                    let doc_comment = self.curr_is('/') || self.curr_is('!');
-                    let start_bpos = self.last_pos - BytePos(2);
+                    let doc_comment = self.ch_is('/') || self.ch_is('!');
+                    let start_bpos = self.pos - BytePos(2);
 
                     while !self.is_eof() {
-                        match self.curr.unwrap() {
+                        match self.ch.unwrap() {
                             '\n' => break,
                             '\r' => {
                                 if self.nextch_is('\n') {
                                     // CRLF
                                     break;
                                 } else if doc_comment {
-                                    self.err_span_(self.last_pos,
-                                                   self.pos,
+                                    self.err_span_(self.pos,
+                                                   self.next_pos,
                                                    "bare CR not allowed in doc-comment");
                                 }
                             }
@@ -538,13 +541,13 @@ impl<'a> StringReader<'a> {
 
                             Some(TokenAndSpan {
                                 tok: tok,
-                                sp: syntax_pos::mk_sp(start_bpos, self.last_pos),
+                                sp: syntax_pos::mk_sp(start_bpos, self.pos),
                             })
                         })
                     } else {
                         Some(TokenAndSpan {
                             tok: token::Comment,
-                            sp: syntax_pos::mk_sp(start_bpos, self.last_pos),
+                            sp: syntax_pos::mk_sp(start_bpos, self.pos),
                         })
                     };
                 }
@@ -555,7 +558,7 @@ impl<'a> StringReader<'a> {
                 }
                 _ => None,
             }
-        } else if self.curr_is('#') {
+        } else if self.ch_is('#') {
             if self.nextch_is('!') {
 
                 // Parse an inner attribute.
@@ -567,17 +570,17 @@ impl<'a> StringReader<'a> {
                 // we're at the beginning of the file...
                 let cmap = CodeMap::new();
                 cmap.files.borrow_mut().push(self.filemap.clone());
-                let loc = cmap.lookup_char_pos_adj(self.last_pos);
+                let loc = cmap.lookup_char_pos_adj(self.pos);
                 debug!("Skipping a shebang");
                 if loc.line == 1 && loc.col == CharPos(0) {
                     // FIXME: Add shebang "token", return it
-                    let start = self.last_pos;
-                    while !self.curr_is('\n') && !self.is_eof() {
+                    let start = self.pos;
+                    while !self.ch_is('\n') && !self.is_eof() {
                         self.bump();
                     }
                     return Some(TokenAndSpan {
                         tok: token::Shebang(self.name_from(start)),
-                        sp: syntax_pos::mk_sp(start, self.last_pos),
+                        sp: syntax_pos::mk_sp(start, self.pos),
                     });
                 }
             }
@@ -590,7 +593,7 @@ impl<'a> StringReader<'a> {
     /// If there is whitespace, shebang, or a comment, scan it. Otherwise,
     /// return None.
     fn scan_whitespace_or_comment(&mut self) -> Option<TokenAndSpan> {
-        match self.curr.unwrap_or('\0') {
+        match self.ch.unwrap_or('\0') {
             // # to handle shebang at start of file -- this is the entry point
             // for skipping over all "junk"
             '/' | '#' => {
@@ -599,13 +602,13 @@ impl<'a> StringReader<'a> {
                 c
             },
             c if is_pattern_whitespace(Some(c)) => {
-                let start_bpos = self.last_pos;
-                while is_pattern_whitespace(self.curr) {
+                let start_bpos = self.pos;
+                while is_pattern_whitespace(self.ch) {
                     self.bump();
                 }
                 let c = Some(TokenAndSpan {
                     tok: token::Whitespace,
-                    sp: syntax_pos::mk_sp(start_bpos, self.last_pos),
+                    sp: syntax_pos::mk_sp(start_bpos, self.pos),
                 });
                 debug!("scanning whitespace: {:?}", c);
                 c
@@ -617,8 +620,8 @@ impl<'a> StringReader<'a> {
     /// Might return a sugared-doc-attr
     fn scan_block_comment(&mut self) -> Option<TokenAndSpan> {
         // block comments starting with "/**" or "/*!" are doc-comments
-        let is_doc_comment = self.curr_is('*') || self.curr_is('!');
-        let start_bpos = self.last_pos - BytePos(2);
+        let is_doc_comment = self.ch_is('*') || self.ch_is('!');
+        let start_bpos = self.pos - BytePos(2);
 
         let mut level: isize = 1;
         let mut has_cr = false;
@@ -629,10 +632,10 @@ impl<'a> StringReader<'a> {
                 } else {
                     "unterminated block comment"
                 };
-                let last_bpos = self.last_pos;
+                let last_bpos = self.pos;
                 panic!(self.fatal_span_(start_bpos, last_bpos, msg));
             }
-            let n = self.curr.unwrap();
+            let n = self.ch.unwrap();
             match n {
                 '/' if self.nextch_is('*') => {
                     level += 1;
@@ -667,7 +670,7 @@ impl<'a> StringReader<'a> {
 
             Some(TokenAndSpan {
                 tok: tok,
-                sp: syntax_pos::mk_sp(start_bpos, self.last_pos),
+                sp: syntax_pos::mk_sp(start_bpos, self.pos),
             })
         })
     }
@@ -682,7 +685,7 @@ impl<'a> StringReader<'a> {
         assert!(real_radix <= scan_radix);
         let mut len = 0;
         loop {
-            let c = self.curr;
+            let c = self.ch;
             if c == Some('_') {
                 debug!("skipping a _");
                 self.bump();
@@ -694,8 +697,8 @@ impl<'a> StringReader<'a> {
                     // check that the hypothetical digit is actually
                     // in range for the true radix
                     if c.unwrap().to_digit(real_radix).is_none() {
-                        self.err_span_(self.last_pos,
-                                       self.pos,
+                        self.err_span_(self.pos,
+                                       self.next_pos,
                                        &format!("invalid digit for a base {} literal", real_radix));
                     }
                     len += 1;
@@ -710,12 +713,12 @@ impl<'a> StringReader<'a> {
     fn scan_number(&mut self, c: char) -> token::Lit {
         let num_digits;
         let mut base = 10;
-        let start_bpos = self.last_pos;
+        let start_bpos = self.pos;
 
         self.bump();
 
         if c == '0' {
-            match self.curr.unwrap_or('\0') {
+            match self.ch.unwrap_or('\0') {
                 'b' => {
                     self.bump();
                     base = 2;
@@ -747,7 +750,7 @@ impl<'a> StringReader<'a> {
 
         if num_digits == 0 {
             self.err_span_(start_bpos,
-                           self.last_pos,
+                           self.pos,
                            "no valid digits found for number");
             return token::Integer(token::intern("0"));
         }
@@ -755,26 +758,26 @@ impl<'a> StringReader<'a> {
         // might be a float, but don't be greedy if this is actually an
         // integer literal followed by field/method access or a range pattern
         // (`0..2` and `12.foo()`)
-        if self.curr_is('.') && !self.nextch_is('.') &&
+        if self.ch_is('.') && !self.nextch_is('.') &&
            !self.nextch()
                 .unwrap_or('\0')
                 .is_xid_start() {
             // might have stuff after the ., and if it does, it needs to start
             // with a number
             self.bump();
-            if self.curr.unwrap_or('\0').is_digit(10) {
+            if self.ch.unwrap_or('\0').is_digit(10) {
                 self.scan_digits(10, 10);
                 self.scan_float_exponent();
             }
-            let last_pos = self.last_pos;
-            self.check_float_base(start_bpos, last_pos, base);
+            let pos = self.pos;
+            self.check_float_base(start_bpos, pos, base);
             return token::Float(self.name_from(start_bpos));
         } else {
             // it might be a float if it has an exponent
-            if self.curr_is('e') || self.curr_is('E') {
+            if self.ch_is('e') || self.ch_is('E') {
                 self.scan_float_exponent();
-                let last_pos = self.last_pos;
-                self.check_float_base(start_bpos, last_pos, base);
+                let pos = self.pos;
+                self.check_float_base(start_bpos, pos, base);
                 return token::Float(self.name_from(start_bpos));
             }
             // but we certainly have an integer!
@@ -786,30 +789,30 @@ impl<'a> StringReader<'a> {
     /// error if too many or too few digits are encountered.
     fn scan_hex_digits(&mut self, n_digits: usize, delim: char, below_0x7f_only: bool) -> bool {
         debug!("scanning {} digits until {:?}", n_digits, delim);
-        let start_bpos = self.last_pos;
+        let start_bpos = self.pos;
         let mut accum_int = 0;
 
         let mut valid = true;
         for _ in 0..n_digits {
             if self.is_eof() {
-                let last_bpos = self.last_pos;
+                let last_bpos = self.pos;
                 panic!(self.fatal_span_(start_bpos,
                                         last_bpos,
                                         "unterminated numeric character escape"));
             }
-            if self.curr_is(delim) {
-                let last_bpos = self.last_pos;
+            if self.ch_is(delim) {
+                let last_bpos = self.pos;
                 self.err_span_(start_bpos,
                                last_bpos,
                                "numeric character escape is too short");
                 valid = false;
                 break;
             }
-            let c = self.curr.unwrap_or('\x00');
+            let c = self.ch.unwrap_or('\x00');
             accum_int *= 16;
             accum_int += c.to_digit(16).unwrap_or_else(|| {
-                self.err_span_char(self.last_pos,
-                                   self.pos,
+                self.err_span_char(self.pos,
+                                   self.next_pos,
                                    "invalid character in numeric character escape",
                                    c);
 
@@ -821,7 +824,7 @@ impl<'a> StringReader<'a> {
 
         if below_0x7f_only && accum_int >= 0x80 {
             self.err_span_(start_bpos,
-                           self.last_pos,
+                           self.pos,
                            "this form of character escape may only be used with characters in \
                             the range [\\x00-\\x7f]");
             valid = false;
@@ -830,7 +833,7 @@ impl<'a> StringReader<'a> {
         match char::from_u32(accum_int) {
             Some(_) => valid,
             None => {
-                let last_bpos = self.last_pos;
+                let last_bpos = self.pos;
                 self.err_span_(start_bpos, last_bpos, "invalid numeric character escape");
                 false
             }
@@ -851,8 +854,8 @@ impl<'a> StringReader<'a> {
         match first_source_char {
             '\\' => {
                 // '\X' for some X must be a character constant:
-                let escaped = self.curr;
-                let escaped_pos = self.last_pos;
+                let escaped = self.ch;
+                let escaped_pos = self.pos;
                 self.bump();
                 match escaped {
                     None => {}  // EOF here is an error that will be checked later.
@@ -861,10 +864,10 @@ impl<'a> StringReader<'a> {
                             'n' | 'r' | 't' | '\\' | '\'' | '"' | '0' => true,
                             'x' => self.scan_byte_escape(delim, !ascii_only),
                             'u' => {
-                                let valid = if self.curr_is('{') {
+                                let valid = if self.ch_is('{') {
                                     self.scan_unicode_escape(delim) && !ascii_only
                                 } else {
-                                    let span = syntax_pos::mk_sp(start, self.last_pos);
+                                    let span = syntax_pos::mk_sp(start, self.pos);
                                     self.span_diagnostic
                                         .struct_span_err(span, "incorrect unicode escape sequence")
                                         .span_help(span,
@@ -875,7 +878,7 @@ impl<'a> StringReader<'a> {
                                 };
                                 if ascii_only {
                                     self.err_span_(start,
-                                                   self.last_pos,
+                                                   self.pos,
                                                    "unicode escape sequences cannot be used as a \
                                                     byte or in a byte string");
                                 }
@@ -886,14 +889,14 @@ impl<'a> StringReader<'a> {
                                 self.consume_whitespace();
                                 true
                             }
-                            '\r' if delim == '"' && self.curr_is('\n') => {
+                            '\r' if delim == '"' && self.ch_is('\n') => {
                                 self.consume_whitespace();
                                 true
                             }
                             c => {
-                                let last_pos = self.last_pos;
+                                let pos = self.pos;
                                 let mut err = self.struct_err_span_char(escaped_pos,
-                                                                        last_pos,
+                                                                        pos,
                                                                         if ascii_only {
                                                                             "unknown byte escape"
                                                                         } else {
@@ -902,13 +905,13 @@ impl<'a> StringReader<'a> {
                                                                         },
                                                                         c);
                                 if e == '\r' {
-                                    err.span_help(syntax_pos::mk_sp(escaped_pos, last_pos),
+                                    err.span_help(syntax_pos::mk_sp(escaped_pos, pos),
                                                   "this is an isolated carriage return; consider \
                                                    checking your editor and version control \
                                                    settings");
                                 }
                                 if (e == '{' || e == '}') && !ascii_only {
-                                    err.span_help(syntax_pos::mk_sp(escaped_pos, last_pos),
+                                    err.span_help(syntax_pos::mk_sp(escaped_pos, pos),
                                                   "if used in a formatting string, curly braces \
                                                    are escaped with `{{` and `}}`");
                                 }
@@ -920,9 +923,9 @@ impl<'a> StringReader<'a> {
                 }
             }
             '\t' | '\n' | '\r' | '\'' if delim == '\'' => {
-                let last_pos = self.last_pos;
+                let pos = self.pos;
                 self.err_span_char(start,
-                                   last_pos,
+                                   pos,
                                    if ascii_only {
                                        "byte constant must be escaped"
                                    } else {
@@ -932,21 +935,21 @@ impl<'a> StringReader<'a> {
                 return false;
             }
             '\r' => {
-                if self.curr_is('\n') {
+                if self.ch_is('\n') {
                     self.bump();
                     return true;
                 } else {
                     self.err_span_(start,
-                                   self.last_pos,
+                                   self.pos,
                                    "bare CR not allowed in string, use \\r instead");
                     return false;
                 }
             }
             _ => {
                 if ascii_only && first_source_char > '\x7F' {
-                    let last_pos = self.last_pos;
+                    let pos = self.pos;
                     self.err_span_(start,
-                                   last_pos,
+                                   pos,
                                    "byte constant must be ASCII. Use a \\xHH escape for a \
                                     non-ASCII byte");
                     return false;
@@ -962,29 +965,29 @@ impl<'a> StringReader<'a> {
     /// will read at least one digit, and up to 6, and pass over the }.
     fn scan_unicode_escape(&mut self, delim: char) -> bool {
         self.bump(); // past the {
-        let start_bpos = self.last_pos;
+        let start_bpos = self.pos;
         let mut count = 0;
         let mut accum_int = 0;
         let mut valid = true;
 
-        while !self.curr_is('}') && count <= 6 {
-            let c = match self.curr {
+        while !self.ch_is('}') && count <= 6 {
+            let c = match self.ch {
                 Some(c) => c,
                 None => {
                     panic!(self.fatal_span_(start_bpos,
-                                            self.last_pos,
+                                            self.pos,
                                             "unterminated unicode escape (found EOF)"));
                 }
             };
             accum_int *= 16;
             accum_int += c.to_digit(16).unwrap_or_else(|| {
                 if c == delim {
-                    panic!(self.fatal_span_(self.last_pos,
-                                            self.pos,
+                    panic!(self.fatal_span_(self.pos,
+                                            self.next_pos,
                                             "unterminated unicode escape (needed a `}`)"));
                 } else {
-                    self.err_span_char(self.last_pos,
-                                       self.pos,
+                    self.err_span_char(self.pos,
+                                       self.next_pos,
                                        "invalid character in unicode escape",
                                        c);
                 }
@@ -997,14 +1000,14 @@ impl<'a> StringReader<'a> {
 
         if count > 6 {
             self.err_span_(start_bpos,
-                           self.last_pos,
+                           self.pos,
                            "overlong unicode escape (can have at most 6 hex digits)");
             valid = false;
         }
 
         if valid && (char::from_u32(accum_int).is_none() || count == 0) {
             self.err_span_(start_bpos,
-                           self.last_pos,
+                           self.pos,
                            "invalid unicode character escape");
             valid = false;
         }
@@ -1015,14 +1018,14 @@ impl<'a> StringReader<'a> {
 
     /// Scan over a float exponent.
     fn scan_float_exponent(&mut self) {
-        if self.curr_is('e') || self.curr_is('E') {
+        if self.ch_is('e') || self.ch_is('E') {
             self.bump();
-            if self.curr_is('-') || self.curr_is('+') {
+            if self.ch_is('-') || self.ch_is('+') {
                 self.bump();
             }
             if self.scan_digits(10, 10) == 0 {
-                self.err_span_(self.last_pos,
-                               self.pos,
+                self.err_span_(self.pos,
+                               self.next_pos,
                                "expected at least one digit in exponent")
             }
         }
@@ -1053,7 +1056,7 @@ impl<'a> StringReader<'a> {
 
     fn binop(&mut self, op: token::BinOpToken) -> token::Token {
         self.bump();
-        if self.curr_is('=') {
+        if self.ch_is('=') {
             self.bump();
             return token::BinOpEq(op);
         } else {
@@ -1064,7 +1067,7 @@ impl<'a> StringReader<'a> {
     /// Return the next token from the string, advances the input past that
     /// token, and updates the interner
     fn next_token_inner(&mut self) -> Result<token::Token, ()> {
-        let c = self.curr;
+        let c = self.ch;
         if ident_start(c) &&
            match (c.unwrap(), self.nextch(), self.nextnextch()) {
             // Note: r as in r" or r#" is part of a raw string literal,
@@ -1078,8 +1081,8 @@ impl<'a> StringReader<'a> {
             ('b', Some('r'), Some('#')) => false,
             _ => true,
         } {
-            let start = self.last_pos;
-            while ident_continue(self.curr) {
+            let start = self.pos;
+            while ident_continue(self.ch) {
                 self.bump();
             }
 
@@ -1112,9 +1115,9 @@ impl<'a> StringReader<'a> {
             }
             '.' => {
                 self.bump();
-                return if self.curr_is('.') {
+                return if self.ch_is('.') {
                     self.bump();
-                    if self.curr_is('.') {
+                    if self.ch_is('.') {
                         self.bump();
                         Ok(token::DotDotDot)
                     } else {
@@ -1166,7 +1169,7 @@ impl<'a> StringReader<'a> {
             }
             ':' => {
                 self.bump();
-                if self.curr_is(':') {
+                if self.ch_is(':') {
                     self.bump();
                     return Ok(token::ModSep);
                 } else {
@@ -1182,10 +1185,10 @@ impl<'a> StringReader<'a> {
             // Multi-byte tokens.
             '=' => {
                 self.bump();
-                if self.curr_is('=') {
+                if self.ch_is('=') {
                     self.bump();
                     return Ok(token::EqEq);
-                } else if self.curr_is('>') {
+                } else if self.ch_is('>') {
                     self.bump();
                     return Ok(token::FatArrow);
                 } else {
@@ -1194,7 +1197,7 @@ impl<'a> StringReader<'a> {
             }
             '!' => {
                 self.bump();
-                if self.curr_is('=') {
+                if self.ch_is('=') {
                     self.bump();
                     return Ok(token::Ne);
                 } else {
@@ -1203,7 +1206,7 @@ impl<'a> StringReader<'a> {
             }
             '<' => {
                 self.bump();
-                match self.curr.unwrap_or('\x00') {
+                match self.ch.unwrap_or('\x00') {
                     '=' => {
                         self.bump();
                         return Ok(token::Le);
@@ -1213,7 +1216,7 @@ impl<'a> StringReader<'a> {
                     }
                     '-' => {
                         self.bump();
-                        match self.curr.unwrap_or('\x00') {
+                        match self.ch.unwrap_or('\x00') {
                             _ => {
                                 return Ok(token::LArrow);
                             }
@@ -1226,7 +1229,7 @@ impl<'a> StringReader<'a> {
             }
             '>' => {
                 self.bump();
-                match self.curr.unwrap_or('\x00') {
+                match self.ch.unwrap_or('\x00') {
                     '=' => {
                         self.bump();
                         return Ok(token::Ge);
@@ -1241,25 +1244,25 @@ impl<'a> StringReader<'a> {
             }
             '\'' => {
                 // Either a character constant 'a' OR a lifetime name 'abc
-                let start_with_quote = self.last_pos;
+                let start_with_quote = self.pos;
                 self.bump();
-                let start = self.last_pos;
+                let start = self.pos;
 
                 // the eof will be picked up by the final `'` check below
-                let c2 = self.curr.unwrap_or('\x00');
+                let c2 = self.ch.unwrap_or('\x00');
                 self.bump();
 
                 // If the character is an ident start not followed by another single
                 // quote, then this is a lifetime name:
-                if ident_start(Some(c2)) && !self.curr_is('\'') {
-                    while ident_continue(self.curr) {
+                if ident_start(Some(c2)) && !self.ch_is('\'') {
+                    while ident_continue(self.ch) {
                         self.bump();
                     }
                     // lifetimes shouldn't end with a single quote
                     // if we find one, then this is an invalid character literal
-                    if self.curr_is('\'') {
+                    if self.ch_is('\'') {
                         panic!(self.fatal_span_verbose(
-                               start_with_quote, self.pos,
+                               start_with_quote, self.next_pos,
                                String::from("character literal may only contain one codepoint")));
 
                     }
@@ -1277,7 +1280,7 @@ impl<'a> StringReader<'a> {
                         str_to_ident(lifetime_name)
                     });
                     let keyword_checking_token = &token::Ident(keyword_checking_ident);
-                    let last_bpos = self.last_pos;
+                    let last_bpos = self.pos;
                     if keyword_checking_token.is_any_keyword() &&
                        !keyword_checking_token.is_keyword(keywords::Static) {
                         self.err_span_(start, last_bpos, "lifetimes cannot use keyword names");
@@ -1292,9 +1295,9 @@ impl<'a> StringReader<'a> {
                                                    false,
                                                    '\'');
 
-                if !self.curr_is('\'') {
+                if !self.ch_is('\'') {
                     panic!(self.fatal_span_verbose(
-                           start_with_quote, self.last_pos,
+                           start_with_quote, self.pos,
                            String::from("character literal may only contain one codepoint")));
                 }
 
@@ -1303,13 +1306,13 @@ impl<'a> StringReader<'a> {
                 } else {
                     token::intern("0")
                 };
-                self.bump(); // advance curr past token
+                self.bump(); // advance ch past token
                 let suffix = self.scan_optional_raw_name();
                 return Ok(token::Literal(token::Char(id), suffix));
             }
             'b' => {
                 self.bump();
-                let lit = match self.curr {
+                let lit = match self.ch {
                     Some('\'') => self.scan_byte(),
                     Some('"') => self.scan_byte_string(),
                     Some('r') => self.scan_raw_byte_string(),
@@ -1319,19 +1322,19 @@ impl<'a> StringReader<'a> {
                 return Ok(token::Literal(lit, suffix));
             }
             '"' => {
-                let start_bpos = self.last_pos;
+                let start_bpos = self.pos;
                 let mut valid = true;
                 self.bump();
-                while !self.curr_is('"') {
+                while !self.ch_is('"') {
                     if self.is_eof() {
-                        let last_bpos = self.last_pos;
+                        let last_bpos = self.pos;
                         panic!(self.fatal_span_(start_bpos,
                                                 last_bpos,
                                                 "unterminated double quote string"));
                     }
 
-                    let ch_start = self.last_pos;
-                    let ch = self.curr.unwrap();
+                    let ch_start = self.pos;
+                    let ch = self.ch.unwrap();
                     self.bump();
                     valid &= self.scan_char_or_byte(ch_start,
                                                     ch,
@@ -1350,20 +1353,20 @@ impl<'a> StringReader<'a> {
                 return Ok(token::Literal(token::Str_(id), suffix));
             }
             'r' => {
-                let start_bpos = self.last_pos;
+                let start_bpos = self.pos;
                 self.bump();
                 let mut hash_count = 0;
-                while self.curr_is('#') {
+                while self.ch_is('#') {
                     self.bump();
                     hash_count += 1;
                 }
 
                 if self.is_eof() {
-                    let last_bpos = self.last_pos;
+                    let last_bpos = self.pos;
                     panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated raw string"));
-                } else if !self.curr_is('"') {
-                    let last_bpos = self.last_pos;
-                    let curr_char = self.curr.unwrap();
+                } else if !self.ch_is('"') {
+                    let last_bpos = self.pos;
+                    let curr_char = self.ch.unwrap();
                     panic!(self.fatal_span_char(start_bpos,
                                                 last_bpos,
                                                 "found invalid character; only `#` is allowed \
@@ -1371,27 +1374,27 @@ impl<'a> StringReader<'a> {
                                                 curr_char));
                 }
                 self.bump();
-                let content_start_bpos = self.last_pos;
+                let content_start_bpos = self.pos;
                 let mut content_end_bpos;
                 let mut valid = true;
                 'outer: loop {
                     if self.is_eof() {
-                        let last_bpos = self.last_pos;
+                        let last_bpos = self.pos;
                         panic!(self.fatal_span_(start_bpos, last_bpos, "unterminated raw string"));
                     }
-                    // if self.curr_is('"') {
-                    // content_end_bpos = self.last_pos;
+                    // if self.ch_is('"') {
+                    // content_end_bpos = self.pos;
                     // for _ in 0..hash_count {
                     // self.bump();
-                    // if !self.curr_is('#') {
+                    // if !self.ch_is('#') {
                     // continue 'outer;
-                    let c = self.curr.unwrap();
+                    let c = self.ch.unwrap();
                     match c {
                         '"' => {
-                            content_end_bpos = self.last_pos;
+                            content_end_bpos = self.pos;
                             for _ in 0..hash_count {
                                 self.bump();
-                                if !self.curr_is('#') {
+                                if !self.ch_is('#') {
                                     continue 'outer;
                                 }
                             }
@@ -1399,7 +1402,7 @@ impl<'a> StringReader<'a> {
                         }
                         '\r' => {
                             if !self.nextch_is('\n') {
-                                let last_bpos = self.last_pos;
+                                let last_bpos = self.pos;
                                 self.err_span_(start_bpos,
                                                last_bpos,
                                                "bare CR not allowed in raw string, use \\r \
@@ -1466,8 +1469,8 @@ impl<'a> StringReader<'a> {
                 return Ok(self.binop(token::Percent));
             }
             c => {
-                let last_bpos = self.last_pos;
-                let bpos = self.pos;
+                let last_bpos = self.pos;
+                let bpos = self.next_pos;
                 let mut err = self.struct_fatal_span_char(last_bpos,
                                                           bpos,
                                                           "unknown start of token",
@@ -1480,18 +1483,18 @@ impl<'a> StringReader<'a> {
     }
 
     fn consume_whitespace(&mut self) {
-        while is_pattern_whitespace(self.curr) && !self.is_eof() {
+        while is_pattern_whitespace(self.ch) && !self.is_eof() {
             self.bump();
         }
     }
 
     fn read_to_eol(&mut self) -> String {
         let mut val = String::new();
-        while !self.curr_is('\n') && !self.is_eof() {
-            val.push(self.curr.unwrap());
+        while !self.ch_is('\n') && !self.is_eof() {
+            val.push(self.ch.unwrap());
             self.bump();
         }
-        if self.curr_is('\n') {
+        if self.ch_is('\n') {
             self.bump();
         }
         return val;
@@ -1505,23 +1508,23 @@ impl<'a> StringReader<'a> {
     }
 
     fn consume_non_eol_whitespace(&mut self) {
-        while is_pattern_whitespace(self.curr) && !self.curr_is('\n') && !self.is_eof() {
+        while is_pattern_whitespace(self.ch) && !self.ch_is('\n') && !self.is_eof() {
             self.bump();
         }
     }
 
     fn peeking_at_comment(&self) -> bool {
-        (self.curr_is('/') && self.nextch_is('/')) || (self.curr_is('/') && self.nextch_is('*')) ||
+        (self.ch_is('/') && self.nextch_is('/')) || (self.ch_is('/') && self.nextch_is('*')) ||
         // consider shebangs comments, but not inner attributes
-        (self.curr_is('#') && self.nextch_is('!') && !self.nextnextch_is('['))
+        (self.ch_is('#') && self.nextch_is('!') && !self.nextnextch_is('['))
     }
 
     fn scan_byte(&mut self) -> token::Lit {
         self.bump();
-        let start = self.last_pos;
+        let start = self.pos;
 
         // the eof will be picked up by the final `'` check below
-        let c2 = self.curr.unwrap_or('\x00');
+        let c2 = self.ch.unwrap_or('\x00');
         self.bump();
 
         let valid = self.scan_char_or_byte(start,
@@ -1529,13 +1532,13 @@ impl<'a> StringReader<'a> {
                                            // ascii_only =
                                            true,
                                            '\'');
-        if !self.curr_is('\'') {
+        if !self.ch_is('\'') {
             // Byte offsetting here is okay because the
             // character before position `start` are an
             // ascii single quote and ascii 'b'.
-            let last_pos = self.last_pos;
+            let pos = self.pos;
             panic!(self.fatal_span_verbose(start - BytePos(2),
-                                           last_pos,
+                                           pos,
                                            "unterminated byte constant".to_string()));
         }
 
@@ -1544,7 +1547,7 @@ impl<'a> StringReader<'a> {
         } else {
             token::intern("?")
         };
-        self.bump(); // advance curr past token
+        self.bump(); // advance ch past token
         return token::Byte(id);
     }
 
@@ -1554,17 +1557,17 @@ impl<'a> StringReader<'a> {
 
     fn scan_byte_string(&mut self) -> token::Lit {
         self.bump();
-        let start = self.last_pos;
+        let start = self.pos;
         let mut valid = true;
 
-        while !self.curr_is('"') {
+        while !self.ch_is('"') {
             if self.is_eof() {
-                let last_pos = self.last_pos;
-                panic!(self.fatal_span_(start, last_pos, "unterminated double quote byte string"));
+                let pos = self.pos;
+                panic!(self.fatal_span_(start, pos, "unterminated double quote byte string"));
             }
 
-            let ch_start = self.last_pos;
-            let ch = self.curr.unwrap();
+            let ch_start = self.pos;
+            let ch = self.ch.unwrap();
             self.bump();
             valid &= self.scan_char_or_byte(ch_start,
                                             ch,
@@ -1582,40 +1585,40 @@ impl<'a> StringReader<'a> {
     }
 
     fn scan_raw_byte_string(&mut self) -> token::Lit {
-        let start_bpos = self.last_pos;
+        let start_bpos = self.pos;
         self.bump();
         let mut hash_count = 0;
-        while self.curr_is('#') {
+        while self.ch_is('#') {
             self.bump();
             hash_count += 1;
         }
 
         if self.is_eof() {
-            let last_pos = self.last_pos;
-            panic!(self.fatal_span_(start_bpos, last_pos, "unterminated raw string"));
-        } else if !self.curr_is('"') {
-            let last_pos = self.last_pos;
-            let ch = self.curr.unwrap();
+            let pos = self.pos;
+            panic!(self.fatal_span_(start_bpos, pos, "unterminated raw string"));
+        } else if !self.ch_is('"') {
+            let pos = self.pos;
+            let ch = self.ch.unwrap();
             panic!(self.fatal_span_char(start_bpos,
-                                        last_pos,
+                                        pos,
                                         "found invalid character; only `#` is allowed in raw \
                                          string delimitation",
                                         ch));
         }
         self.bump();
-        let content_start_bpos = self.last_pos;
+        let content_start_bpos = self.pos;
         let mut content_end_bpos;
         'outer: loop {
-            match self.curr {
+            match self.ch {
                 None => {
-                    let last_pos = self.last_pos;
-                    panic!(self.fatal_span_(start_bpos, last_pos, "unterminated raw string"))
+                    let pos = self.pos;
+                    panic!(self.fatal_span_(start_bpos, pos, "unterminated raw string"))
                 }
                 Some('"') => {
-                    content_end_bpos = self.last_pos;
+                    content_end_bpos = self.pos;
                     for _ in 0..hash_count {
                         self.bump();
-                        if !self.curr_is('#') {
+                        if !self.ch_is('#') {
                             continue 'outer;
                         }
                     }
@@ -1623,8 +1626,8 @@ impl<'a> StringReader<'a> {
                 }
                 Some(c) => {
                     if c > '\x7F' {
-                        let last_pos = self.last_pos;
-                        self.err_span_char(last_pos, last_pos, "raw byte string must be ASCII", c);
+                        let pos = self.pos;
+                        self.err_span_char(pos, pos, "raw byte string must be ASCII", c);
                     }
                 }
             }
@@ -1738,7 +1741,7 @@ mod tests {
         assert_eq!(tok1, tok2);
         assert_eq!(string_reader.next_token().tok, token::Whitespace);
         // the 'main' id is already read:
-        assert_eq!(string_reader.last_pos.clone(), BytePos(28));
+        assert_eq!(string_reader.pos.clone(), BytePos(28));
         // read another token:
         let tok3 = string_reader.next_token();
         let tok4 = TokenAndSpan {
@@ -1751,7 +1754,7 @@ mod tests {
         };
         assert_eq!(tok3, tok4);
         // the lparen is already read:
-        assert_eq!(string_reader.last_pos.clone(), BytePos(29))
+        assert_eq!(string_reader.pos.clone(), BytePos(29))
     }
 
     // check that the given reader produces the desired stream
diff --git a/src/libsyntax/parse/lexer/unicode_chars.rs b/src/libsyntax/parse/lexer/unicode_chars.rs
index dab97d1d5a6..1e08b20b7e1 100644
--- a/src/libsyntax/parse/lexer/unicode_chars.rs
+++ b/src/libsyntax/parse/lexer/unicode_chars.rs
@@ -234,7 +234,7 @@ pub fn check_for_substitution<'a>(reader: &StringReader<'a>,
     .iter()
     .find(|&&(c, _, _)| c == ch)
     .map(|&(_, u_name, ascii_char)| {
-        let span = make_span(reader.last_pos, reader.pos);
+        let span = make_span(reader.pos, reader.next_pos);
         match ASCII_ARRAY.iter().find(|&&(c, _)| c == ascii_char) {
             Some(&(ascii_char, ascii_name)) => {
                 let msg =
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 9b6002b2469..61268d457ce 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -238,7 +238,7 @@ fn maybe_append(mut lhs: Vec<Attribute>, rhs: Option<Vec<Attribute>>)
 }
 
 #[derive(PartialEq)]
-enum LastTokenKind {
+enum PrevTokenKind {
     DocComment,
     Comma,
     Interpolated,
@@ -254,11 +254,11 @@ pub struct Parser<'a> {
     pub token: token::Token,
     /// the span of the current token:
     pub span: Span,
-    /// the span of the prior token:
-    pub last_span: Span,
+    /// the span of the previous token:
+    pub prev_span: Span,
     pub cfg: CrateConfig,
     /// the previous token kind
-    last_token_kind: LastTokenKind,
+    prev_token_kind: PrevTokenKind,
     pub buffer: [TokenAndSpan; 4],
     pub buffer_start: isize,
     pub buffer_end: isize,
@@ -368,8 +368,8 @@ impl<'a> Parser<'a> {
             cfg: cfg,
             token: tok0.tok,
             span: span,
-            last_span: span,
-            last_token_kind: LastTokenKind::Other,
+            prev_span: span,
+            prev_token_kind: PrevTokenKind::Other,
             buffer: [
                 placeholder.clone(),
                 placeholder.clone(),
@@ -414,8 +414,7 @@ impl<'a> Parser<'a> {
 
     pub fn unexpected_last<T>(&self, t: &token::Token) -> PResult<'a, T> {
         let token_str = Parser::token_to_string(t);
-        let last_span = self.last_span;
-        Err(self.span_fatal(last_span, &format!("unexpected token: `{}`", token_str)))
+        Err(self.span_fatal(self.prev_span, &format!("unexpected token: `{}`", token_str)))
     }
 
     pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
@@ -505,8 +504,8 @@ impl<'a> Parser<'a> {
                                  expr: PResult<'a, P<Expr>>)
                                  -> PResult<'a, (Span, P<Expr>)> {
         expr.map(|e| {
-            if self.last_token_kind == LastTokenKind::Interpolated {
-                (self.last_span, e)
+            if self.prev_token_kind == PrevTokenKind::Interpolated {
+                (self.prev_span, e)
             } else {
                 (e.span, e)
             }
@@ -525,8 +524,8 @@ impl<'a> Parser<'a> {
                 self.bug("ident interpolation not converted to real token");
             }
             _ => {
-                Err(if self.last_token_kind == LastTokenKind::DocComment {
-                    self.span_fatal_help(self.last_span,
+                Err(if self.prev_token_kind == PrevTokenKind::DocComment {
+                    self.span_fatal_help(self.prev_span,
                         "found a documentation comment that doesn't document anything",
                         "doc comments must come before what they document, maybe a comment was \
                         intended with `//`?")
@@ -923,20 +922,20 @@ impl<'a> Parser<'a> {
 
     /// Advance the parser by one token
     pub fn bump(&mut self) {
-        if self.last_token_kind == LastTokenKind::Eof {
+        if self.prev_token_kind == PrevTokenKind::Eof {
             // Bumping after EOF is a bad sign, usually an infinite loop.
             self.bug("attempted to bump the parser past EOF (may be stuck in a loop)");
         }
 
-        self.last_span = self.span;
+        self.prev_span = self.span;
 
         // Record last token kind for possible error recovery.
-        self.last_token_kind = match self.token {
-            token::DocComment(..) => LastTokenKind::DocComment,
-            token::Comma => LastTokenKind::Comma,
-            token::Interpolated(..) => LastTokenKind::Interpolated,
-            token::Eof => LastTokenKind::Eof,
-            _ => LastTokenKind::Other,
+        self.prev_token_kind = match self.token {
+            token::DocComment(..) => PrevTokenKind::DocComment,
+            token::Comma => PrevTokenKind::Comma,
+            token::Interpolated(..) => PrevTokenKind::Interpolated,
+            token::Eof => PrevTokenKind::Eof,
+            _ => PrevTokenKind::Other,
         };
 
         let next = if self.buffer_start == self.buffer_end {
@@ -974,11 +973,11 @@ impl<'a> Parser<'a> {
                      next: token::Token,
                      lo: BytePos,
                      hi: BytePos) {
-        self.last_span = mk_sp(self.span.lo, lo);
+        self.prev_span = mk_sp(self.span.lo, lo);
         // It would be incorrect to record the kind of the current token, but
         // fortunately for tokens currently using `bump_with`, the
-        // last_token_kind will be of no use anyway.
-        self.last_token_kind = LastTokenKind::Other;
+        // prev_token_kind will be of no use anyway.
+        self.prev_token_kind = PrevTokenKind::Other;
         self.span = mk_sp(lo, hi);
         self.token = next;
         self.expected_tokens.clear();
@@ -1114,8 +1113,7 @@ impl<'a> Parser<'a> {
         let bounds = self.parse_ty_param_bounds(BoundParsingMode::Modified)?;
 
         if !bounds.iter().any(|b| if let TraitTyParamBound(..) = *b { true } else { false }) {
-            let last_span = self.last_span;
-            self.span_err(last_span, "at least one trait must be specified");
+            self.span_err(self.prev_span, "at least one trait must be specified");
         }
 
         Ok(ast::TyKind::ImplTrait(bounds))
@@ -1213,7 +1211,7 @@ impl<'a> Parser<'a> {
                 self.expect(&token::Semi)?
             }
 
-            let mac = spanned(lo, self.last_span.hi, Mac_ { path: pth, tts: tts });
+            let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts });
             (keywords::Invalid.ident(), ast::TraitItemKind::Macro(mac))
         } else {
             let (constness, unsafety, abi) = match self.parse_fn_front_matter() {
@@ -1283,7 +1281,7 @@ impl<'a> Parser<'a> {
             ident: name,
             attrs: attrs,
             node: node,
-            span: mk_sp(lo, self.last_span.hi),
+            span: mk_sp(lo, self.prev_span.hi),
         })
     }
 
@@ -1330,13 +1328,13 @@ impl<'a> Parser<'a> {
         // In type grammar, `+` is treated like a binary operator,
         // and hence both L and R side are required.
         if bounds.is_empty() {
-            let last_span = self.last_span;
-            self.span_err(last_span,
+            let prev_span = self.prev_span;
+            self.span_err(prev_span,
                           "at least one type parameter bound \
                           must be specified");
         }
 
-        let sp = mk_sp(lo, self.last_span.hi);
+        let sp = mk_sp(lo, self.prev_span.hi);
         let sum = ast::TyKind::ObjectSum(lhs, bounds);
         Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: sum, span: sp}))
     }
@@ -1438,7 +1436,7 @@ impl<'a> Parser<'a> {
             return Err(self.fatal(&msg));
         };
 
-        let sp = mk_sp(lo, self.last_span.hi);
+        let sp = mk_sp(lo, self.prev_span.hi);
         Ok(P(Ty {id: ast::DUMMY_NODE_ID, node: t, span: sp}))
     }
 
@@ -1456,7 +1454,7 @@ impl<'a> Parser<'a> {
         } else if self.eat_keyword(keywords::Const) {
             Mutability::Immutable
         } else {
-            let span = self.last_span;
+            let span = self.prev_span;
             self.span_err(span,
                           "expected mut or const in raw pointer type (use \
                            `*mut T` or `*const T` as appropriate)");
@@ -1499,7 +1497,7 @@ impl<'a> Parser<'a> {
             pat
         } else {
             debug!("parse_arg_general ident_to_pat");
-            let sp = self.last_span;
+            let sp = self.prev_span;
             let spanned = Spanned { span: sp, node: keywords::Invalid.ident() };
             P(Pat {
                 id: ast::DUMMY_NODE_ID,
@@ -1624,7 +1622,7 @@ impl<'a> Parser<'a> {
             let lit = self.parse_lit_token()?;
             lit
         };
-        Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.last_span.hi) })
+        Ok(codemap::Spanned { node: lit, span: mk_sp(lo, self.prev_span.hi) })
     }
 
     /// matches '-' lit | lit
@@ -1633,11 +1631,11 @@ impl<'a> Parser<'a> {
         let minus_present = self.eat(&token::BinOp(token::Minus));
         let lo = self.span.lo;
         let literal = P(self.parse_lit()?);
-        let hi = self.last_span.hi;
+        let hi = self.prev_span.hi;
         let expr = self.mk_expr(lo, hi, ExprKind::Lit(literal), ThinVec::new());
 
         if minus_present {
-            let minus_hi = self.last_span.hi;
+            let minus_hi = self.prev_span.hi;
             let unary = self.mk_unary(UnOp::Neg, expr);
             Ok(self.mk_expr(minus_lo, minus_hi, unary, ThinVec::new()))
         } else {
@@ -1672,7 +1670,7 @@ impl<'a> Parser<'a> {
     /// `<T as U>::F::a::<S>`
     pub fn parse_qualified_path(&mut self, mode: PathStyle)
                                 -> PResult<'a, (QSelf, ast::Path)> {
-        let span = self.last_span;
+        let span = self.prev_span;
         let self_type = self.parse_ty_sum()?;
         let mut path = if self.eat_keyword(keywords::As) {
             self.parse_path(PathStyle::Type)?
@@ -1705,7 +1703,7 @@ impl<'a> Parser<'a> {
         };
         path.segments.extend(segments);
 
-        path.span.hi = self.last_span.hi;
+        path.span.hi = self.prev_span.hi;
 
         Ok((qself, path))
     }
@@ -1743,7 +1741,7 @@ impl<'a> Parser<'a> {
         };
 
         // Assemble the span.
-        let span = mk_sp(lo, self.last_span.hi);
+        let span = mk_sp(lo, self.prev_span.hi);
 
         // Assemble the result.
         Ok(ast::Path {
@@ -1773,7 +1771,7 @@ impl<'a> Parser<'a> {
                     bindings: P::from_vec(bindings),
                 })
             } else if self.eat(&token::OpenDelim(token::Paren)) {
-                let lo = self.last_span.lo;
+                let lo = self.prev_span.lo;
 
                 let inputs = self.parse_seq_to_end(
                     &token::CloseDelim(token::Paren),
@@ -1786,7 +1784,7 @@ impl<'a> Parser<'a> {
                     None
                 };
 
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
 
                 ast::PathParameters::Parenthesized(ast::ParenthesizedParameterData {
                     span: mk_sp(lo, hi),
@@ -2017,7 +2015,7 @@ impl<'a> Parser<'a> {
     pub fn parse_field(&mut self) -> PResult<'a, Field> {
         let lo = self.span.lo;
         let i = self.parse_field_name()?;
-        let hi = self.last_span.hi;
+        let hi = self.prev_span.hi;
         self.expect(&token::Colon)?;
         let e = self.parse_expr()?;
         Ok(ast::Field {
@@ -2172,7 +2170,7 @@ impl<'a> Parser<'a> {
                 }
                 self.bump();
 
-                hi = self.last_span.hi;
+                hi = self.prev_span.hi;
                 return if es.len() == 1 && !trailing_comma {
                     Ok(self.mk_expr(lo, hi, ExprKind::Paren(es.into_iter().nth(0).unwrap()), attrs))
                 } else {
@@ -2221,7 +2219,7 @@ impl<'a> Parser<'a> {
                         ex = ExprKind::Vec(vec!(first_expr));
                     }
                 }
-                hi = self.last_span.hi;
+                hi = self.prev_span.hi;
             }
             _ => {
                 if self.eat_lt() {
@@ -2231,18 +2229,18 @@ impl<'a> Parser<'a> {
                     return Ok(self.mk_expr(lo, hi, ExprKind::Path(Some(qself), path), attrs));
                 }
                 if self.eat_keyword(keywords::Move) {
-                    let lo = self.last_span.lo;
+                    let lo = self.prev_span.lo;
                     return self.parse_lambda_expr(lo, CaptureBy::Value, attrs);
                 }
                 if self.eat_keyword(keywords::If) {
                     return self.parse_if_expr(attrs);
                 }
                 if self.eat_keyword(keywords::For) {
-                    let lo = self.last_span.lo;
+                    let lo = self.prev_span.lo;
                     return self.parse_for_expr(None, lo, attrs);
                 }
                 if self.eat_keyword(keywords::While) {
-                    let lo = self.last_span.lo;
+                    let lo = self.prev_span.lo;
                     return self.parse_while_expr(None, lo, attrs);
                 }
                 if self.token.is_lifetime() {
@@ -2263,7 +2261,7 @@ impl<'a> Parser<'a> {
                     return Err(self.fatal("expected `while`, `for`, or `loop` after a label"))
                 }
                 if self.eat_keyword(keywords::Loop) {
-                    let lo = self.last_span.lo;
+                    let lo = self.prev_span.lo;
                     return self.parse_loop_expr(None, lo, attrs);
                 }
                 if self.eat_keyword(keywords::Continue) {
@@ -2277,7 +2275,7 @@ impl<'a> Parser<'a> {
                     } else {
                         ExprKind::Continue(None)
                     };
-                    let hi = self.last_span.hi;
+                    let hi = self.prev_span.hi;
                     return Ok(self.mk_expr(lo, hi, ex, attrs));
                 }
                 if self.eat_keyword(keywords::Match) {
@@ -2307,7 +2305,7 @@ impl<'a> Parser<'a> {
                     } else {
                         ex = ExprKind::Break(None);
                     }
-                    hi = self.last_span.hi;
+                    hi = self.prev_span.hi;
                 } else if self.token.is_keyword(keywords::Let) {
                     // Catch this syntax error here, instead of in `check_strict_keywords`, so
                     // that we can explicitly mention that let is not to be used as an expression
@@ -2324,7 +2322,7 @@ impl<'a> Parser<'a> {
                         let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
                                                         SeqSep::none(),
                                                         |p| p.parse_token_tree())?;
-                        let hi = self.last_span.hi;
+                        let hi = self.prev_span.hi;
                         return Ok(self.mk_mac_expr(lo, hi, Mac_ { path: pth, tts: tts }, attrs));
                     }
                     if self.check(&token::OpenDelim(token::Brace)) {
@@ -2489,8 +2487,8 @@ impl<'a> Parser<'a> {
         };
 
         if !bindings.is_empty() {
-            let last_span = self.last_span;
-            self.span_err(last_span, "type bindings are only permitted on trait paths");
+            let prev_span = self.prev_span;
+            self.span_err(prev_span, "type bindings are only permitted on trait paths");
         }
 
         Ok(match self.token {
@@ -2502,7 +2500,7 @@ impl<'a> Parser<'a> {
                     SeqSep::trailing_allowed(token::Comma),
                     |p| Ok(p.parse_expr()?)
                 )?;
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
 
                 es.insert(0, self_value);
                 let id = spanned(ident_span.lo, ident_span.hi, ident);
@@ -2512,8 +2510,8 @@ impl<'a> Parser<'a> {
             // Field access.
             _ => {
                 if !tys.is_empty() {
-                    let last_span = self.last_span;
-                    self.span_err(last_span,
+                    let prev_span = self.prev_span;
+                    self.span_err(prev_span,
                                   "field expressions may not \
                                    have type parameters");
                 }
@@ -2531,7 +2529,7 @@ impl<'a> Parser<'a> {
         loop {
             // expr?
             while self.eat(&token::Question) {
-                let hi = self.last_span.hi;
+                let hi = self.prev_span.hi;
                 e = self.mk_expr(lo, hi, ExprKind::Try(e), ThinVec::new());
             }
 
@@ -2539,7 +2537,7 @@ impl<'a> Parser<'a> {
             if self.eat(&token::Dot) {
                 match self.token {
                   token::Ident(i) => {
-                    let dot_pos = self.last_span.hi;
+                    let dot_pos = self.prev_span.hi;
                     hi = self.span.hi;
                     self.bump();
 
@@ -2551,7 +2549,7 @@ impl<'a> Parser<'a> {
                     // A tuple index may not have a suffix
                     self.expect_no_suffix(sp, "tuple index", suf);
 
-                    let dot = self.last_span.hi;
+                    let dot = self.prev_span.hi;
                     hi = self.span.hi;
                     self.bump();
 
@@ -2563,16 +2561,16 @@ impl<'a> Parser<'a> {
                             e = self.mk_expr(lo, hi, field, ThinVec::new());
                         }
                         None => {
-                            let last_span = self.last_span;
-                            self.span_err(last_span, "invalid tuple or tuple struct index");
+                            let prev_span = self.prev_span;
+                            self.span_err(prev_span, "invalid tuple or tuple struct index");
                         }
                     }
                   }
                   token::Literal(token::Float(n), _suf) => {
                     self.bump();
-                    let last_span = self.last_span;
+                    let prev_span = self.prev_span;
                     let fstr = n.as_str();
-                    let mut err = self.diagnostic().struct_span_err(last_span,
+                    let mut err = self.diagnostic().struct_span_err(prev_span,
                         &format!("unexpected token: `{}`", n.as_str()));
                     if fstr.chars().all(|x| "0123456789.".contains(x)) {
                         let float = match fstr.parse::<f64>().ok() {
@@ -2591,7 +2589,7 @@ impl<'a> Parser<'a> {
                     let actual = self.this_token_to_string();
                     self.span_err(self.span, &format!("unexpected token: `{}`", actual));
 
-                    let dot_pos = self.last_span.hi;
+                    let dot_pos = self.prev_span.hi;
                     e = self.parse_dot_suffix(keywords::Invalid.ident(),
                                               mk_sp(dot_pos, dot_pos),
                                               e, lo)?;
@@ -2609,7 +2607,7 @@ impl<'a> Parser<'a> {
                     SeqSep::trailing_allowed(token::Comma),
                     |p| Ok(p.parse_expr()?)
                 )?;
-                hi = self.last_span.hi;
+                hi = self.prev_span.hi;
 
                 let nd = self.mk_call(e, es);
                 e = self.mk_expr(lo, hi, nd, ThinVec::new());
@@ -2952,8 +2950,8 @@ impl<'a> Parser<'a> {
         self.expected_tokens.push(TokenType::Operator);
         while let Some(op) = AssocOp::from_token(&self.token) {
 
-            let lhs_span = if self.last_token_kind == LastTokenKind::Interpolated {
-                self.last_span
+            let lhs_span = if self.prev_token_kind == PrevTokenKind::Interpolated {
+                self.prev_span
             } else {
                 lhs.span
             };
@@ -3146,7 +3144,7 @@ impl<'a> Parser<'a> {
         if self.check_keyword(keywords::Let) {
             return self.parse_if_let_expr(attrs);
         }
-        let lo = self.last_span.lo;
+        let lo = self.prev_span.lo;
         let cond = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL, None)?;
         let thn = self.parse_block()?;
         let mut els: Option<P<Expr>> = None;
@@ -3162,7 +3160,7 @@ impl<'a> Parser<'a> {
     /// Parse an 'if let' expression ('if' token already eaten)
     pub fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>)
                              -> PResult<'a, P<Expr>> {
-        let lo = self.last_span.lo;
+        let lo = self.prev_span.lo;
         self.expect_keyword(keywords::Let)?;
         let pat = self.parse_pat()?;
         self.expect(&token::Eq)?;
@@ -3185,7 +3183,7 @@ impl<'a> Parser<'a> {
                              -> PResult<'a, P<Expr>>
     {
         let decl = self.parse_fn_block_decl()?;
-        let decl_hi = self.last_span.hi;
+        let decl_hi = self.prev_span.hi;
         let body = match decl.output {
             FunctionRetTy::Default(_) => {
                 // If no explicit return type is given, parse any
@@ -3238,7 +3236,7 @@ impl<'a> Parser<'a> {
         let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
 
-        let hi = self.last_span.hi;
+        let hi = self.prev_span.hi;
 
         Ok(self.mk_expr(span_lo, hi,
                         ExprKind::ForLoop(pat, expr, loop_block, opt_ident),
@@ -3286,8 +3284,8 @@ impl<'a> Parser<'a> {
 
     // `match` token already eaten
     fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
-        let match_span = self.last_span;
-        let lo = self.last_span.lo;
+        let match_span = self.prev_span;
+        let lo = self.prev_span.lo;
         let discriminant = self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL,
                                                None)?;
         if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) {
@@ -3409,7 +3407,7 @@ impl<'a> Parser<'a> {
                 }
             } else if ddpos.is_some() && self.eat(&token::DotDot) {
                 // Emit a friendly error, ignore `..` and continue parsing
-                self.span_err(self.last_span, "`..` can only be used once per \
+                self.span_err(self.prev_span, "`..` can only be used once per \
                                                tuple or tuple struct pattern");
             } else {
                 fields.push(self.parse_pat()?);
@@ -3520,7 +3518,7 @@ impl<'a> Parser<'a> {
                 let is_ref = self.eat_keyword(keywords::Ref);
                 let is_mut = self.eat_keyword(keywords::Mut);
                 let fieldname = self.parse_ident()?;
-                hi = self.last_span.hi;
+                hi = self.prev_span.hi;
 
                 let bind_type = match (is_ref, is_mut) {
                     (true, true) => BindingMode::ByRef(Mutability::Mutable),
@@ -3528,7 +3526,7 @@ impl<'a> Parser<'a> {
                     (false, true) => BindingMode::ByValue(Mutability::Mutable),
                     (false, false) => BindingMode::ByValue(Mutability::Immutable),
                 };
-                let fieldpath = codemap::Spanned{span:self.last_span, node:fieldname};
+                let fieldpath = codemap::Spanned{span:self.prev_span, node:fieldname};
                 let fieldpat = P(ast::Pat{
                     id: ast::DUMMY_NODE_ID,
                     node: PatKind::Ident(bind_type, fieldpath, None),
@@ -3567,7 +3565,7 @@ impl<'a> Parser<'a> {
                 // Parse an unqualified path
                 (None, self.parse_path(PathStyle::Expr)?)
             };
-            let hi = self.last_span.hi;
+            let hi = self.prev_span.hi;
             Ok(self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new()))
         } else {
             self.parse_pat_literal_maybe_minus()
@@ -3651,12 +3649,12 @@ impl<'a> Parser<'a> {
                         let tts = self.parse_seq_to_end(&token::CloseDelim(delim),
                                                         SeqSep::none(),
                                                         |p| p.parse_token_tree())?;
-                        let mac = spanned(lo, self.last_span.hi, Mac_ { path: path, tts: tts });
+                        let mac = spanned(lo, self.prev_span.hi, Mac_ { path: path, tts: tts });
                         pat = PatKind::Mac(mac);
                     }
                     token::DotDotDot => {
                         // Parse range
-                        let hi = self.last_span.hi;
+                        let hi = self.prev_span.hi;
                         let begin =
                               self.mk_expr(lo, hi, ExprKind::Path(qself, path), ThinVec::new());
                         self.bump();
@@ -3709,7 +3707,7 @@ impl<'a> Parser<'a> {
             }
         }
 
-        let hi = self.last_span.hi;
+        let hi = self.prev_span.hi;
         Ok(P(ast::Pat {
             id: ast::DUMMY_NODE_ID,
             node: pat,
@@ -3724,8 +3722,8 @@ impl<'a> Parser<'a> {
                        binding_mode: ast::BindingMode)
                        -> PResult<'a, PatKind> {
         let ident = self.parse_ident()?;
-        let last_span = self.last_span;
-        let name = codemap::Spanned{span: last_span, node: ident};
+        let prev_span = self.prev_span;
+        let name = codemap::Spanned{span: prev_span, node: ident};
         let sub = if self.eat(&token::At) {
             Some(self.parse_pat()?)
         } else {
@@ -3739,9 +3737,8 @@ impl<'a> Parser<'a> {
         // binding mode then we do not end up here, because the lookahead
         // will direct us over to parse_enum_variant()
         if self.token == token::OpenDelim(token::Paren) {
-            let last_span = self.last_span;
             return Err(self.span_fatal(
-                last_span,
+                self.prev_span,
                 "expected identifier, found enum pattern"))
         }
 
@@ -3763,7 +3760,7 @@ impl<'a> Parser<'a> {
             pat: pat,
             init: init,
             id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, self.last_span.hi),
+            span: mk_sp(lo, self.prev_span.hi),
             attrs: attrs,
         }))
     }
@@ -3778,7 +3775,7 @@ impl<'a> Parser<'a> {
         self.expect(&token::Colon)?;
         let ty = self.parse_ty_sum()?;
         Ok(StructField {
-            span: mk_sp(lo, self.last_span.hi),
+            span: mk_sp(lo, self.prev_span.hi),
             ident: Some(name),
             vis: vis,
             id: ast::DUMMY_NODE_ID,
@@ -3796,7 +3793,7 @@ impl<'a> Parser<'a> {
             _ => "expected item after attributes",
         };
 
-        self.span_err(self.last_span, message);
+        self.span_err(self.prev_span, message);
     }
 
     /// Parse a statement. This stops just before trailing semicolons on everything but items.
@@ -3886,7 +3883,7 @@ impl<'a> Parser<'a> {
             Stmt {
                 id: ast::DUMMY_NODE_ID,
                 node: StmtKind::Local(self.parse_local(attrs.into())?),
-                span: mk_sp(lo, self.last_span.hi),
+                span: mk_sp(lo, self.prev_span.hi),
             }
         } else if self.token.is_path_start() && self.token != token::Lt && {
             !self.check_keyword(keywords::Union) ||
@@ -3898,7 +3895,7 @@ impl<'a> Parser<'a> {
                 let expr = if self.check(&token::OpenDelim(token::Brace)) {
                     self.parse_struct_expr(lo, pth, ThinVec::new())?
                 } else {
-                    let hi = self.last_span.hi;
+                    let hi = self.prev_span.hi;
                     self.mk_expr(lo, hi, ExprKind::Path(None, pth), ThinVec::new())
                 };
 
@@ -3910,7 +3907,7 @@ impl<'a> Parser<'a> {
                 return Ok(Some(Stmt {
                     id: ast::DUMMY_NODE_ID,
                     node: StmtKind::Expr(expr),
-                    span: mk_sp(lo, self.last_span.hi),
+                    span: mk_sp(lo, self.prev_span.hi),
                 }));
             }
 
@@ -3946,7 +3943,7 @@ impl<'a> Parser<'a> {
                 SeqSep::none(),
                 |p| p.parse_token_tree()
             )?;
-            let hi = self.last_span.hi;
+            let hi = self.prev_span.hi;
 
             let style = if delim == token::Brace {
                 MacStmtStyle::Braces
@@ -3991,8 +3988,7 @@ impl<'a> Parser<'a> {
                 // Require a semicolon or braces.
                 if style != MacStmtStyle::Braces {
                     if !self.eat(&token::Semi) {
-                        let last_span = self.last_span;
-                        self.span_err(last_span,
+                        self.span_err(self.prev_span,
                                       "macros that expand to items must \
                                        either be surrounded with braces or \
                                        followed by a semicolon");
@@ -4023,8 +4019,8 @@ impl<'a> Parser<'a> {
                 None => {
                     let unused_attrs = |attrs: &[_], s: &mut Self| {
                         if attrs.len() > 0 {
-                            if s.last_token_kind == LastTokenKind::DocComment {
-                                s.span_err_help(s.last_span,
+                            if s.prev_token_kind == PrevTokenKind::DocComment {
+                                s.span_err_help(s.prev_span,
                                     "found a documentation comment that doesn't document anything",
                                     "doc comments must come before what they document, maybe a \
                                     comment was intended with `//`?");
@@ -4087,7 +4083,7 @@ impl<'a> Parser<'a> {
                     let mut stmt_span = stmt.span;
                     // expand the span to include the semicolon, if it exists
                     if self.eat(&token::Semi) {
-                        stmt_span.hi = self.last_span.hi;
+                        stmt_span.hi = self.prev_span.hi;
                     }
                     e.span_help(stmt_span, "try placing this code inside a block");
                 }
@@ -4133,7 +4129,7 @@ impl<'a> Parser<'a> {
             stmts: stmts,
             id: ast::DUMMY_NODE_ID,
             rules: s,
-            span: mk_sp(lo, self.last_span.hi),
+            span: mk_sp(lo, self.prev_span.hi),
         }))
     }
 
@@ -4172,7 +4168,7 @@ impl<'a> Parser<'a> {
             stmt = stmt.add_trailing_semicolon();
         }
 
-        stmt.span.hi = self.last_span.hi;
+        stmt.span.hi = self.prev_span.hi;
         Ok(Some(stmt))
     }
 
@@ -4308,8 +4304,8 @@ impl<'a> Parser<'a> {
                 if ty_param.default.is_some() {
                     seen_default = true;
                 } else if seen_default {
-                    let last_span = p.last_span;
-                    p.span_err(last_span,
+                    let prev_span = p.prev_span;
+                    p.span_err(prev_span,
                                "type parameters with a default must be trailing");
                 }
                 Ok(ty_param)
@@ -4327,7 +4323,7 @@ impl<'a> Parser<'a> {
                     id: ast::DUMMY_NODE_ID,
                     predicates: Vec::new(),
                 },
-                span: mk_sp(span_lo, self.last_span.hi),
+                span: mk_sp(span_lo, self.prev_span.hi),
             })
         } else {
             Ok(ast::Generics::default())
@@ -4342,7 +4338,7 @@ impl<'a> Parser<'a> {
 
         let missing_comma = !lifetimes.is_empty() &&
                             !self.token.is_like_gt() &&
-                            self.last_token_kind != LastTokenKind::Comma;
+                            self.prev_token_kind != PrevTokenKind::Comma;
 
         if missing_comma {
 
@@ -4449,7 +4445,7 @@ impl<'a> Parser<'a> {
                     let bounds =
                         self.parse_lifetimes(token::BinOp(token::Plus))?;
 
-                    let hi = self.last_span.hi;
+                    let hi = self.prev_span.hi;
                     let span = mk_sp(lo, hi);
 
                     where_clause.predicates.push(ast::WherePredicate::RegionPredicate(
@@ -4478,7 +4474,7 @@ impl<'a> Parser<'a> {
 
                     if self.eat(&token::Colon) {
                         let bounds = self.parse_ty_param_bounds(BoundParsingMode::Bare)?;
-                        let hi = self.last_span.hi;
+                        let hi = self.prev_span.hi;
                         let span = mk_sp(lo, hi);
 
                         if bounds.is_empty() {
@@ -4498,7 +4494,7 @@ impl<'a> Parser<'a> {
                         parsed_something = true;
                     } else if self.eat(&token::Eq) {
                         // let ty = try!(self.parse_ty());
-                        let hi = self.last_span.hi;
+                        let hi = self.prev_span.hi;
                         let span = mk_sp(lo, hi);
                         // where_clause.predicates.push(
                         //     ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
@@ -4513,8 +4509,8 @@ impl<'a> Parser<'a> {
                                      "equality constraints are not yet supported \
                                      in where clauses (#20041)");
                     } else {
-                        let last_span = self.last_span;
-                        self.span_err(last_span,
+                        let prev_span = self.prev_span;
+                        self.span_err(prev_span,
                               "unexpected token in `where` clause");
                     }
                 }
@@ -4526,8 +4522,8 @@ impl<'a> Parser<'a> {
         }
 
         if !parsed_something {
-            let last_span = self.last_span;
-            self.span_err(last_span,
+            let prev_span = self.prev_span;
+            self.span_err(prev_span,
                           "a `where` clause must have at least one predicate \
                            in it");
         }
@@ -4600,7 +4596,7 @@ impl<'a> Parser<'a> {
     fn parse_self_arg(&mut self) -> PResult<'a, Option<Arg>> {
         let expect_ident = |this: &mut Self| match this.token {
             // Preserve hygienic context.
-            token::Ident(ident) => { this.bump(); codemap::respan(this.last_span, ident) }
+            token::Ident(ident) => { this.bump(); codemap::respan(this.prev_span, ident) }
             _ => unreachable!()
         };
 
@@ -4689,7 +4685,7 @@ impl<'a> Parser<'a> {
             _ => return Ok(None),
         };
 
-        let eself = codemap::respan(mk_sp(eself_lo, self.last_span.hi), eself);
+        let eself = codemap::respan(mk_sp(eself_lo, self.prev_span.hi), eself);
         Ok(Some(Arg::from_self(eself, eself_ident)))
     }
 
@@ -4807,7 +4803,7 @@ impl<'a> Parser<'a> {
                                                 ast::Unsafety,
                                                 abi::Abi)> {
         let is_const_fn = self.eat_keyword(keywords::Const);
-        let const_span = self.last_span;
+        let const_span = self.prev_span;
         let unsafety = self.parse_unsafety()?;
         let (constness, unsafety, abi) = if is_const_fn {
             (respan(const_span, Constness::Const), unsafety, Abi::Rust)
@@ -4817,7 +4813,7 @@ impl<'a> Parser<'a> {
             } else {
                 Abi::Rust
             };
-            (respan(self.last_span, Constness::NotConst), unsafety, abi)
+            (respan(self.prev_span, Constness::NotConst), unsafety, abi)
         };
         self.expect_keyword(keywords::Fn)?;
         Ok((constness, unsafety, abi))
@@ -4854,7 +4850,7 @@ impl<'a> Parser<'a> {
 
         Ok(ImplItem {
             id: ast::DUMMY_NODE_ID,
-            span: mk_sp(lo, self.last_span.hi),
+            span: mk_sp(lo, self.prev_span.hi),
             ident: name,
             vis: vis,
             defaultness: defaultness,
@@ -4894,8 +4890,8 @@ impl<'a> Parser<'a> {
         if self.token.is_path_start() {
             // method macro.
 
-            let last_span = self.last_span;
-            self.complain_if_pub_macro(&vis, last_span);
+            let prev_span = self.prev_span;
+            self.complain_if_pub_macro(&vis, prev_span);
 
             let lo = self.span.lo;
             let pth = self.parse_path(PathStyle::Mod)?;
@@ -4910,7 +4906,7 @@ impl<'a> Parser<'a> {
                 self.expect(&token::Semi)?
             }
 
-            let mac = spanned(lo, self.last_span.hi, Mac_ { path: pth, tts: tts });
+            let mac = spanned(lo, self.prev_span.hi, Mac_ { path: pth, tts: tts });
             Ok((keywords::Invalid.ident(), vec![], ast::ImplItemKind::Macro(mac)))
         } else {
             let (constness, unsafety, abi) = self.parse_fn_front_matter()?;
@@ -5051,7 +5047,7 @@ impl<'a> Parser<'a> {
         Ok(ast::PolyTraitRef {
             bound_lifetimes: lifetime_defs,
             trait_ref: self.parse_trait_ref()?,
-            span: mk_sp(lo, self.last_span.hi),
+            span: mk_sp(lo, self.prev_span.hi),
         })
     }
 
@@ -5217,7 +5213,7 @@ impl<'a> Parser<'a> {
     // If `allow_path` is false, just parse the `pub` in `pub(path)` (but still parse `pub(crate)`)
     fn parse_visibility(&mut self, allow_path: bool) -> PResult<'a, Visibility> {
         let pub_crate = |this: &mut Self| {
-            let span = this.last_span;
+            let span = this.prev_span;
             this.expect(&token::CloseDelim(token::Paren))?;
             Ok(Visibility::Crate(span))
         };
@@ -5268,7 +5264,7 @@ impl<'a> Parser<'a> {
         let hi = if self.span == syntax_pos::DUMMY_SP {
             inner_lo
         } else {
-            self.last_span.hi
+            self.prev_span.hi
         };
 
         Ok(ast::Mod {
@@ -5537,9 +5533,9 @@ impl<'a> Parser<'a> {
         };
         self.expect(&token::Semi)?;
 
-        let last_span = self.last_span;
+        let prev_span = self.prev_span;
         Ok(self.mk_item(lo,
-                        last_span.hi,
+                        prev_span.hi,
                         ident,
                         ItemKind::ExternCrate(maybe_path),
                         visibility,
@@ -5574,13 +5570,13 @@ impl<'a> Parser<'a> {
         }
         self.expect(&token::CloseDelim(token::Brace))?;
 
-        let last_span = self.last_span;
+        let prev_span = self.prev_span;
         let m = ast::ForeignMod {
             abi: abi,
             items: foreign_items
         };
         Ok(self.mk_item(lo,
-                     last_span.hi,
+                     prev_span.hi,
                      keywords::Invalid.ident(),
                      ItemKind::ForeignMod(m),
                      visibility,
@@ -5633,7 +5629,7 @@ impl<'a> Parser<'a> {
                 data: struct_def,
                 disr_expr: disr_expr,
             };
-            variants.push(spanned(vlo, self.last_span.hi, vr));
+            variants.push(spanned(vlo, self.prev_span.hi, vr));
 
             if !self.eat(&token::Comma) { break; }
         }
@@ -5670,9 +5666,9 @@ impl<'a> Parser<'a> {
                 match abi::lookup(&s.as_str()) {
                     Some(abi) => Ok(Some(abi)),
                     None => {
-                        let last_span = self.last_span;
+                        let prev_span = self.prev_span;
                         self.span_err(
-                            last_span,
+                            prev_span,
                             &format!("invalid ABI: expected one of [{}], \
                                      found `{}`",
                                     abi::all_names().join(", "),
@@ -5714,9 +5710,9 @@ impl<'a> Parser<'a> {
             let item_ = ItemKind::Use(self.parse_view_path()?);
             self.expect(&token::Semi)?;
 
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     keywords::Invalid.ident(),
                                     item_,
                                     visibility,
@@ -5733,15 +5729,15 @@ impl<'a> Parser<'a> {
 
             if self.eat_keyword(keywords::Fn) {
                 // EXTERN FUNCTION ITEM
-                let fn_span = self.last_span;
+                let fn_span = self.prev_span;
                 let abi = opt_abi.unwrap_or(Abi::C);
                 let (ident, item_, extra_attrs) =
                     self.parse_item_fn(Unsafety::Normal,
                                        respan(fn_span, Constness::NotConst),
                                        abi)?;
-                let last_span = self.last_span;
+                let prev_span = self.prev_span;
                 let item = self.mk_item(lo,
-                                        last_span.hi,
+                                        prev_span.hi,
                                         ident,
                                         item_,
                                         visibility,
@@ -5762,9 +5758,9 @@ impl<'a> Parser<'a> {
                 Mutability::Immutable
             };
             let (ident, item_, extra_attrs) = self.parse_item_const(Some(m))?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5772,7 +5768,7 @@ impl<'a> Parser<'a> {
             return Ok(Some(item));
         }
         if self.eat_keyword(keywords::Const) {
-            let const_span = self.last_span;
+            let const_span = self.prev_span;
             if self.check_keyword(keywords::Fn)
                 || (self.check_keyword(keywords::Unsafe)
                     && self.look_ahead(1, |t| t.is_keyword(keywords::Fn))) {
@@ -5787,9 +5783,9 @@ impl<'a> Parser<'a> {
                     self.parse_item_fn(unsafety,
                                        respan(const_span, Constness::Const),
                                        Abi::Rust)?;
-                let last_span = self.last_span;
+                let prev_span = self.prev_span;
                 let item = self.mk_item(lo,
-                                        last_span.hi,
+                                        prev_span.hi,
                                         ident,
                                         item_,
                                         visibility,
@@ -5799,15 +5795,15 @@ impl<'a> Parser<'a> {
 
             // CONST ITEM
             if self.eat_keyword(keywords::Mut) {
-                let last_span = self.last_span;
-                self.diagnostic().struct_span_err(last_span, "const globals cannot be mutable")
+                let prev_span = self.prev_span;
+                self.diagnostic().struct_span_err(prev_span, "const globals cannot be mutable")
                                  .help("did you mean to declare a static?")
                                  .emit();
             }
             let (ident, item_, extra_attrs) = self.parse_item_const(None)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5822,9 +5818,9 @@ impl<'a> Parser<'a> {
             self.expect_keyword(keywords::Trait)?;
             let (ident, item_, extra_attrs) =
                 self.parse_item_trait(ast::Unsafety::Unsafe)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5838,9 +5834,9 @@ impl<'a> Parser<'a> {
             self.expect_keyword(keywords::Unsafe)?;
             self.expect_keyword(keywords::Impl)?;
             let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Unsafe)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5850,14 +5846,14 @@ impl<'a> Parser<'a> {
         if self.check_keyword(keywords::Fn) {
             // FUNCTION ITEM
             self.bump();
-            let fn_span = self.last_span;
+            let fn_span = self.prev_span;
             let (ident, item_, extra_attrs) =
                 self.parse_item_fn(Unsafety::Normal,
                                    respan(fn_span, Constness::NotConst),
                                    Abi::Rust)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5874,14 +5870,14 @@ impl<'a> Parser<'a> {
                 Abi::Rust
             };
             self.expect_keyword(keywords::Fn)?;
-            let fn_span = self.last_span;
+            let fn_span = self.prev_span;
             let (ident, item_, extra_attrs) =
                 self.parse_item_fn(Unsafety::Unsafe,
                                    respan(fn_span, Constness::NotConst),
                                    abi)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5892,9 +5888,9 @@ impl<'a> Parser<'a> {
             // MODULE ITEM
             let (ident, item_, extra_attrs) =
                 self.parse_item_mod(&attrs[..])?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5904,9 +5900,9 @@ impl<'a> Parser<'a> {
         if self.eat_keyword(keywords::Type) {
             // TYPE ITEM
             let (ident, item_, extra_attrs) = self.parse_item_type()?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5916,9 +5912,9 @@ impl<'a> Parser<'a> {
         if self.eat_keyword(keywords::Enum) {
             // ENUM ITEM
             let (ident, item_, extra_attrs) = self.parse_item_enum()?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5929,9 +5925,9 @@ impl<'a> Parser<'a> {
             // TRAIT ITEM
             let (ident, item_, extra_attrs) =
                 self.parse_item_trait(ast::Unsafety::Normal)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5941,9 +5937,9 @@ impl<'a> Parser<'a> {
         if self.eat_keyword(keywords::Impl) {
             // IMPL ITEM
             let (ident, item_, extra_attrs) = self.parse_item_impl(ast::Unsafety::Normal)?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5953,9 +5949,9 @@ impl<'a> Parser<'a> {
         if self.eat_keyword(keywords::Struct) {
             // STRUCT ITEM
             let (ident, item_, extra_attrs) = self.parse_item_struct()?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -5967,9 +5963,9 @@ impl<'a> Parser<'a> {
             // UNION ITEM
             self.bump();
             let (ident, item_, extra_attrs) = self.parse_item_union()?;
-            let last_span = self.last_span;
+            let prev_span = self.prev_span;
             let item = self.mk_item(lo,
-                                    last_span.hi,
+                                    prev_span.hi,
                                     ident,
                                     item_,
                                     visibility,
@@ -6015,8 +6011,8 @@ impl<'a> Parser<'a> {
         if macros_allowed && self.token.is_path_start() {
             // MACRO INVOCATION ITEM
 
-            let last_span = self.last_span;
-            self.complain_if_pub_macro(&visibility, last_span);
+            let prev_span = self.prev_span;
+            self.complain_if_pub_macro(&visibility, prev_span);
 
             let mac_lo = self.span.lo;
 
@@ -6039,15 +6035,15 @@ impl<'a> Parser<'a> {
                                             |p| p.parse_token_tree())?;
             if delim != token::Brace {
                 if !self.eat(&token::Semi) {
-                    let last_span = self.last_span;
-                    self.span_err(last_span,
+                    let prev_span = self.prev_span;
+                    self.span_err(prev_span,
                                   "macros that expand to items must either \
                                    be surrounded with braces or followed by \
                                    a semicolon");
                 }
             }
 
-            let hi = self.last_span.hi;
+            let hi = self.prev_span.hi;
             let mac = spanned(mac_lo, hi, Mac_ { path: pth, tts: tts });
             let item = self.mk_item(lo, hi, id, ItemKind::Mac(mac), visibility, attrs);
             return Ok(Some(item));
@@ -6057,8 +6053,8 @@ impl<'a> Parser<'a> {
         match visibility {
             Visibility::Inherited => {}
             _ => {
-                let last_span = self.last_span;
-                return Err(self.span_fatal(last_span, "unmatched visibility `pub`"));
+                let prev_span = self.prev_span;
+                return Err(self.span_fatal(prev_span, "unmatched visibility `pub`"));
             }
         }
 
@@ -6089,7 +6085,7 @@ impl<'a> Parser<'a> {
                 rename: rename,
                 id: ast::DUMMY_NODE_ID
             };
-            let hi = this.last_span.hi;
+            let hi = this.prev_span.hi;
             Ok(spanned(lo, hi, node))
         })
     }
@@ -6134,7 +6130,7 @@ impl<'a> Parser<'a> {
                 // `foo::bar` or `foo::bar as baz`
                 let rename = self.parse_rename()?.
                                   unwrap_or(prefix.segments.last().unwrap().identifier);
-                Ok(P(spanned(lo, self.last_span.hi, ViewPathSimple(rename, prefix))))
+                Ok(P(spanned(lo, self.prev_span.hi, ViewPathSimple(rename, prefix))))
             }
         }
     }
@@ -6182,7 +6178,7 @@ impl<'a> Parser<'a> {
     pub fn parse_str(&mut self) -> PResult<'a, (InternedString, StrStyle)> {
         match self.parse_optional_str() {
             Some((s, style, suf)) => {
-                let sp = self.last_span;
+                let sp = self.prev_span;
                 self.expect_no_suffix(sp, "string literal", suf);
                 Ok((s, style))
             }
diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs
index 09bc5607946..3d4dd9ec064 100644
--- a/src/libsyntax/parse/token.rs
+++ b/src/libsyntax/parse/token.rs
@@ -478,27 +478,20 @@ pub fn clear_ident_interner() {
 /// somehow.
 #[derive(Clone, PartialEq, Hash, PartialOrd, Eq, Ord)]
 pub struct InternedString {
-    string: Rc<String>,
+    string: Rc<str>,
 }
 
 impl InternedString {
     #[inline]
     pub fn new(string: &'static str) -> InternedString {
         InternedString {
-            string: Rc::new(string.to_owned()),
-        }
-    }
-
-    #[inline]
-    fn new_from_rc_str(string: Rc<String>) -> InternedString {
-        InternedString {
-            string: string,
+            string: Rc::__from_str(string),
         }
     }
 
     #[inline]
     pub fn new_from_name(name: ast::Name) -> InternedString {
-        with_ident_interner(|interner| InternedString::new_from_rc_str(interner.get(name)))
+        with_ident_interner(|interner| InternedString { string: interner.get(name) })
     }
 }
 
@@ -566,7 +559,7 @@ impl PartialEq<InternedString> for str {
 
 impl Decodable for InternedString {
     fn decode<D: Decoder>(d: &mut D) -> Result<InternedString, D::Error> {
-        Ok(intern(d.read_str()?.as_ref()).as_str())
+        Ok(intern(&d.read_str()?).as_str())
     }
 }
 
diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs
index 3c106970232..ecb437f31a5 100644
--- a/src/libsyntax/print/pprust.rs
+++ b/src/libsyntax/print/pprust.rs
@@ -112,7 +112,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap,
                                       out,
                                       ann,
                                       is_expanded);
-    if is_expanded && !std_inject::no_std(krate) {
+    if is_expanded && !std_inject::injected_crate_name(krate).is_none() {
         // We need to print `#![no_std]` (and its feature gate) so that
         // compiling pretty-printed source won't inject libstd again.
         // However we don't want these attributes in the AST because
diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs
index d1454ab06cb..1b63a2b7076 100644
--- a/src/libsyntax/std_inject.rs
+++ b/src/libsyntax/std_inject.rs
@@ -34,23 +34,25 @@ fn ignored_span(sess: &ParseSess, sp: Span) -> Span {
     return sp;
 }
 
-pub fn no_core(krate: &ast::Crate) -> bool {
-    attr::contains_name(&krate.attrs, "no_core")
-}
-
-pub fn no_std(krate: &ast::Crate) -> bool {
-    attr::contains_name(&krate.attrs, "no_std") || no_core(krate)
+pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> {
+    if attr::contains_name(&krate.attrs, "no_core") {
+        None
+    } else if attr::contains_name(&krate.attrs, "no_std") {
+        Some("core")
+    } else {
+        Some("std")
+    }
 }
 
 pub fn maybe_inject_crates_ref(sess: &ParseSess,
                                mut krate: ast::Crate,
                                alt_std_name: Option<String>)
                                -> ast::Crate {
-    if no_core(&krate) {
-        return krate;
-    }
+    let name = match injected_crate_name(&krate) {
+        Some(name) => name,
+        None => return krate,
+    };
 
-    let name = if no_std(&krate) { "core" } else { "std" };
     let crate_name = token::intern(&alt_std_name.unwrap_or(name.to_string()));
 
     krate.module.items.insert(0, P(ast::Item {
diff --git a/src/libsyntax/util/interner.rs b/src/libsyntax/util/interner.rs
index 6bb409715aa..f56c6cedcd1 100644
--- a/src/libsyntax/util/interner.rs
+++ b/src/libsyntax/util/interner.rs
@@ -14,23 +14,13 @@
 
 use ast::Name;
 
-use std::borrow::Borrow;
 use std::collections::HashMap;
 use std::rc::Rc;
 
-#[derive(PartialEq, Eq, Hash)]
-struct RcStr(Rc<String>);
-
-impl Borrow<str> for RcStr {
-    fn borrow(&self) -> &str {
-        &self.0
-    }
-}
-
 #[derive(Default)]
 pub struct Interner {
-    names: HashMap<RcStr, Name>,
-    strings: Vec<Rc<String>>,
+    names: HashMap<Rc<str>, Name>,
+    strings: Vec<Rc<str>>,
 }
 
 /// When traits can extend traits, we should extend index<Name,T> to get []
@@ -47,22 +37,22 @@ impl Interner {
         this
     }
 
-    pub fn intern<T: Borrow<str> + Into<String>>(&mut self, string: T) -> Name {
-        if let Some(&name) = self.names.get(string.borrow()) {
+    pub fn intern(&mut self, string: &str) -> Name {
+        if let Some(&name) = self.names.get(string) {
             return name;
         }
 
         let name = Name(self.strings.len() as u32);
-        let string = Rc::new(string.into());
+        let string = Rc::__from_str(string);
         self.strings.push(string.clone());
-        self.names.insert(RcStr(string), name);
+        self.names.insert(string, name);
         name
     }
 
     pub fn gensym(&mut self, string: &str) -> Name {
         let gensym = Name(self.strings.len() as u32);
         // leave out of `names` to avoid colliding
-        self.strings.push(Rc::new(string.to_owned()));
+        self.strings.push(Rc::__from_str(string));
         gensym
     }
 
@@ -75,7 +65,7 @@ impl Interner {
         gensym
     }
 
-    pub fn get(&self, name: Name) -> Rc<String> {
+    pub fn get(&self, name: Name) -> Rc<str> {
         self.strings[name.0 as usize].clone()
     }
 
@@ -109,13 +99,13 @@ mod tests {
         assert_eq!(i.gensym("dog"), Name(4));
         // gensym tests again with gensym_copy:
         assert_eq!(i.gensym_copy(Name(2)), Name(5));
-        assert_eq!(*i.get(Name(5)), "zebra");
+        assert_eq!(&*i.get(Name(5)), "zebra");
         assert_eq!(i.gensym_copy(Name(2)), Name(6));
-        assert_eq!(*i.get(Name(6)), "zebra");
-        assert_eq!(*i.get(Name(0)), "dog");
-        assert_eq!(*i.get(Name(1)), "cat");
-        assert_eq!(*i.get(Name(2)), "zebra");
-        assert_eq!(*i.get(Name(3)), "zebra");
-        assert_eq!(*i.get(Name(4)), "dog");
+        assert_eq!(&*i.get(Name(6)), "zebra");
+        assert_eq!(&*i.get(Name(0)), "dog");
+        assert_eq!(&*i.get(Name(1)), "cat");
+        assert_eq!(&*i.get(Name(2)), "zebra");
+        assert_eq!(&*i.get(Name(3)), "zebra");
+        assert_eq!(&*i.get(Name(4)), "dog");
     }
 }
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index cc4fb604d6c..c16b7d29594 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -122,7 +122,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
 
                     let (constraint, _str_style) = panictry!(p.parse_str());
 
-                    let span = p.last_span;
+                    let span = p.prev_span;
 
                     panictry!(p.expect(&token::OpenDelim(token::Paren)));
                     let out = panictry!(p.parse_expr());
@@ -167,9 +167,9 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                     let (constraint, _str_style) = panictry!(p.parse_str());
 
                     if constraint.starts_with("=") {
-                        cx.span_err(p.last_span, "input operand constraint contains '='");
+                        cx.span_err(p.prev_span, "input operand constraint contains '='");
                     } else if constraint.starts_with("+") {
-                        cx.span_err(p.last_span, "input operand constraint contains '+'");
+                        cx.span_err(p.prev_span, "input operand constraint contains '+'");
                     }
 
                     panictry!(p.expect(&token::OpenDelim(token::Paren)));
@@ -189,9 +189,9 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                     let (s, _str_style) = panictry!(p.parse_str());
 
                     if OPTIONS.iter().any(|&opt| s == opt) {
-                        cx.span_warn(p.last_span, "expected a clobber, found an option");
+                        cx.span_warn(p.prev_span, "expected a clobber, found an option");
                     } else if s.starts_with("{") || s.ends_with("}") {
-                        cx.span_err(p.last_span, "clobber should not be surrounded by braces");
+                        cx.span_err(p.prev_span, "clobber should not be surrounded by braces");
                     }
 
                     clobs.push(s);
@@ -209,7 +209,7 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt,
                 } else if option == "intel" {
                     dialect = AsmDialect::Intel;
                 } else {
-                    cx.span_warn(p.last_span, "unrecognized option");
+                    cx.span_warn(p.prev_span, "unrecognized option");
                 }
 
                 if p.token == token::Comma {
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index fdb10a2beb2..9f99919c895 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -11,6 +11,7 @@
 //! The compiler code necessary to implement the `#[derive]` extensions.
 
 use syntax::ast::{self, MetaItem};
+use syntax::attr::HasAttrs;
 use syntax::ext::base::{Annotatable, ExtCtxt};
 use syntax::ext::build::AstBuilder;
 use syntax::feature_gate;
@@ -104,13 +105,37 @@ pub fn expand_derive(cx: &mut ExtCtxt,
         }
     };
 
-    if mitem.value_str().is_some() {
-        cx.span_err(mitem.span, "unexpected value in `derive`");
+    let mut derive_attrs = Vec::new();
+    item = item.map_attrs(|attrs| {
+        let partition = attrs.into_iter().partition(|attr| &attr.name() == "derive");
+        derive_attrs = partition.0;
+        partition.1
+    });
+
+    // Expand `#[derive]`s after other attribute macro invocations.
+    if cx.resolver.find_attr_invoc(&mut item.attrs.clone()).is_some() {
+        return vec![Annotatable::Item(item.map_attrs(|mut attrs| {
+            attrs.push(cx.attribute(span, P(mitem.clone())));
+            attrs.extend(derive_attrs);
+            attrs
+        }))];
     }
 
-    let mut traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
-    if traits.is_empty() {
-        cx.span_warn(mitem.span, "empty trait list in `derive`");
+    let get_traits = |mitem: &MetaItem, cx: &ExtCtxt| {
+        if mitem.value_str().is_some() {
+            cx.span_err(mitem.span, "unexpected value in `derive`");
+        }
+
+        let traits = mitem.meta_item_list().unwrap_or(&[]).to_owned();
+        if traits.is_empty() {
+            cx.span_warn(mitem.span, "empty trait list in `derive`");
+        }
+        traits
+    };
+
+    let mut traits = get_traits(mitem, cx);
+    for derive_attr in derive_attrs {
+        traits.extend(get_traits(&derive_attr.node.value, cx));
     }
 
     // First, weed out malformed #[derive]
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index e9d2c0a503b..f336b26ae41 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -50,20 +50,23 @@ pub mod deriving;
 
 use std::rc::Rc;
 use syntax::ast;
-use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier};
+use syntax::ext::base::{MacroExpanderFn, NormalTT, IdentTT, MultiModifier, NamedSyntaxExtension};
 use syntax::ext::tt::macro_rules::MacroRulesExpander;
 use syntax::parse::token::intern;
 
-pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quotes: bool) {
+pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
+                         user_exts: Vec<NamedSyntaxExtension>,
+                         enable_quotes: bool) {
     let mut register = |name, ext| {
-        resolver.add_ext(ast::Ident::with_empty_ctxt(intern(name)), Rc::new(ext));
+        resolver.add_ext(ast::Ident::with_empty_ctxt(name), Rc::new(ext));
     };
 
-    register("macro_rules", IdentTT(Box::new(MacroRulesExpander), None, false));
+    register(intern("macro_rules"), IdentTT(Box::new(MacroRulesExpander), None, false));
 
     macro_rules! register {
         ($( $name:ident: $f:expr, )*) => { $(
-            register(stringify!($name), NormalTT(Box::new($f as MacroExpanderFn), None, false));
+            register(intern(stringify!($name)),
+                     NormalTT(Box::new($f as MacroExpanderFn), None, false));
         )* }
     }
 
@@ -108,7 +111,11 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver, enable_quot
     }
 
     // format_args uses `unstable` things internally.
-    register("format_args", NormalTT(Box::new(format::expand_format_args), None, true));
+    register(intern("format_args"), NormalTT(Box::new(format::expand_format_args), None, true));
 
-    register("derive", MultiModifier(Box::new(deriving::expand_derive)));
+    register(intern("derive"), MultiModifier(Box::new(deriving::expand_derive)));
+
+    for (name, ext) in user_exts {
+        register(name, ext);
+    }
 }
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 13dcf7b188b..e3feaee5369 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -27,7 +27,7 @@
 #![allow(unused_attributes)]
 #![feature(rustc_private)]
 #![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![feature(specialization)]
 
 use std::cell::{Cell, RefCell};
diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs
index 0244e265796..caef808f474 100644
--- a/src/libterm/lib.rs
+++ b/src/libterm/lib.rs
@@ -59,7 +59,7 @@
 #![cfg_attr(windows, feature(libc))]
 // Handle rustfmt skips
 #![feature(custom_attribute)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![allow(unused_attributes)]
 
 use std::io::prelude::*;
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index bb42351d3b7..625666e641c 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -38,7 +38,7 @@
 #![feature(rustc_private)]
 #![feature(set_stdio)]
 #![feature(staged_api)]
-#![feature(question_mark)]
+#![cfg_attr(stage0, feature(question_mark))]
 #![feature(panic_unwind)]
 
 extern crate getopts;
diff --git a/src/rtstartup/rsbegin.rs b/src/rtstartup/rsbegin.rs
index b57b7e84321..65c85697ce7 100644
--- a/src/rtstartup/rsbegin.rs
+++ b/src/rtstartup/rsbegin.rs
@@ -44,7 +44,7 @@ pub mod eh_frames {
 
     // Scratch space for unwinder's internal book-keeping.
     // This is defined as `struct object` in $GCC/libgcc/unwind-dw2-fde.h.
-    static mut obj: [isize; 6] = [0; 6];
+    static mut OBJ: [isize; 6] = [0; 6];
 
     // Unwind info registration/deregistration routines.
     // See the docs of `unwind` module in libstd.
@@ -56,13 +56,13 @@ pub mod eh_frames {
     unsafe fn init() {
         // register unwind info on module startup
         rust_eh_register_frames(&__EH_FRAME_BEGIN__ as *const u8,
-                                &mut obj as *mut _ as *mut u8);
+                                &mut OBJ as *mut _ as *mut u8);
     }
 
     unsafe fn uninit() {
         // unregister on shutdown
         rust_eh_unregister_frames(&__EH_FRAME_BEGIN__ as *const u8,
-                                  &mut obj as *mut _ as *mut u8);
+                                  &mut OBJ as *mut _ as *mut u8);
     }
 
     // MSVC-specific init/uninit routine registration
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 672ab117f15..369388caa04 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -562,8 +562,6 @@ extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateVariable(
     LLVMRustMetadataRef Ty,
     bool AlwaysPreserve,
     unsigned Flags,
-    int64_t* AddrOps,
-    unsigned AddrOpsCount,
     unsigned ArgNo) {
 #if LLVM_VERSION_GE(3, 8)
     if (Tag == 0x100) { // DW_TAG_auto_variable
@@ -645,23 +643,6 @@ extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareAtEnd(
         unwrap(InsertAtEnd)));
 }
 
-extern "C" LLVMValueRef LLVMRustDIBuilderInsertDeclareBefore(
-    LLVMRustDIBuilderRef Builder,
-    LLVMValueRef Val,
-    LLVMRustMetadataRef VarInfo,
-    int64_t* AddrOps,
-    unsigned AddrOpsCount,
-    LLVMValueRef DL,
-    LLVMValueRef InsertBefore) {
-    return wrap(Builder->insertDeclare(
-        unwrap(Val),
-        unwrap<DILocalVariable>(VarInfo),
-        Builder->createExpression(
-          llvm::ArrayRef<int64_t>(AddrOps, AddrOpsCount)),
-        DebugLoc(cast<MDNode>(unwrap<MetadataAsValue>(DL)->getMetadata())),
-        unwrap<Instruction>(InsertBefore)));
-}
-
 extern "C" LLVMRustMetadataRef LLVMRustDIBuilderCreateEnumerator(
     LLVMRustDIBuilderRef Builder,
     const char* Name,
@@ -1302,7 +1283,7 @@ static LLVMLinkage from_rust(LLVMRustLinkage linkage) {
             return LLVMCommonLinkage;
         default:
             llvm_unreachable("Invalid LLVMRustLinkage value!");
-    } 
+    }
 }
 
 extern "C" LLVMRustLinkage LLVMRustGetLinkage(LLVMValueRef V) {
diff --git a/src/test/compile-fail/E0408.rs b/src/test/compile-fail/E0408.rs
index 43f6d9d757d..d75f6124827 100644
--- a/src/test/compile-fail/E0408.rs
+++ b/src/test/compile-fail/E0408.rs
@@ -12,7 +12,7 @@ fn main() {
     let x = Some(0);
 
     match x {
-        Some(y) | None => {} //~ ERROR E0408
-        _ => ()
+        Some(y) | None => {} //~  ERROR variable `y` from pattern #1 is not bound in pattern #2
+        _ => ()              //~| NOTE pattern doesn't bind `y`
     }
 }
diff --git a/src/test/compile-fail/if-without-else-result.rs b/src/test/compile-fail/if-without-else-result.rs
index e8aa1f70ea1..95bcce5a847 100644
--- a/src/test/compile-fail/if-without-else-result.rs
+++ b/src/test/compile-fail/if-without-else-result.rs
@@ -10,7 +10,7 @@
 
 fn main() {
     let a = if true { true };
-    //~^ ERROR if may be missing an else clause
+    //~^ ERROR if may be missing an else clause [E0317]
     //~| expected type `()`
     //~| found type `bool`
     //~| expected (), found bool
diff --git a/src/test/compile-fail/issue-2848.rs b/src/test/compile-fail/issue-2848.rs
index e5503edfab5..f5e0c545bb5 100644
--- a/src/test/compile-fail/issue-2848.rs
+++ b/src/test/compile-fail/issue-2848.rs
@@ -19,7 +19,7 @@ mod bar {
 fn main() {
     use bar::foo::{alpha, charlie};
     match alpha {
-      alpha | beta => {} //~ ERROR variable `beta` from pattern #2 is not bound in pattern #1
-      charlie => {}
+      alpha | beta => {} //~  ERROR variable `beta` from pattern #2 is not bound in pattern #1
+      charlie => {}      //~| NOTE pattern doesn't bind `beta`
     }
 }
diff --git a/src/test/compile-fail/issue-32709.rs b/src/test/compile-fail/issue-32709.rs
index f9d11f3a171..09538818dcd 100644
--- a/src/test/compile-fail/issue-32709.rs
+++ b/src/test/compile-fail/issue-32709.rs
@@ -8,12 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(question_mark)]
-
 // Make sure that the span of try shorthand does not include the trailing
 // semicolon;
 fn a() -> Result<i32, ()> {
-    Err(5)?; //~ ERROR 16:5: 16:12
+    Err(5)?; //~ ERROR 14:5: 14:12
     Ok(1)
 }
 
diff --git a/src/test/compile-fail/issue-33876.rs b/src/test/compile-fail/issue-33876.rs
index d95890730a0..87747d2851f 100644
--- a/src/test/compile-fail/issue-33876.rs
+++ b/src/test/compile-fail/issue-33876.rs
@@ -8,9 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(reflect_marker)]
-
-use std::marker::Reflect;
 use std::any::Any;
 
 struct Foo;
diff --git a/src/test/compile-fail/lint-group-style.rs b/src/test/compile-fail/lint-group-style.rs
index 393e46ab539..b2e6072c985 100644
--- a/src/test/compile-fail/lint-group-style.rs
+++ b/src/test/compile-fail/lint-group-style.rs
@@ -24,7 +24,7 @@ mod test {
     mod bad {
         fn CamelCase() {} //~ ERROR function `CamelCase` should have a snake case name
 
-        static bad: isize = 1; //~ ERROR static constant `bad` should have an upper case name
+        static bad: isize = 1; //~ ERROR static variable `bad` should have an upper case name
     }
 
     mod warn {
diff --git a/src/test/compile-fail/lint-non-uppercase-statics.rs b/src/test/compile-fail/lint-non-uppercase-statics.rs
index e1fbc73bbed..463a93612ca 100644
--- a/src/test/compile-fail/lint-non-uppercase-statics.rs
+++ b/src/test/compile-fail/lint-non-uppercase-statics.rs
@@ -11,6 +11,9 @@
 #![forbid(non_upper_case_globals)]
 #![allow(dead_code)]
 
-static foo: isize = 1; //~ ERROR static constant `foo` should have an upper case name such as `FOO`
+static foo: isize = 1; //~ ERROR static variable `foo` should have an upper case name such as `FOO`
+
+static mut bar: isize = 1;
+        //~^ ERROR static variable `bar` should have an upper case name such as `BAR`
 
 fn main() { }
diff --git a/src/test/compile-fail/macro-shadowing.rs b/src/test/compile-fail/macro-shadowing.rs
index 22463825ef9..8381dc34a6a 100644
--- a/src/test/compile-fail/macro-shadowing.rs
+++ b/src/test/compile-fail/macro-shadowing.rs
@@ -12,31 +12,28 @@
 
 macro_rules! foo { () => {} }
 macro_rules! macro_one { () => {} }
+#[macro_use(macro_two)] extern crate two_macros;
 
 macro_rules! m1 { () => {
     macro_rules! foo { () => {} } //~ ERROR `foo` is already in scope
-    //~^ NOTE macro-expanded `macro_rules!`s and `#[macro_use]`s may not shadow existing macros
+    //~^ NOTE macro-expanded `macro_rules!`s may not shadow existing macros
 
-    #[macro_use] //~ ERROR `macro_one` is already in scope
-    //~^ NOTE macro-expanded `macro_rules!`s and `#[macro_use]`s may not shadow existing macros
-    extern crate two_macros;
+    #[macro_use] //~ ERROR `macro_two` is already in scope
+    //~^ NOTE macro-expanded `#[macro_use]`s may not shadow existing macros
+    extern crate two_macros as __;
 }}
 m1!(); //~ NOTE in this expansion
        //~| NOTE in this expansion
        //~| NOTE in this expansion
        //~| NOTE in this expansion
 
-fn f() { macro_one!(); }
 foo!();
 
 macro_rules! m2 { () => {
     macro_rules! foo { () => {} }
-    #[macro_use] extern crate two_macros as __;
-
-    fn g() { macro_one!(); }
     foo!();
 }}
 m2!();
-//^ Since `foo` and `macro_one` are not used outside this expansion, they are not shadowing errors.
+//^ Since `foo` is not used outside this expansion, it is not a shadowing error.
 
 fn main() {}
diff --git a/src/test/compile-fail/macro-use-scope.rs b/src/test/compile-fail/macro-use-scope.rs
index 5256396a242..9d389413ba9 100644
--- a/src/test/compile-fail/macro-use-scope.rs
+++ b/src/test/compile-fail/macro-use-scope.rs
@@ -19,10 +19,10 @@ fn f() {
 #[macro_use(macro_one)] // Check that this macro is usable in the above function
 extern crate two_macros;
 
+fn g() {
+    macro_two!();
+}
 macro_rules! m { () => {
-    fn g() {
-        macro_two!();
-    }
     #[macro_use(macro_two)] // Check that this macro is usable in the above function
     extern crate two_macros as _two_macros;
 } }
diff --git a/src/test/compile-fail/mir-dataflow/def-inits-1.rs b/src/test/compile-fail/mir-dataflow/def-inits-1.rs
index a133ddc15f1..1ba1bb35bb5 100644
--- a/src/test/compile-fail/mir-dataflow/def-inits-1.rs
+++ b/src/test/compile-fail/mir-dataflow/def-inits-1.rs
@@ -11,7 +11,6 @@
 // General test of maybe_uninits state computed by MIR dataflow.
 
 #![feature(rustc_attrs)]
-#![feature(stmt_expr_attributes)]
 
 use std::intrinsics::rustc_peek;
 use std::mem::{drop, replace};
diff --git a/src/test/compile-fail/mir-dataflow/inits-1.rs b/src/test/compile-fail/mir-dataflow/inits-1.rs
index 949688098f6..c8cf44adb97 100644
--- a/src/test/compile-fail/mir-dataflow/inits-1.rs
+++ b/src/test/compile-fail/mir-dataflow/inits-1.rs
@@ -11,7 +11,6 @@
 // General test of maybe_inits state computed by MIR dataflow.
 
 #![feature(rustc_attrs)]
-#![feature(stmt_expr_attributes)]
 
 use std::intrinsics::rustc_peek;
 use std::mem::{drop, replace};
diff --git a/src/test/compile-fail/mir-dataflow/uninits-1.rs b/src/test/compile-fail/mir-dataflow/uninits-1.rs
index c13daae24f3..a82bfc89698 100644
--- a/src/test/compile-fail/mir-dataflow/uninits-1.rs
+++ b/src/test/compile-fail/mir-dataflow/uninits-1.rs
@@ -11,7 +11,6 @@
 // General test of maybe_uninits state computed by MIR dataflow.
 
 #![feature(rustc_attrs)]
-#![feature(stmt_expr_attributes)]
 
 use std::intrinsics::rustc_peek;
 use std::mem::{drop, replace};
diff --git a/src/test/compile-fail/mir-dataflow/uninits-2.rs b/src/test/compile-fail/mir-dataflow/uninits-2.rs
index 94f812a40a9..8cfdae50662 100644
--- a/src/test/compile-fail/mir-dataflow/uninits-2.rs
+++ b/src/test/compile-fail/mir-dataflow/uninits-2.rs
@@ -11,7 +11,6 @@
 // General test of maybe_uninits state computed by MIR dataflow.
 
 #![feature(rustc_attrs)]
-#![feature(stmt_expr_attributes)]
 
 use std::intrinsics::rustc_peek;
 use std::mem::{drop, replace};
diff --git a/src/test/compile-fail/resolve-inconsistent-names.rs b/src/test/compile-fail/resolve-inconsistent-names.rs
index f7f3acd37d6..1e2541502ac 100644
--- a/src/test/compile-fail/resolve-inconsistent-names.rs
+++ b/src/test/compile-fail/resolve-inconsistent-names.rs
@@ -11,7 +11,9 @@
 fn main() {
     let y = 1;
     match y {
-       a | b => {} //~ ERROR variable `a` from pattern #1 is not bound in pattern #2
-       //~^ ERROR variable `b` from pattern #2 is not bound in pattern #1
+       a | b => {} //~  ERROR variable `a` from pattern #1 is not bound in pattern #2
+                   //~^ ERROR variable `b` from pattern #2 is not bound in pattern #1
+                   //~| NOTE pattern doesn't bind `a`
+                   //~| NOTE pattern doesn't bind `b`
     }
 }
diff --git a/src/test/compile-fail/stmt_expr_attrs_no_feature.rs b/src/test/compile-fail/stmt_expr_attrs_no_feature.rs
index 68338b11595..2fda2ee0900 100644
--- a/src/test/compile-fail/stmt_expr_attrs_no_feature.rs
+++ b/src/test/compile-fail/stmt_expr_attrs_no_feature.rs
@@ -21,15 +21,15 @@ fn main() {
     #[attr]
     fn a() {}
 
-    #[attr] //~ ERROR 15701
+    #[attr]
     {
 
     }
 
-    #[attr] //~ ERROR 15701
+    #[attr]
     5;
 
-    #[attr] //~ ERROR 15701
+    #[attr]
     stmt_mac!();
 }
 
@@ -43,7 +43,7 @@ fn c() {
 
 #[cfg(not(unset))]
 fn j() {
-    #[attr] //~ ERROR 15701
+    #[attr]
     5;
 }
 
@@ -55,7 +55,7 @@ fn d() {
 
 #[cfg_attr(not(unset), cfg(not(unset)))]
 fn i() {
-    #[attr] //~ ERROR 15701
+    #[attr]
     8;
 }
 
@@ -64,7 +64,7 @@ fn i() {
 macro_rules! item_mac {
     ($e:ident) => {
         fn $e() {
-            #[attr] //~ ERROR 15701
+            #[attr]
             42;
 
             #[cfg(unset)]
@@ -75,7 +75,7 @@ macro_rules! item_mac {
 
             #[cfg(not(unset))]
             fn k() {
-                #[attr] //~ ERROR 15701
+                #[attr]
                 5;
             }
 
@@ -87,7 +87,7 @@ macro_rules! item_mac {
 
             #[cfg_attr(not(unset), cfg(not(unset)))]
             fn h() {
-                #[attr] //~ ERROR 15701
+                #[attr]
                 8;
             }
 
diff --git a/src/test/incremental/hashes/struct_defs.rs b/src/test/incremental/hashes/struct_defs.rs
index 74c7797be2a..2d79987823f 100644
--- a/src/test/incremental/hashes/struct_defs.rs
+++ b/src/test/incremental/hashes/struct_defs.rs
@@ -236,3 +236,74 @@ struct Visibility;
 #[rustc_clean(label="Hir", cfg="cfail3")]
 #[rustc_metadata_clean(cfg="cfail3")]
 pub struct Visibility;
+
+
+
+
+struct ReferencedType1;
+struct ReferencedType2;
+
+// Tuple Struct Change Field Type Indirectly -----------------------------------
+mod tuple_struct_change_field_type_indirectly {
+    #[cfg(cfail1)]
+    use super::ReferencedType1 as FieldType;
+    #[cfg(not(cfail1))]
+    use super::ReferencedType2 as FieldType;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    struct TupleStruct(FieldType);
+}
+
+
+// Record Struct Change Field Type Indirectly -----------------------------------
+mod record_struct_change_field_type_indirectly {
+    #[cfg(cfail1)]
+    use super::ReferencedType1 as FieldType;
+    #[cfg(not(cfail1))]
+    use super::ReferencedType2 as FieldType;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    struct RecordStruct {
+        _x: FieldType
+    }
+}
+
+
+
+
+trait ReferencedTrait1 {}
+trait ReferencedTrait2 {}
+
+// Change Trait Bound Indirectly -----------------------------------------------
+mod change_trait_bound_indirectly {
+    #[cfg(cfail1)]
+    use super::ReferencedTrait1 as Trait;
+    #[cfg(not(cfail1))]
+    use super::ReferencedTrait2 as Trait;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    struct Struct<T: Trait>(T);
+}
+
+// Change Trait Bound Indirectly In Where Clause -------------------------------
+mod change_trait_bound_indirectly_in_where_clause {
+    #[cfg(cfail1)]
+    use super::ReferencedTrait1 as Trait;
+    #[cfg(not(cfail1))]
+    use super::ReferencedTrait2 as Trait;
+
+    #[rustc_dirty(label="Hir", cfg="cfail2")]
+    #[rustc_clean(label="Hir", cfg="cfail3")]
+    #[rustc_metadata_dirty(cfg="cfail2")]
+    #[rustc_metadata_clean(cfg="cfail3")]
+    struct Struct<T>(T) where T : Trait;
+}
diff --git a/src/test/run-pass-fulldeps/macro-crate.rs b/src/test/run-pass-fulldeps/macro-crate.rs
index fe2317aabea..9b2e36c8cea 100644
--- a/src/test/run-pass-fulldeps/macro-crate.rs
+++ b/src/test/run-pass-fulldeps/macro-crate.rs
@@ -17,8 +17,8 @@
 #[macro_use] #[no_link]
 extern crate macro_crate_test;
 
-#[into_multi_foo]
 #[derive(PartialEq, Clone, Debug)]
+#[into_multi_foo]
 fn foo() -> AnotherFakeTypeThatHadBetterGoAway {}
 
 // Check that the `#[into_multi_foo]`-generated `foo2` is configured away
diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs
index b9e31fc3329..a942adc4c80 100644
--- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/derive-atob.rs
@@ -21,6 +21,6 @@ use proc_macro::TokenStream;
 #[proc_macro_derive(AToB)]
 pub fn derive(input: TokenStream) -> TokenStream {
     let input = input.to_string();
-    assert_eq!(input, "struct A;\n");
+    assert_eq!(input, "#[derive(Copy, Clone)]\nstruct A;\n");
     "struct B;".parse().unwrap()
 }
diff --git a/src/test/run-pass-fulldeps/proc-macro/load-two.rs b/src/test/run-pass-fulldeps/proc-macro/load-two.rs
index 56f9768764c..431c8c59027 100644
--- a/src/test/run-pass-fulldeps/proc-macro/load-two.rs
+++ b/src/test/run-pass-fulldeps/proc-macro/load-two.rs
@@ -18,6 +18,7 @@ extern crate derive_atob;
 #[macro_use]
 extern crate derive_ctod;
 
+#[derive(Copy, Clone)]
 #[derive(AToB)]
 struct A;
 
diff --git a/src/test/run-pass/const-err.rs b/src/test/run-pass/const-err.rs
index 9f4ae1ad927..a1c9ff8a21e 100644
--- a/src/test/run-pass/const-err.rs
+++ b/src/test/run-pass/const-err.rs
@@ -17,4 +17,8 @@ const X: *const u8 = b"" as _;
 fn main() {
     let _ = ((-1 as i8) << 8 - 1) as f32;
     let _ = 0u8 as char;
+    let _ = true > false;
+    let _ = true >= false;
+    let _ = true < false;
+    let _ = true >= false;
 }
diff --git a/src/test/run-pass/const-negation.rs b/src/test/run-pass/const-negation.rs
index 96f4217e4cb..012fe0d95ec 100644
--- a/src/test/run-pass/const-negation.rs
+++ b/src/test/run-pass/const-negation.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(stmt_expr_attributes)]
-
 #[deny(const_err)]
 
 fn main() {
diff --git a/src/test/run-pass/enum-discrim-autosizing.rs b/src/test/run-pass/enum-discrim-autosizing.rs
index 53c44f2bb24..c85ab535fc1 100644
--- a/src/test/run-pass/enum-discrim-autosizing.rs
+++ b/src/test/run-pass/enum-discrim-autosizing.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(stmt_expr_attributes)]
-
 use std::mem::size_of;
 
 enum Ei8 {
diff --git a/src/test/run-pass/ifmt.rs b/src/test/run-pass/ifmt.rs
index 8b5536de12e..0ebe1ca07c7 100644
--- a/src/test/run-pass/ifmt.rs
+++ b/src/test/run-pass/ifmt.rs
@@ -14,7 +14,6 @@
 #![allow(unused_must_use)]
 #![allow(unused_features)]
 #![feature(box_syntax)]
-#![feature(question_mark)]
 
 use std::fmt::{self, Write};
 use std::usize;
diff --git a/src/test/run-pass/impl-trait/example-st.rs b/src/test/run-pass/impl-trait/example-st.rs
index 461d4cf4ff0..e9326ed286a 100644
--- a/src/test/run-pass/impl-trait/example-st.rs
+++ b/src/test/run-pass/impl-trait/example-st.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(conservative_impl_trait, question_mark)]
+#![feature(conservative_impl_trait)]
 
 struct State;
 type Error = ();
diff --git a/src/test/run-pass/issue-17121.rs b/src/test/run-pass/issue-17121.rs
index b3c80041ef8..dcbcc2d44b5 100644
--- a/src/test/run-pass/issue-17121.rs
+++ b/src/test/run-pass/issue-17121.rs
@@ -10,8 +10,6 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(question_mark)]
-
 use std::fs::File;
 use std::io::{self, BufReader, Read};
 
diff --git a/src/test/run-pass/issue-19404.rs b/src/test/run-pass/issue-19404.rs
index 0eea6ba22ca..c0f13b0b6c7 100644
--- a/src/test/run-pass/issue-19404.rs
+++ b/src/test/run-pass/issue-19404.rs
@@ -8,17 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(reflect_marker)]
-
 use std::any::TypeId;
-use std::marker::Reflect;
 use std::rc::Rc;
 
 type Fp<T> = Rc<T>;
 
 struct Engine;
 
-trait Component: 'static + Reflect {}
+trait Component: 'static {}
 impl Component for Engine {}
 
 trait Env {
diff --git a/src/test/run-pass/issue-20797.rs b/src/test/run-pass/issue-20797.rs
index de952436650..e45582dc2d3 100644
--- a/src/test/run-pass/issue-20797.rs
+++ b/src/test/run-pass/issue-20797.rs
@@ -10,8 +10,6 @@
 
 // Regression test for #20797.
 
-#![feature(question_mark)]
-
 use std::default::Default;
 use std::io;
 use std::fs;
diff --git a/src/test/run-pass/issue-21400.rs b/src/test/run-pass/issue-21400.rs
index 0d1be964748..6715b71a5f5 100644
--- a/src/test/run-pass/issue-21400.rs
+++ b/src/test/run-pass/issue-21400.rs
@@ -11,8 +11,6 @@
 // Regression test for #21400 which itself was extracted from
 // stackoverflow.com/questions/28031155/is-my-borrow-checker-drunk/28031580
 
-#![feature(question_mark)]
-
 fn main() {
     let mut t = Test;
     assert_eq!(t.method1("one"), Ok(1));
diff --git a/src/test/run-pass/issue-36744-bitcast-args-if-needed.rs b/src/test/run-pass/issue-36744-bitcast-args-if-needed.rs
new file mode 100644
index 00000000000..1859cc9ca00
--- /dev/null
+++ b/src/test/run-pass/issue-36744-bitcast-args-if-needed.rs
@@ -0,0 +1,32 @@
+// 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.
+
+// This tests for an ICE (and, if ignored, subsequent LLVM abort) when
+// a lifetime-parametric fn is passed into a context whose expected
+// type has a differing lifetime parameterization.
+
+struct A<'a> {
+    _a: &'a i32,
+}
+
+fn call<T>(s: T, functions: &Vec<for <'n> fn(&'n T)>) {
+    for function in functions {
+        function(&s);
+    }
+}
+
+fn f(a: &A) { println!("a holds {}", a._a); }
+
+fn main() {
+    let a = A { _a: &10 };
+
+    let vec: Vec<for <'u,'v> fn(&'u A<'v>)> = vec![f];
+    call(a, &vec);
+}
diff --git a/src/test/run-pass/issue-36744-without-calls.rs b/src/test/run-pass/issue-36744-without-calls.rs
new file mode 100644
index 00000000000..1766edb06b4
--- /dev/null
+++ b/src/test/run-pass/issue-36744-without-calls.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.
+
+// Tests for an LLVM abort when storing a lifetime-parametric fn into
+// context that is expecting one that is not lifetime-parametric
+// (i.e. has no `for <'_>`).
+
+pub struct A<'a>(&'a ());
+pub struct S<T>(T);
+
+pub fn bad<'s>(v: &mut S<fn(A<'s>)>, y: S<for<'b> fn(A<'b>)>) {
+    *v = y;
+}
+
+fn main() {}
diff --git a/src/test/compile-fail/feature-gate-try-operator.rs b/src/test/run-pass/issue-37020.rs
index b05c7323962..7d0d20269ab 100644
--- a/src/test/compile-fail/feature-gate-try-operator.rs
+++ b/src/test/run-pass/issue-37020.rs
@@ -8,11 +8,18 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-macro_rules! id {
-    ($e:expr) => { $e }
+#![allow(private_in_public)]
+
+mod foo {
+    pub mod bar {
+        extern crate core;
+    }
+}
+
+mod baz {
+    pub use foo::bar::core;
 }
 
 fn main() {
-    id!(x?);  //~ error: the `?` operator is not stable (see issue #31436)
-    y?;  //~ error: the `?` operator is not stable (see issue #31436)
+    baz::core::cell::Cell::new(0u32);
 }
diff --git a/src/test/run-pass/issue-37109.rs b/src/test/run-pass/issue-37109.rs
new file mode 100644
index 00000000000..1c893071d55
--- /dev/null
+++ b/src/test/run-pass/issue-37109.rs
@@ -0,0 +1,25 @@
+// 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 ToRef<'a> {
+    type Ref: 'a;
+}
+
+impl<'a, U: 'a> ToRef<'a> for U {
+    type Ref = &'a U;
+}
+
+fn example<'a, T>(value: &'a T) -> (<T as ToRef<'a>>::Ref, u32) {
+    (value, 0)
+}
+
+fn main() {
+    example(&0);
+}
diff --git a/src/test/run-pass/issue-8460.rs b/src/test/run-pass/issue-8460.rs
index 8d15fe30a1b..f16057ccab1 100644
--- a/src/test/run-pass/issue-8460.rs
+++ b/src/test/run-pass/issue-8460.rs
@@ -11,7 +11,7 @@
 // ignore-emscripten no threads support
 // ignore-pretty : (#23623) problems when  ending with // comments
 
-#![feature(rustc_attrs, stmt_expr_attributes, zero_one)]
+#![feature(rustc_attrs, zero_one)]
 
 use std::num::Zero;
 use std::thread;
diff --git a/src/test/run-pass/try-operator-hygiene.rs b/src/test/run-pass/try-operator-hygiene.rs
index ae622df498f..53d6185020a 100644
--- a/src/test/run-pass/try-operator-hygiene.rs
+++ b/src/test/run-pass/try-operator-hygiene.rs
@@ -18,8 +18,6 @@
 // This test verifies that the expansion is hygienic, i.e. it's not affected by other `val` and
 // `err` bindings that may be in scope.
 
-#![feature(question_mark)]
-
 use std::num::ParseIntError;
 
 fn main() {
diff --git a/src/test/run-pass/try-operator.rs b/src/test/run-pass/try-operator.rs
index de5ccf09c59..29de6364bf1 100644
--- a/src/test/run-pass/try-operator.rs
+++ b/src/test/run-pass/try-operator.rs
@@ -8,8 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(question_mark)]
-
 use std::fs::File;
 use std::io::{Read, self};
 use std::num::ParseIntError;
diff --git a/src/test/rustdoc/playground-empty.rs b/src/test/rustdoc/playground-empty.rs
new file mode 100644
index 00000000000..00881a62dd0
--- /dev/null
+++ b/src/test/rustdoc/playground-empty.rs
@@ -0,0 +1,21 @@
+// 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_name = "foo"]
+
+#![doc(html_playground_url = "")]
+
+//! module docs
+//!
+//! ```
+//! println!("Hello, world!");
+//! ```
+
+// @!has foo/index.html '//a[@class="test-arrow"]' "Run"
diff --git a/src/test/run-pass/lint-non-uppercase-statics-lowercase-mut-statics.rs b/src/test/rustdoc/playground-none.rs
index aa5b3834c01..83c312d7ab2 100644
--- a/src/test/run-pass/lint-non-uppercase-statics-lowercase-mut-statics.rs
+++ b/src/test/rustdoc/playground-none.rs
@@ -1,4 +1,4 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// 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.
 //
@@ -8,12 +8,12 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![crate_name = "foo"]
 
-// pretty-expanded FIXME #23616
+//! module docs
+//!
+//! ```
+//! println!("Hello, world!");
+//! ```
 
-#![forbid(non_camel_case_types)]
-#![forbid(non_upper_case_globals)]
-
-static mut bar: isize = 2;
-
-pub fn main() {}
+// @!has foo/index.html '//a[@class="test-arrow"]' "Run"
diff --git a/src/test/rustdoc/playground.rs b/src/test/rustdoc/playground.rs
new file mode 100644
index 00000000000..9eb8dec51a7
--- /dev/null
+++ b/src/test/rustdoc/playground.rs
@@ -0,0 +1,39 @@
+// 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.
+
+// ignore-tidy-linelength
+
+#![crate_name = "foo"]
+
+#![doc(html_playground_url = "https://www.example.com/")]
+
+//! module docs
+//!
+//! ```
+//! println!("Hello, world!");
+//! ```
+//!
+//! ```
+//! fn main() {
+//!     println!("Hello, world!");
+//! }
+//! ```
+//!
+//! ```
+//! #![feature(something)]
+//!
+//! fn main() {
+//!     println!("Hello, world!");
+//! }
+//! ```
+
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=fn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=fn%20main()%20%7B%0Aprintln!(%22Hello%2C%20world!%22)%3B%0A%7D"]' "Run"
+// @matches foo/index.html '//a[@class="test-arrow"][@href="https://www.example.com/?code=%23!%5Bfeature(something)%5D%0A%0Afn%20main()%20%7B%0A%20%20%20%20println!(%22Hello%2C%20world!%22)%3B%0A%7D%0A&version=nightly"]' "Run"
diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs
index b81258bd6d7..e6efd45cad1 100644
--- a/src/tools/compiletest/src/main.rs
+++ b/src/tools/compiletest/src/main.rs
@@ -13,9 +13,10 @@
 #![feature(box_syntax)]
 #![feature(rustc_private)]
 #![feature(test)]
-#![feature(question_mark)]
 #![feature(libc)]
 
+#![cfg_attr(stage0, feature(question_mark))]
+
 #![deny(warnings)]
 
 extern crate libc;
diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs
index 2c734c8e3e4..e33df0dfbc8 100644
--- a/src/tools/error_index_generator/main.rs
+++ b/src/tools/error_index_generator/main.rs
@@ -9,7 +9,6 @@
 // except according to those terms.
 
 #![feature(rustc_private, rustdoc)]
-#![feature(question_mark)]
 
 extern crate syntax;
 extern crate rustdoc;
@@ -25,7 +24,7 @@ use std::path::PathBuf;
 
 use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
 
-use rustdoc::html::markdown::Markdown;
+use rustdoc::html::markdown::{Markdown, PLAYGROUND};
 use rustc_serialize::json;
 
 enum OutputFormat {
@@ -202,6 +201,9 @@ fn parse_args() -> (OutputFormat, PathBuf) {
 }
 
 fn main() {
+    PLAYGROUND.with(|slot| {
+        *slot.borrow_mut() = Some((None, String::from("https://play.rust-lang.org/")));
+    });
     let (format, dst) = parse_args();
     if let Err(e) = main_with_result(format, &dst) {
         panic!("{}", e.description());
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 3e2bc9032a1..f79cc76e67d 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -24,8 +24,6 @@
 //! A few whitelisted exceptions are allowed as there's known bugs in rustdoc,
 //! but this should catch the majority of "broken link" cases.
 
-#![feature(question_mark)]
-
 extern crate url;
 
 use std::env;
diff --git a/src/tools/rustbook/build.rs b/src/tools/rustbook/build.rs
index 09c2d2510e3..d88ff48843a 100644
--- a/src/tools/rustbook/build.rs
+++ b/src/tools/rustbook/build.rs
@@ -131,7 +131,6 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
         {
             let mut buffer = BufWriter::new(File::create(&postlude)?);
             writeln!(&mut buffer, "<script src='rustbook.js'></script>")?;
-            writeln!(&mut buffer, "<script src='playpen.js'></script>")?;
             writeln!(&mut buffer, "</div></div>")?;
         }
 
@@ -143,7 +142,7 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
             format!("-o{}", out_path.display()),
             format!("--html-before-content={}", prelude.display()),
             format!("--html-after-content={}", postlude.display()),
-            format!("--markdown-playground-url=https://play.rust-lang.org"),
+            format!("--markdown-playground-url=https://play.rust-lang.org/"),
             format!("--markdown-css={}", item.path_to_root.join("rustbook.css").display()),
             "--markdown-no-toc".to_string(),
         ];
@@ -158,10 +157,6 @@ fn render(book: &Book, tgt: &Path) -> CliResult<()> {
     // create index.html from the root README
     fs::copy(&tgt.join("README.html"), &tgt.join("index.html"))?;
 
-    // Copy js for playpen
-    let mut playpen = File::create(tgt.join("playpen.js"))?;
-    let js = include_bytes!("../../librustdoc/html/static/playpen.js");
-    playpen.write_all(js)?;
     Ok(())
 }
 
diff --git a/src/tools/rustbook/main.rs b/src/tools/rustbook/main.rs
index 436dc119753..906251db1c2 100644
--- a/src/tools/rustbook/main.rs
+++ b/src/tools/rustbook/main.rs
@@ -12,7 +12,6 @@
 
 #![feature(rustc_private)]
 #![feature(rustdoc)]
-#![feature(question_mark)]
 
 extern crate rustdoc;
 extern crate rustc_back;