about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/Cargo.lock5
-rw-r--r--src/bootstrap/dist.rs1
-rw-r--r--src/bootstrap/test.rs1
-rwxr-xr-xsrc/etc/sugarise-doc-comments.py93
-rw-r--r--src/liballoc/binary_heap.rs6
-rw-r--r--src/liballoc/boxed.rs2
-rw-r--r--src/liballoc/btree/map.rs16
-rw-r--r--src/liballoc/btree/set.rs14
-rw-r--r--src/liballoc/lib.rs4
-rw-r--r--src/liballoc/linked_list.rs6
-rw-r--r--src/liballoc/str.rs59
-rw-r--r--src/liballoc/string.rs2
-rw-r--r--src/liballoc/vec.rs4
-rw-r--r--src/liballoc/vec_deque.rs8
-rw-r--r--src/libcore/ascii.rs2
-rw-r--r--src/libcore/cell.rs18
-rw-r--r--src/libcore/char.rs12
-rw-r--r--src/libcore/intrinsics.rs4
-rw-r--r--src/libcore/iter/iterator.rs53
-rw-r--r--src/libcore/iter/mod.rs42
-rw-r--r--src/libcore/iter/range.rs6
-rw-r--r--src/libcore/iter/sources.rs8
-rw-r--r--src/libcore/iter/traits.rs4
-rw-r--r--src/libcore/num/mod.rs54
-rw-r--r--src/libcore/option.rs14
-rw-r--r--src/libcore/result.rs6
-rw-r--r--src/libcore/slice/mod.rs22
-rw-r--r--src/libcore/str/mod.rs14
-rw-r--r--src/libcore/tests/lib.rs1
-rw-r--r--src/libcore/tests/num/uint_macros.rs11
-rw-r--r--src/librustc/dep_graph/dep_node.rs14
-rw-r--r--src/librustc/hir/lowering.rs8
-rw-r--r--src/librustc/hir/print.rs9
-rw-r--r--src/librustc/ich/impls_syntax.rs19
-rw-r--r--src/librustc/infer/error_reporting/mod.rs837
-rw-r--r--src/librustc/middle/cstore.rs7
-rw-r--r--src/librustc/middle/exported_symbols.rs61
-rw-r--r--src/librustc/middle/reachable.rs6
-rw-r--r--src/librustc/middle/stability.rs14
-rw-r--r--src/librustc/session/mod.rs66
-rw-r--r--src/librustc/traits/specialize/mod.rs2
-rw-r--r--src/librustc/ty/context.rs78
-rw-r--r--src/librustc/ty/maps/config.rs12
-rw-r--r--src/librustc/ty/maps/mod.rs31
-rw-r--r--src/librustc/ty/maps/plumbing.rs5
-rw-r--r--src/librustc/ty/mod.rs18
-rw-r--r--src/librustc_borrowck/borrowck/mod.rs2
-rw-r--r--src/librustc_const_eval/_match.rs4
-rw-r--r--src/librustc_const_eval/check_match.rs2
-rw-r--r--src/librustc_const_eval/eval.rs2
-rw-r--r--src/librustc_data_structures/obligation_forest/mod.rs8
-rw-r--r--src/librustc_driver/driver.rs12
-rw-r--r--src/librustc_incremental/assert_dep_graph.rs2
-rw-r--r--src/librustc_incremental/persist/dirty_clean.rs2
-rw-r--r--src/librustc_lint/builtin.rs2
-rw-r--r--src/librustc_lint/types.rs157
-rw-r--r--src/librustc_lint/unused.rs2
-rw-r--r--src/librustc_metadata/creader.rs4
-rw-r--r--src/librustc_metadata/cstore.rs2
-rw-r--r--src/librustc_metadata/cstore_impl.rs41
-rw-r--r--src/librustc_metadata/decoder.rs10
-rw-r--r--src/librustc_metadata/encoder.rs36
-rw-r--r--src/librustc_metadata/native_libs.rs4
-rw-r--r--src/librustc_metadata/schema.rs4
-rw-r--r--src/librustc_mir/borrow_check/error_reporting.rs196
-rw-r--r--src/librustc_mir/borrow_check/mod.rs10
-rw-r--r--src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs15
-rw-r--r--src/librustc_mir/borrow_check/nll/region_infer/mod.rs127
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs2
-rw-r--r--src/librustc_mir/build/cfg.rs2
-rw-r--r--src/librustc_mir/build/matches/simplify.rs2
-rw-r--r--src/librustc_mir/monomorphize/collector.rs4
-rw-r--r--src/librustc_mir/monomorphize/partitioning.rs6
-rw-r--r--src/librustc_mir/transform/clean_end_regions.rs2
-rw-r--r--src/librustc_mir/transform/lower_128bit.rs19
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs2
-rw-r--r--src/librustc_mir/util/borrowck_errors.rs2
-rw-r--r--src/librustc_plugin/load.rs2
-rw-r--r--src/librustc_resolve/build_reduced_graph.rs2
-rw-r--r--src/librustc_resolve/lib.rs6
-rw-r--r--src/librustc_resolve/macros.rs4
-rw-r--r--src/librustc_resolve/resolve_imports.rs2
-rw-r--r--src/librustc_trans/back/linker.rs8
-rw-r--r--src/librustc_trans/back/lto.rs2
-rw-r--r--src/librustc_trans/back/symbol_export.rs315
-rw-r--r--src/librustc_trans/back/write.rs37
-rw-r--r--src/librustc_trans/base.rs16
-rw-r--r--src/librustc_trans/callee.rs2
-rw-r--r--src/librustc_trans/consts.rs2
-rw-r--r--src/librustc_trans/context.rs6
-rw-r--r--src/librustc_trans/debuginfo/utils.rs2
-rw-r--r--src/librustc_trans/intrinsic.rs8
-rw-r--r--src/librustc_trans_utils/lib.rs55
-rw-r--r--src/librustc_trans_utils/symbol_names_test.rs2
-rw-r--r--src/librustc_trans_utils/trans_crate.rs3
-rw-r--r--src/librustc_typeck/astconv.rs2
-rw-r--r--src/librustc_typeck/check/_match.rs2
-rw-r--r--src/librustc_typeck/check/coercion.rs2
-rw-r--r--src/librustc_typeck/check/intrinsic.rs3
-rw-r--r--src/librustc_typeck/check/method/probe.rs2
-rw-r--r--src/librustc_typeck/check/mod.rs4
-rw-r--r--src/librustc_typeck/check/wfcheck.rs2
-rw-r--r--src/librustc_typeck/coherence/mod.rs2
-rw-r--r--src/librustc_typeck/collect.rs6
-rw-r--r--src/librustc_typeck/lib.rs2
-rw-r--r--src/librustdoc/test.rs2
-rw-r--r--src/libstd/collections/hash/map.rs68
-rw-r--r--src/libstd/collections/hash/set.rs18
-rw-r--r--src/libstd/ffi/c_str.rs2
-rw-r--r--src/libstd/lib.rs1
-rw-r--r--src/libstd/path.rs6
-rw-r--r--src/libstd/sys_common/wtf8.rs23
-rw-r--r--src/libstd_unicode/char.rs4
-rw-r--r--src/libstd_unicode/lib.rs1
-rw-r--r--src/libstd_unicode/u_str.rs3
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs17
-rw-r--r--src/libsyntax/ext/tt/quoted.rs15
-rw-r--r--src/libsyntax/feature_gate.rs7
-rw-r--r--src/libsyntax/parse/lexer/mod.rs33
-rw-r--r--src/libsyntax/parse/parser.rs2
-rw-r--r--src/libsyntax_ext/format.rs17
-rw-r--r--src/libsyntax_pos/lib.rs7
-rw-r--r--src/test/codegen/abi-main-signature-16bit-c-int.rs1
-rw-r--r--src/test/codegen/fastcall-inreg.rs2
-rw-r--r--src/test/codegen/global_asm.rs2
-rw-r--r--src/test/codegen/global_asm_include.rs2
-rw-r--r--src/test/codegen/global_asm_x2.rs2
-rw-r--r--src/test/codegen/repr-transparent-aggregates-1.rs1
-rw-r--r--src/test/incremental/feature_gate.rs23
-rw-r--r--src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs2
-rw-r--r--src/test/run-pass/extern-types-pointer-cast.rs2
-rw-r--r--src/test/run-pass/intrinsics-integer.rs37
-rw-r--r--src/test/run-pass/issue-36053.rs1
-rw-r--r--src/test/ui/cast_char.rs4
-rw-r--r--src/test/ui/cast_char.stderr4
-rw-r--r--src/test/ui/issue-22644.stderr16
-rw-r--r--src/test/ui/issue-42954.stderr2
-rw-r--r--src/test/ui/lint/type-overflow.rs33
-rw-r--r--src/test/ui/lint/type-overflow.stderr58
-rw-r--r--src/test/ui/nll/borrowed-local-error.rs26
-rw-r--r--src/test/ui/nll/borrowed-local-error.stderr17
-rw-r--r--src/test/ui/nll/borrowed-temporary-error.rs26
-rw-r--r--src/test/ui/nll/borrowed-temporary-error.stderr14
-rw-r--r--src/test/ui/nll/borrowed-universal-error-2.rs22
-rw-r--r--src/test/ui/nll/borrowed-universal-error-2.stderr18
-rw-r--r--src/test/ui/nll/borrowed-universal-error.rs26
-rw-r--r--src/test/ui/nll/borrowed-universal-error.stderr18
-rw-r--r--src/test/ui/nll/capture-ref-in-struct.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/escape-argument.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr2
-rw-r--r--src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr2
-rw-r--r--src/test/ui/nll/return-ref-mut-issue-46557.stderr2
-rw-r--r--src/test/ui/raw_string.rs14
-rw-r--r--src/test/ui/raw_string.stderr8
-rw-r--r--src/tools/compiletest/src/util.rs1
-rw-r--r--src/tools/tidy/Cargo.toml5
-rw-r--r--src/tools/tidy/src/deps.rs248
-rw-r--r--src/tools/tidy/src/lib.rs5
-rw-r--r--src/tools/tidy/src/main.rs6
160 files changed, 2361 insertions, 1388 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 7620fe8ddb3..5e7909ff435 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -2585,6 +2585,11 @@ dependencies = [
 [[package]]
 name = "tidy"
 version = "0.1.0"
+dependencies = [
+ "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
+]
 
 [[package]]
 name = "time"
diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs
index 576e5078247..aa0a7c52246 100644
--- a/src/bootstrap/dist.rs
+++ b/src/bootstrap/dist.rs
@@ -810,6 +810,7 @@ impl Step for Src {
             "src/libterm",
             "src/jemalloc",
             "src/libprofiler_builtins",
+            "src/stdsimd",
         ];
         let std_src_dirs_exclude = [
             "src/libcompiler_builtins/compiler-rt/test",
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index c0998c1e42c..48490493525 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -528,6 +528,7 @@ impl Step for Tidy {
         println!("tidy check ({})", host);
         let mut cmd = builder.tool_cmd(Tool::Tidy);
         cmd.arg(build.src.join("src"));
+        cmd.arg(&build.initial_cargo);
         if !build.config.vendor {
             cmd.arg("--no-vendor");
         }
diff --git a/src/etc/sugarise-doc-comments.py b/src/etc/sugarise-doc-comments.py
deleted file mode 100755
index ac2223f4ace..00000000000
--- a/src/etc/sugarise-doc-comments.py
+++ /dev/null
@@ -1,93 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
-# file at the top-level directory of this distribution and at
-# http://rust-lang.org/COPYRIGHT.
-#
-# 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 script attempts to turn doc comment attributes (#[doc = "..."])
-# into sugared-doc-comments (/** ... */ and /// ...)
-#
-# it sugarises all .rs/.rc files underneath the working directory
-#
-
-import sys
-import os
-import fnmatch
-import re
-
-
-DOC_PATTERN = '^(?P<indent>[\\t ]*)#\\[(\\s*)doc(\\s*)=' + \
-              '(\\s*)"(?P<text>(\\"|[^"])*?)"(\\s*)\\]' + \
-              '(?P<semi>;)?'
-
-ESCAPES = [("\\'", "'"),
-           ('\\"', '"'),
-           ("\\n", "\n"),
-           ("\\r", "\r"),
-           ("\\t", "\t")]
-
-
-def unescape(s):
-    for (find, repl) in ESCAPES:
-        s = s.replace(find, repl)
-    return s
-
-
-def block_trim(s):
-    lns = s.splitlines()
-
-    # remove leading/trailing whitespace-lines
-    while lns and not lns[0].strip():
-        lns = lns[1:]
-    while lns and not lns[-1].strip():
-        lns = lns[:-1]
-
-    # remove leading horizontal whitespace
-    n = sys.maxsize
-    for ln in lns:
-        if ln.strip():
-            n = min(n, len(re.search('^\s*', ln).group()))
-    if n != sys.maxsize:
-        lns = [ln[n:] for ln in lns]
-
-    # strip trailing whitespace
-    lns = [ln.rstrip() for ln in lns]
-
-    return lns
-
-
-def replace_doc(m):
-    indent = m.group('indent')
-    text = block_trim(unescape(m.group('text')))
-
-    if len(text) > 1:
-        inner = '!' if m.group('semi') else '*'
-        starify = lambda s: indent + ' *' + (' ' + s if s else '')
-        text = '\n'.join(map(starify, text))
-        repl = indent + '/*' + inner + '\n' + text + '\n' + indent + ' */'
-    else:
-        inner = '!' if m.group('semi') else '/'
-        repl = indent + '//' + inner + ' ' + text[0]
-
-    return repl
-
-
-def sugarise_file(path):
-    s = open(path).read()
-
-    r = re.compile(DOC_PATTERN, re.MULTILINE | re.DOTALL)
-    ns = re.sub(r, replace_doc, s)
-
-    if s != ns:
-        open(path, 'w').write(ns)
-
-for (dirpath, dirnames, filenames) in os.walk('.'):
-    for name in fnmatch.filter(filenames, '*.r[sc]'):
-        sugarise_file(os.path.join(dirpath, name))
diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/binary_heap.rs
index 3041f85cd4c..8aaac5d6e08 100644
--- a/src/liballoc/binary_heap.rs
+++ b/src/liballoc/binary_heap.rs
@@ -964,7 +964,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for Iter<'a, T> {}
 
 /// An owning iterator over the elements of a `BinaryHeap`.
@@ -1019,7 +1019,7 @@ impl<T> ExactSizeIterator for IntoIter<T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<T> FusedIterator for IntoIter<T> {}
 
 /// A draining iterator over the elements of a `BinaryHeap`.
@@ -1065,7 +1065,7 @@ impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T: 'a> FusedIterator for Drain<'a, T> {}
 
 #[stable(feature = "binary_heap_extras_15", since = "1.5.0")]
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 75a59de337c..b776556d59f 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -722,7 +722,7 @@ impl<I: ExactSizeIterator + ?Sized> ExactSizeIterator for Box<I> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I: FusedIterator + ?Sized> FusedIterator for Box<I> {}
 
 
diff --git a/src/liballoc/btree/map.rs b/src/liballoc/btree/map.rs
index 618ef81fdd9..ed9c8c18f0d 100644
--- a/src/liballoc/btree/map.rs
+++ b/src/liballoc/btree/map.rs
@@ -1156,7 +1156,7 @@ impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for Iter<'a, K, V> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1235,7 +1235,7 @@ impl<'a, K: 'a, V: 'a> ExactSizeIterator for IterMut<'a, K, V> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1365,7 +1365,7 @@ impl<K, V> ExactSizeIterator for IntoIter<K, V> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<K, V> FusedIterator for IntoIter<K, V> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1395,7 +1395,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for Keys<'a, K, V> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1432,7 +1432,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for Values<'a, K, V> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1482,7 +1482,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {}
 
 
@@ -1561,7 +1561,7 @@ impl<'a, K, V> Range<'a, K, V> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for Range<'a, K, V> {}
 
 #[stable(feature = "btree_range", since = "1.17.0")]
@@ -1630,7 +1630,7 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for RangeMut<'a, K, V> {}
 
 impl<'a, K, V> RangeMut<'a, K, V> {
diff --git a/src/liballoc/btree/set.rs b/src/liballoc/btree/set.rs
index 327eaaf4651..2e3157147a0 100644
--- a/src/liballoc/btree/set.rs
+++ b/src/liballoc/btree/set.rs
@@ -946,7 +946,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> {
     fn len(&self) -> usize { self.iter.len() }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for Iter<'a, T> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -971,7 +971,7 @@ impl<T> ExactSizeIterator for IntoIter<T> {
     fn len(&self) -> usize { self.iter.len() }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<T> FusedIterator for IntoIter<T> {}
 
 #[stable(feature = "btree_range", since = "1.17.0")]
@@ -997,7 +997,7 @@ impl<'a, T> DoubleEndedIterator for Range<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for Range<'a, T> {}
 
 /// Compare `x` and `y`, but return `short` if x is None and `long` if y is None
@@ -1044,7 +1044,7 @@ impl<'a, T: Ord> Iterator for Difference<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T: Ord> FusedIterator for Difference<'a, T> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1078,7 +1078,7 @@ impl<'a, T: Ord> Iterator for SymmetricDifference<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T: Ord> FusedIterator for SymmetricDifference<'a, T> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1116,7 +1116,7 @@ impl<'a, T: Ord> Iterator for Intersection<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T: Ord> FusedIterator for Intersection<'a, T> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1150,5 +1150,5 @@ impl<'a, T: Ord> Iterator for Union<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T: Ord> FusedIterator for Union<'a, T> {}
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index d250cfe1880..3f306784558 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -96,7 +96,6 @@
 #![feature(fmt_internals)]
 #![feature(from_ref)]
 #![feature(fundamental)]
-#![feature(fused)]
 #![feature(generic_param_attrs)]
 #![feature(i128_type)]
 #![feature(inclusive_range)]
@@ -124,8 +123,9 @@
 #![feature(allocator_internals)]
 #![feature(on_unimplemented)]
 #![feature(exact_chunks)]
+#![feature(pointer_methods)]
 
-#![cfg_attr(not(test), feature(fused, fn_traits, placement_new_protocol, swap_with_slice, i128))]
+#![cfg_attr(not(test), feature(fn_traits, placement_new_protocol, swap_with_slice, i128))]
 #![cfg_attr(test, feature(test, box_heap))]
 
 // Allow testing this library
diff --git a/src/liballoc/linked_list.rs b/src/liballoc/linked_list.rs
index ec579e3fd68..097d2e414f5 100644
--- a/src/liballoc/linked_list.rs
+++ b/src/liballoc/linked_list.rs
@@ -897,7 +897,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for Iter<'a, T> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -946,7 +946,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for IterMut<'a, T> {}
 
 impl<'a, T> IterMut<'a, T> {
@@ -1117,7 +1117,7 @@ impl<T> DoubleEndedIterator for IntoIter<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ExactSizeIterator for IntoIter<T> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<T> FusedIterator for IntoIter<T> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs
index a00e3d17dd0..14d5e96d2e7 100644
--- a/src/liballoc/str.rs
+++ b/src/liballoc/str.rs
@@ -43,6 +43,7 @@ use core::str as core_str;
 use core::str::pattern::Pattern;
 use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher};
 use core::mem;
+use core::ptr;
 use core::iter::FusedIterator;
 use std_unicode::str::{UnicodeStr, Utf16Encoder};
 
@@ -171,7 +172,7 @@ impl<'a> Iterator for EncodeUtf16<'a> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a> FusedIterator for EncodeUtf16<'a> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -2066,9 +2067,59 @@ impl str {
     /// ```
     #[stable(feature = "repeat_str", since = "1.16.0")]
     pub fn repeat(&self, n: usize) -> String {
-        let mut s = String::with_capacity(self.len() * n);
-        s.extend((0..n).map(|_| self));
-        s
+        if n == 0 {
+            return String::new();
+        }
+
+        // If `n` is larger than zero, it can be split as
+        // `n = 2^expn + rem (2^expn > rem, expn >= 0, rem >= 0)`.
+        // `2^expn` is the number represented by the leftmost '1' bit of `n`,
+        // and `rem` is the remaining part of `n`.
+
+        // Using `Vec` to access `set_len()`.
+        let mut buf = Vec::with_capacity(self.len() * n);
+
+        // `2^expn` repetition is done by doubling `buf` `expn`-times.
+        buf.extend(self.as_bytes());
+        {
+            let mut m = n >> 1;
+            // If `m > 0`, there are remaining bits up to the leftmost '1'.
+            while m > 0 {
+                // `buf.extend(buf)`:
+                unsafe {
+                    ptr::copy_nonoverlapping(
+                        buf.as_ptr(),
+                        (buf.as_mut_ptr() as *mut u8).add(buf.len()),
+                        buf.len(),
+                    );
+                    // `buf` has capacity of `self.len() * n`.
+                    let buf_len = buf.len();
+                    buf.set_len(buf_len * 2);
+                }
+
+                m >>= 1;
+            }
+        }
+
+        // `rem` (`= n - 2^expn`) repetition is done by copying
+        // first `rem` repetitions from `buf` itself.
+        let rem_len = self.len() * n - buf.len(); // `self.len() * rem`
+        if rem_len > 0 {
+            // `buf.extend(buf[0 .. rem_len])`:
+            unsafe {
+                // This is non-overlapping since `2^expn > rem`.
+                ptr::copy_nonoverlapping(
+                    buf.as_ptr(),
+                    (buf.as_mut_ptr() as *mut u8).add(buf.len()),
+                    rem_len,
+                );
+                // `buf.len() + rem_len` equals to `buf.capacity()` (`= self.len() * n`).
+                let buf_cap = buf.capacity();
+                buf.set_len(buf_cap);
+            }
+        }
+
+        unsafe { String::from_utf8_unchecked(buf) }
     }
 
     /// Checks if all characters in this string are within the ASCII range.
diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs
index 409d2ab287e..370fb6b4e89 100644
--- a/src/liballoc/string.rs
+++ b/src/liballoc/string.rs
@@ -2254,5 +2254,5 @@ impl<'a> DoubleEndedIterator for Drain<'a> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a> FusedIterator for Drain<'a> {}
diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs
index feed7c8699a..2f57c53a6d8 100644
--- a/src/liballoc/vec.rs
+++ b/src/liballoc/vec.rs
@@ -2273,7 +2273,7 @@ impl<T> ExactSizeIterator for IntoIter<T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<T> FusedIterator for IntoIter<T> {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
@@ -2379,7 +2379,7 @@ impl<'a, T> ExactSizeIterator for Drain<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for Drain<'a, T> {}
 
 /// A place for insertion at the back of a `Vec`.
diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/vec_deque.rs
index 8b686365e69..68add3cbd51 100644
--- a/src/liballoc/vec_deque.rs
+++ b/src/liballoc/vec_deque.rs
@@ -1991,7 +1991,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for Iter<'a, T> {}
 
 
@@ -2084,7 +2084,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for IterMut<'a, T> {}
 
 /// An owning iterator over the elements of a `VecDeque`.
@@ -2140,7 +2140,7 @@ impl<T> ExactSizeIterator for IntoIter<T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<T> FusedIterator for IntoIter<T> {}
 
 /// A draining iterator over the elements of a `VecDeque`.
@@ -2247,7 +2247,7 @@ impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> {
 #[stable(feature = "drain", since = "1.6.0")]
 impl<'a, T: 'a> ExactSizeIterator for Drain<'a, T> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T: 'a> FusedIterator for Drain<'a, T> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs
index f409536d1b0..2c4bccebceb 100644
--- a/src/libcore/ascii.rs
+++ b/src/libcore/ascii.rs
@@ -136,7 +136,7 @@ impl DoubleEndedIterator for EscapeDefault {
 }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl ExactSizeIterator for EscapeDefault {}
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl FusedIterator for EscapeDefault {}
 
 #[stable(feature = "std_debug", since = "1.16.0")]
diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs
index 419ae96b94b..1372151b753 100644
--- a/src/libcore/cell.rs
+++ b/src/libcore/cell.rs
@@ -10,6 +10,24 @@
 
 //! Shareable mutable containers.
 //!
+//! Rust memory safety is based on this rule: Given an object `T`, it is only possible to
+//! have one of the following:
+//!
+//! - Having several immutable references (`&T`) to the object (also known as **aliasing**).
+//! - Having one mutable reference (`&mut T`) to the object (also known as **mutability**).
+//!
+//! This is enforced by the Rust compiler. However, there are situations where this rule is not
+//! flexible enough. Sometimes it is required to have multiple references to an object and yet
+//! mutate it.
+//!
+//! Shareable mutable containers exist to permit mutability in a controlled manner, even in the
+//! presence of aliasing. Both `Cell<T>` and `RefCell<T>` allows to do this in a single threaded
+//! way. However, neither `Cell<T>` nor `RefCell<T>` are thread safe (they do not implement
+//! `Sync`). If you need to do aliasing and mutation between multiple threads it is possible to
+//! use [`Mutex`](../../std/sync/struct.Mutex.html),
+//! [`RwLock`](../../std/sync/struct.RwLock.html) or
+//! [`atomic`](../../core/sync/atomic/index.html) types.
+//!
 //! Values of the `Cell<T>` and `RefCell<T>` types may be mutated through shared references (i.e.
 //! the common `&T` type), whereas most Rust types can only be mutated through unique (`&mut T`)
 //! references. We say that `Cell<T>` and `RefCell<T>` provide 'interior mutability', in contrast
diff --git a/src/libcore/char.rs b/src/libcore/char.rs
index 7215bd2a476..1638f9710f5 100644
--- a/src/libcore/char.rs
+++ b/src/libcore/char.rs
@@ -79,7 +79,7 @@ pub const MAX: char = '\u{10ffff}';
 
 /// Converts a `u32` to a `char`.
 ///
-/// Note that all [`char`]s are valid [`u32`]s, and can be casted to one with
+/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with
 /// [`as`]:
 ///
 /// ```
@@ -131,7 +131,7 @@ pub fn from_u32(i: u32) -> Option<char> {
 
 /// Converts a `u32` to a `char`, ignoring validity.
 ///
-/// Note that all [`char`]s are valid [`u32`]s, and can be casted to one with
+/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with
 /// [`as`]:
 ///
 /// ```
@@ -643,7 +643,7 @@ impl ExactSizeIterator for EscapeUnicode {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl FusedIterator for EscapeUnicode {}
 
 #[stable(feature = "char_struct_display", since = "1.16.0")]
@@ -756,7 +756,7 @@ impl ExactSizeIterator for EscapeDefault {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl FusedIterator for EscapeDefault {}
 
 #[stable(feature = "char_struct_display", since = "1.16.0")]
@@ -790,7 +790,7 @@ impl Iterator for EscapeDebug {
 #[stable(feature = "char_escape_debug", since = "1.20.0")]
 impl ExactSizeIterator for EscapeDebug { }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl FusedIterator for EscapeDebug {}
 
 #[stable(feature = "char_escape_debug", since = "1.20.0")]
@@ -904,5 +904,5 @@ impl<I: Iterator<Item = u8>> Iterator for DecodeUtf8<I> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[unstable(feature = "decode_utf8", issue = "33906")]
 impl<I: FusedIterator<Item = u8>> FusedIterator for DecodeUtf8<I> {}
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index a05d67a304f..830ebad0654 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1292,6 +1292,10 @@ extern "rust-intrinsic" {
     /// Reverses the bytes in an integer type `T`.
     pub fn bswap<T>(x: T) -> T;
 
+    /// Reverses the bits in an integer type `T`.
+    #[cfg(not(stage0))]
+    pub fn bitreverse<T>(x: T) -> T;
+
     /// Performs checked integer addition.
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `overflowing_add` method. For example,
diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs
index b06534c9c1e..2cfbc092293 100644
--- a/src/libcore/iter/iterator.rs
+++ b/src/libcore/iter/iterator.rs
@@ -1180,19 +1180,19 @@ pub trait Iterator {
     ///
     /// // this iterator sequence is complex.
     /// let sum = a.iter()
-    ///             .cloned()
-    ///             .filter(|&x| x % 2 == 0)
-    ///             .fold(0, |sum, i| sum + i);
+    ///     .cloned()
+    ///     .filter(|x| x % 2 == 0)
+    ///     .fold(0, |sum, i| sum + i);
     ///
     /// println!("{}", sum);
     ///
     /// // let's add some inspect() calls to investigate what's happening
     /// let sum = a.iter()
-    ///             .cloned()
-    ///             .inspect(|x| println!("about to filter: {}", x))
-    ///             .filter(|&x| x % 2 == 0)
-    ///             .inspect(|x| println!("made it through filter: {}", x))
-    ///             .fold(0, |sum, i| sum + i);
+    ///     .cloned()
+    ///     .inspect(|x| println!("about to filter: {}", x))
+    ///     .filter(|x| x % 2 == 0)
+    ///     .inspect(|x| println!("made it through filter: {}", x))
+    ///     .fold(0, |sum, i| sum + i);
     ///
     /// println!("{}", sum);
     /// ```
@@ -1200,6 +1200,7 @@ pub trait Iterator {
     /// This will print:
     ///
     /// ```text
+    /// 6
     /// about to filter: 1
     /// about to filter: 4
     /// made it through filter: 4
@@ -1230,8 +1231,7 @@ pub trait Iterator {
     ///
     /// let iter = a.into_iter();
     ///
-    /// let sum: i32 = iter.take(5)
-    ///                    .fold(0, |acc, &i| acc + i );
+    /// let sum: i32 = iter.take(5).fold(0, |acc, i| acc + i );
     ///
     /// assert_eq!(sum, 6);
     ///
@@ -1245,9 +1245,7 @@ pub trait Iterator {
     /// let mut iter = a.into_iter();
     ///
     /// // instead, we add in a .by_ref()
-    /// let sum: i32 = iter.by_ref()
-    ///                    .take(2)
-    ///                    .fold(0, |acc, &i| acc + i );
+    /// let sum: i32 = iter.by_ref().take(2).fold(0, |acc, i| acc + i );
     ///
     /// assert_eq!(sum, 3);
     ///
@@ -1304,9 +1302,7 @@ pub trait Iterator {
     ///
     /// let a = [1, 2, 3];
     ///
-    /// let doubled: VecDeque<i32> = a.iter()
-    ///                               .map(|&x| x * 2)
-    ///                               .collect();
+    /// let doubled: VecDeque<i32> = a.iter().map(|&x| x * 2).collect();
     ///
     /// assert_eq!(2, doubled[0]);
     /// assert_eq!(4, doubled[1]);
@@ -1318,9 +1314,7 @@ pub trait Iterator {
     /// ```
     /// let a = [1, 2, 3];
     ///
-    /// let doubled = a.iter()
-    ///                .map(|&x| x * 2)
-    ///                .collect::<Vec<i32>>();
+    /// let doubled = a.iter().map(|x| x * 2).collect::<Vec<i32>>();
     ///
     /// assert_eq!(vec![2, 4, 6], doubled);
     /// ```
@@ -1331,9 +1325,7 @@ pub trait Iterator {
     /// ```
     /// let a = [1, 2, 3];
     ///
-    /// let doubled = a.iter()
-    ///                .map(|&x| x * 2)
-    ///                .collect::<Vec<_>>();
+    /// let doubled = a.iter().map(|x| x * 2).collect::<Vec<_>>();
     ///
     /// assert_eq!(vec![2, 4, 6], doubled);
     /// ```
@@ -1344,9 +1336,9 @@ pub trait Iterator {
     /// let chars = ['g', 'd', 'k', 'k', 'n'];
     ///
     /// let hello: String = chars.iter()
-    ///                          .map(|&x| x as u8)
-    ///                          .map(|x| (x + 1) as char)
-    ///                          .collect();
+    ///     .map(|&x| x as u8)
+    ///     .map(|x| (x + 1) as char)
+    ///     .collect();
     ///
     /// assert_eq!("hello", hello);
     /// ```
@@ -1393,8 +1385,9 @@ pub trait Iterator {
     /// ```
     /// let a = [1, 2, 3];
     ///
-    /// let (even, odd): (Vec<i32>, Vec<i32>) = a.into_iter()
-    ///                                          .partition(|&n| n % 2 == 0);
+    /// let (even, odd): (Vec<i32>, Vec<i32>) = a
+    ///     .into_iter()
+    ///     .partition(|&n| n % 2 == 0);
     ///
     /// assert_eq!(even, vec![2]);
     /// assert_eq!(odd, vec![1, 3]);
@@ -1457,8 +1450,7 @@ pub trait Iterator {
     /// let a = [1, 2, 3];
     ///
     /// // the checked sum of all of the elements of the array
-    /// let sum = a.iter()
-    ///            .try_fold(0i8, |acc, &x| acc.checked_add(x));
+    /// let sum = a.iter().try_fold(0i8, |acc, &x| acc.checked_add(x));
     ///
     /// assert_eq!(sum, Some(6));
     /// ```
@@ -1556,8 +1548,7 @@ pub trait Iterator {
     /// let a = [1, 2, 3];
     ///
     /// // the sum of all of the elements of the array
-    /// let sum = a.iter()
-    ///            .fold(0, |acc, &x| acc + x);
+    /// let sum = a.iter().fold(0, |acc, x| acc + x);
     ///
     /// assert_eq!(sum, 6);
     /// ```
diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs
index 257d7d6caaa..a6802d606ca 100644
--- a/src/libcore/iter/mod.rs
+++ b/src/libcore/iter/mod.rs
@@ -344,7 +344,7 @@ pub use self::sources::{Once, once};
 pub use self::traits::{FromIterator, IntoIterator, DoubleEndedIterator, Extend};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use self::traits::{ExactSizeIterator, Sum, Product};
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 pub use self::traits::FusedIterator;
 #[unstable(feature = "trusted_len", issue = "37572")]
 pub use self::traits::TrustedLen;
@@ -506,7 +506,7 @@ impl<I> ExactSizeIterator for Rev<I>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I> FusedIterator for Rev<I>
     where I: FusedIterator + DoubleEndedIterator {}
 
@@ -589,7 +589,7 @@ impl<'a, I, T: 'a> ExactSizeIterator for Cloned<I>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, I, T: 'a> FusedIterator for Cloned<I>
     where I: FusedIterator<Item=&'a T>, T: Clone
 {}
@@ -662,7 +662,7 @@ impl<I> Iterator for Cycle<I> where I: Clone + Iterator {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I> FusedIterator for Cycle<I> where I: Clone + Iterator {}
 
 /// An iterator for stepping iterators by a custom amount.
@@ -1002,7 +1002,7 @@ impl<A, B> DoubleEndedIterator for Chain<A, B> where
 }
 
 // Note: *both* must be fused to handle double-ended iterators.
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<A, B> FusedIterator for Chain<A, B>
     where A: FusedIterator,
           B: FusedIterator<Item=A::Item>,
@@ -1262,7 +1262,7 @@ unsafe impl<A, B> TrustedRandomAccess for Zip<A, B>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<A, B> FusedIterator for Zip<A, B>
     where A: FusedIterator, B: FusedIterator, {}
 
@@ -1404,7 +1404,7 @@ impl<B, I: ExactSizeIterator, F> ExactSizeIterator for Map<I, F>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<B, I: FusedIterator, F> FusedIterator for Map<I, F>
     where F: FnMut(I::Item) -> B {}
 
@@ -1553,7 +1553,7 @@ impl<I: DoubleEndedIterator, P> DoubleEndedIterator for Filter<I, P>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I: FusedIterator, P> FusedIterator for Filter<I, P>
     where P: FnMut(&I::Item) -> bool {}
 
@@ -1663,7 +1663,7 @@ impl<B, I: DoubleEndedIterator, F> DoubleEndedIterator for FilterMap<I, F>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<B, I: FusedIterator, F> FusedIterator for FilterMap<I, F>
     where F: FnMut(I::Item) -> Option<B> {}
 
@@ -1818,7 +1818,7 @@ unsafe impl<I> TrustedRandomAccess for Enumerate<I>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I> FusedIterator for Enumerate<I> where I: FusedIterator {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
@@ -1938,7 +1938,7 @@ impl<I: Iterator> Iterator for Peekable<I> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I: ExactSizeIterator> ExactSizeIterator for Peekable<I> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I: FusedIterator> FusedIterator for Peekable<I> {}
 
 impl<I: Iterator> Peekable<I> {
@@ -2072,7 +2072,7 @@ impl<I: Iterator, P> Iterator for SkipWhile<I, P>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I, P> FusedIterator for SkipWhile<I, P>
     where I: FusedIterator, P: FnMut(&I::Item) -> bool {}
 
@@ -2151,7 +2151,7 @@ impl<I: Iterator, P> Iterator for TakeWhile<I, P>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I, P> FusedIterator for TakeWhile<I, P>
     where I: FusedIterator, P: FnMut(&I::Item) -> bool {}
 
@@ -2290,7 +2290,7 @@ impl<I> DoubleEndedIterator for Skip<I> where I: DoubleEndedIterator + ExactSize
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I> FusedIterator for Skip<I> where I: FusedIterator {}
 
 /// An iterator that only iterates over the first `n` iterations of `iter`.
@@ -2371,7 +2371,7 @@ impl<I> Iterator for Take<I> where I: Iterator{
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I> ExactSizeIterator for Take<I> where I: ExactSizeIterator {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I> FusedIterator for Take<I> where I: FusedIterator {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
@@ -2517,7 +2517,7 @@ impl<I: DoubleEndedIterator, U, F> DoubleEndedIterator for FlatMap<I, U, F>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I, U, F> FusedIterator for FlatMap<I, U, F>
     where I: FusedIterator, U: IntoIterator, F: FnMut(I::Item) -> U {}
 
@@ -2605,7 +2605,7 @@ impl<I, U> DoubleEndedIterator for Flatten<I>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I, U> FusedIterator for Flatten<I>
     where I: FusedIterator, U: Iterator,
           I::Item: IntoIterator<IntoIter = U, Item = U::Item> {}
@@ -2765,7 +2765,7 @@ pub struct Fuse<I> {
     done: bool
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I> FusedIterator for Fuse<I> where I: Iterator {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -2896,7 +2896,7 @@ unsafe impl<I> TrustedRandomAccess for Fuse<I>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I> Iterator for Fuse<I> where I: FusedIterator {
     #[inline]
     fn next(&mut self) -> Option<<I as Iterator>::Item> {
@@ -2938,7 +2938,7 @@ impl<I> Iterator for Fuse<I> where I: FusedIterator {
     }
 }
 
-#[unstable(feature = "fused", reason = "recently added", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I> DoubleEndedIterator for Fuse<I>
     where I: DoubleEndedIterator + FusedIterator
 {
@@ -3082,6 +3082,6 @@ impl<I: ExactSizeIterator, F> ExactSizeIterator for Inspect<I, F>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<I: FusedIterator, F> FusedIterator for Inspect<I, F>
     where F: FnMut(&I::Item) {}
diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs
index 65b38c94dda..9a3fd215dcf 100644
--- a/src/libcore/iter/range.rs
+++ b/src/libcore/iter/range.rs
@@ -295,7 +295,7 @@ impl<A: Step> DoubleEndedIterator for ops::Range<A> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<A: Step> FusedIterator for ops::Range<A> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -322,7 +322,7 @@ impl<A: Step> Iterator for ops::RangeFrom<A> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<A: Step> FusedIterator for ops::RangeFrom<A> {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
@@ -463,5 +463,5 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}
diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs
index dfd42f3e733..0fc1a3aa8ac 100644
--- a/src/libcore/iter/sources.rs
+++ b/src/libcore/iter/sources.rs
@@ -41,7 +41,7 @@ impl<A: Clone> DoubleEndedIterator for Repeat<A> {
     fn next_back(&mut self) -> Option<A> { Some(self.element.clone()) }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<A: Clone> FusedIterator for Repeat<A> {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
@@ -135,7 +135,7 @@ impl<A, F: FnMut() -> A> DoubleEndedIterator for RepeatWith<F> {
     fn next_back(&mut self) -> Option<A> { self.next() }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[unstable(feature = "iterator_repeat_with", issue = "48169")]
 impl<A, F: FnMut() -> A> FusedIterator for RepeatWith<F> {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
@@ -259,7 +259,7 @@ impl<T> ExactSizeIterator for Empty<T> {
 #[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<T> TrustedLen for Empty<T> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<T> FusedIterator for Empty<T> {}
 
 // not #[derive] because that adds a Clone bound on T,
@@ -340,7 +340,7 @@ impl<T> ExactSizeIterator for Once<T> {
 #[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<T> TrustedLen for Once<T> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<T> FusedIterator for Once<T> {}
 
 /// Creates an iterator that yields an element exactly once.
diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs
index 860742d9eab..0267fcd3754 100644
--- a/src/libcore/iter/traits.rs
+++ b/src/libcore/iter/traits.rs
@@ -959,10 +959,10 @@ impl<T, U, E> Product<Result<U, E>> for Result<T, E>
 /// [`None`]: ../../std/option/enum.Option.html#variant.None
 /// [`Iterator::fuse`]: ../../std/iter/trait.Iterator.html#method.fuse
 /// [`Fuse`]: ../../std/iter/struct.Fuse.html
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 pub trait FusedIterator: Iterator {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, I: FusedIterator + ?Sized> FusedIterator for &'a mut I {}
 
 /// An iterator that reports an accurate length using size_hint.
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index 59a67fff48c..a46ac2b5f0f 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -321,6 +321,33 @@ $EndFeature, "
             (self as $UnsignedT).swap_bytes() as Self
         }
 
+        /// Reverses the bit pattern of the integer.
+        ///
+        /// # Examples
+        ///
+        /// Please note that this example is shared between integer types.
+        /// Which explains why `i16` is used here.
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// #![feature(reverse_bits)]
+        ///
+        /// let n: i16 = 0b0000000_01010101;
+        /// assert_eq!(n, 85);
+        ///
+        /// let m = n.reverse_bits();
+        ///
+        /// assert_eq!(m as u16, 0b10101010_00000000);
+        /// assert_eq!(m, -22016);
+        /// ```
+        #[unstable(feature = "reverse_bits", issue = "48763")]
+        #[cfg(not(stage0))]
+        #[inline]
+        pub fn reverse_bits(self) -> Self {
+            (self as $UnsignedT).reverse_bits() as Self
+        }
+
         doc_comment! {
             concat!("Converts an integer from big endian to the target's endianness.
 
@@ -1773,6 +1800,33 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, "
             unsafe { intrinsics::bswap(self as $ActualT) as Self }
         }
 
+        /// Reverses the bit pattern of the integer.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// Please note that this example is shared between integer types.
+        /// Which explains why `u16` is used here.
+        ///
+        /// ```
+        /// #![feature(reverse_bits)]
+        ///
+        /// let n: u16 = 0b0000000_01010101;
+        /// assert_eq!(n, 85);
+        ///
+        /// let m = n.reverse_bits();
+        ///
+        /// assert_eq!(m, 0b10101010_00000000);
+        /// assert_eq!(m, 43520);
+        /// ```
+        #[unstable(feature = "reverse_bits", issue = "48763")]
+        #[cfg(not(stage0))]
+        #[inline]
+        pub fn reverse_bits(self) -> Self {
+            unsafe { intrinsics::bitreverse(self as $ActualT) as Self }
+        }
+
         doc_comment! {
             concat!("Converts an integer from big endian to the target's endianness.
 
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index b8fe28d0f0d..25f57d8c0f7 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -233,11 +233,11 @@ impl<T> Option<T> {
     /// [`usize`]: ../../std/primitive.usize.html
     ///
     /// ```
-    /// let num_as_str: Option<String> = Some("10".to_string());
+    /// let text: Option<String> = Some("Hello, world!".to_string());
     /// // First, cast `Option<String>` to `Option<&String>` with `as_ref`,
-    /// // then consume *that* with `map`, leaving `num_as_str` on the stack.
-    /// let num_as_int: Option<usize> = num_as_str.as_ref().map(|n| n.len());
-    /// println!("still can print num_as_str: {:?}", num_as_str);
+    /// // then consume *that* with `map`, leaving `text` on the stack.
+    /// let text_length: Option<usize> = text.as_ref().map(|s| s.len());
+    /// println!("still can print text: {:?}", text);
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -1051,7 +1051,7 @@ impl<'a, A> DoubleEndedIterator for Iter<'a, A> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, A> ExactSizeIterator for Iter<'a, A> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, A> FusedIterator for Iter<'a, A> {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
@@ -1096,7 +1096,7 @@ impl<'a, A> DoubleEndedIterator for IterMut<'a, A> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, A> ExactSizeIterator for IterMut<'a, A> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, A> FusedIterator for IterMut<'a, A> {}
 #[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {}
@@ -1133,7 +1133,7 @@ impl<A> DoubleEndedIterator for IntoIter<A> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<A> ExactSizeIterator for IntoIter<A> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<A> FusedIterator for IntoIter<A> {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
diff --git a/src/libcore/result.rs b/src/libcore/result.rs
index 3801db94e15..c152d4979b9 100644
--- a/src/libcore/result.rs
+++ b/src/libcore/result.rs
@@ -1038,7 +1038,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for Iter<'a, T> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for Iter<'a, T> {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
@@ -1082,7 +1082,7 @@ impl<'a, T> DoubleEndedIterator for IterMut<'a, T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for IterMut<'a, T> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for IterMut<'a, T> {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
@@ -1125,7 +1125,7 @@ impl<T> DoubleEndedIterator for IntoIter<T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> ExactSizeIterator for IntoIter<T> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<T> FusedIterator for IntoIter<T> {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 64d0d3bb650..19fe4dd36b6 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -1455,7 +1455,7 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for Iter<'a, T> {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
@@ -1583,7 +1583,7 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for IterMut<'a, T> {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
@@ -1731,7 +1731,7 @@ impl<'a, T, P> SplitIter for Split<'a, T, P> where P: FnMut(&T) -> bool {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T, P> FusedIterator for Split<'a, T, P> where P: FnMut(&T) -> bool {}
 
 /// An iterator over the subslices of the vector which are separated
@@ -1829,7 +1829,7 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {}
 
 /// An iterator over subslices separated by elements that match a predicate
@@ -1886,7 +1886,6 @@ impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
     }
 }
 
-//#[unstable(feature = "fused", issue = "35602")]
 #[unstable(feature = "slice_rsplit", issue = "41020")]
 impl<'a, T, P> FusedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {}
 
@@ -1945,7 +1944,6 @@ impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where
     }
 }
 
-//#[unstable(feature = "fused", issue = "35602")]
 #[unstable(feature = "slice_rsplit", issue = "41020")]
 impl<'a, T, P> FusedIterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {}
 
@@ -2082,7 +2080,7 @@ macro_rules! forward_iterator {
             }
         }
 
-        #[unstable(feature = "fused", issue = "35602")]
+        #[stable(feature = "fused", since = "1.26.0")]
         impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P>
             where P: FnMut(&T) -> bool {}
     }
@@ -2188,7 +2186,7 @@ impl<'a, T> DoubleEndedIterator for Windows<'a, T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for Windows<'a, T> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for Windows<'a, T> {}
 
 #[doc(hidden)]
@@ -2307,7 +2305,7 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for Chunks<'a, T> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for Chunks<'a, T> {}
 
 #[doc(hidden)]
@@ -2423,7 +2421,7 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> {
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {}
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T> FusedIterator for ChunksMut<'a, T> {}
 
 #[doc(hidden)]
@@ -2533,7 +2531,7 @@ impl<'a, T> ExactSizeIterator for ExactChunks<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[unstable(feature = "exact_chunks", issue = "47115")]
 impl<'a, T> FusedIterator for ExactChunks<'a, T> {}
 
 #[doc(hidden)]
@@ -2630,7 +2628,7 @@ impl<'a, T> ExactSizeIterator for ExactChunksMut<'a, T> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[unstable(feature = "exact_chunks", issue = "47115")]
 impl<'a, T> FusedIterator for ExactChunksMut<'a, T> {}
 
 #[doc(hidden)]
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 765b369e4b2..e225c9522bc 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -609,7 +609,7 @@ impl<'a> DoubleEndedIterator for Chars<'a> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a> FusedIterator for Chars<'a> {}
 
 impl<'a> Chars<'a> {
@@ -702,7 +702,7 @@ impl<'a> DoubleEndedIterator for CharIndices<'a> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a> FusedIterator for CharIndices<'a> {}
 
 impl<'a> CharIndices<'a> {
@@ -817,7 +817,7 @@ impl<'a> ExactSizeIterator for Bytes<'a> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a> FusedIterator for Bytes<'a> {}
 
 #[unstable(feature = "trusted_len", issue = "37572")]
@@ -977,10 +977,10 @@ macro_rules! generate_pattern_iterators {
             }
         }
 
-        #[unstable(feature = "fused", issue = "35602")]
+        #[stable(feature = "fused", since = "1.26.0")]
         impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {}
 
-        #[unstable(feature = "fused", issue = "35602")]
+        #[stable(feature = "fused", since = "1.26.0")]
         impl<'a, P: Pattern<'a>> FusedIterator for $reverse_iterator<'a, P>
             where P::Searcher: ReverseSearcher<'a> {}
 
@@ -1337,7 +1337,7 @@ impl<'a> DoubleEndedIterator for Lines<'a> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a> FusedIterator for Lines<'a> {}
 
 /// Created with the method [`lines_any`].
@@ -1403,7 +1403,7 @@ impl<'a> DoubleEndedIterator for LinesAny<'a> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 #[allow(deprecated)]
 impl<'a> FusedIterator for LinesAny<'a> {}
 
diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs
index 939afdcb982..971991dce3d 100644
--- a/src/libcore/tests/lib.rs
+++ b/src/libcore/tests/lib.rs
@@ -46,6 +46,7 @@
 #![feature(try_trait)]
 #![feature(exact_chunks)]
 #![feature(atomic_nand)]
+#![feature(reverse_bits)]
 
 extern crate core;
 extern crate test;
diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs
index daa1cc3a7f4..ca6906f7310 100644
--- a/src/libcore/tests/num/uint_macros.rs
+++ b/src/libcore/tests/num/uint_macros.rs
@@ -98,6 +98,17 @@ mod tests {
     }
 
     #[test]
+    fn test_reverse_bits() {
+        assert_eq!(A.reverse_bits().reverse_bits(), A);
+        assert_eq!(B.reverse_bits().reverse_bits(), B);
+        assert_eq!(C.reverse_bits().reverse_bits(), C);
+
+        // Swapping these should make no difference
+        assert_eq!(_0.reverse_bits(), _0);
+        assert_eq!(_1.reverse_bits(), _1);
+    }
+
+    #[test]
     fn test_le() {
         assert_eq!($T::from_le(A.to_le()), A);
         assert_eq!($T::from_le(B.to_le()), B);
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index aa678ba788a..84fdeba4ab3 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -436,6 +436,9 @@ impl DepKind {
 }
 
 define_dep_nodes!( <'tcx>
+    // We use this for most things when incr. comp. is turned off.
+    [] Null,
+
     // Represents the `Krate` as a whole (the `hir::Krate` value) (as
     // distinct from the krate module). This is basically a hash of
     // the entire krate, so if you read from `Krate` (e.g., by calling
@@ -553,7 +556,7 @@ define_dep_nodes!( <'tcx>
     [] RvaluePromotableMap(DefId),
     [] ImplParent(DefId),
     [] TraitOfItem(DefId),
-    [] IsExportedSymbol(DefId),
+    [] IsReachableNonGeneric(DefId),
     [] IsMirAvailable(DefId),
     [] ItemAttrs(DefId),
     [] FnArgNames(DefId),
@@ -571,7 +574,7 @@ define_dep_nodes!( <'tcx>
     [] GetPanicStrategy(CrateNum),
     [] IsNoBuiltins(CrateNum),
     [] ImplDefaultness(DefId),
-    [] ExportedSymbolIds(CrateNum),
+    [] ReachableNonGenerics(CrateNum),
     [] NativeLibraries(CrateNum),
     [] PluginRegistrarFn(CrateNum),
     [] DeriveRegistrarFn(CrateNum),
@@ -605,8 +608,8 @@ define_dep_nodes!( <'tcx>
     [input] MissingExternCrateItem(CrateNum),
     [input] UsedCrateSource(CrateNum),
     [input] PostorderCnums,
-    [input] HasCloneClosures(CrateNum),
-    [input] HasCopyClosures(CrateNum),
+    [] HasCloneClosures(CrateNum),
+    [] HasCopyClosures(CrateNum),
 
     // This query is not expected to have inputs -- as a result, it's
     // not a good candidate for "replay" because it's essentially a
@@ -630,8 +633,6 @@ define_dep_nodes!( <'tcx>
     [] CompileCodegenUnit(InternedString),
     [input] OutputFilenames,
     [anon] NormalizeTy,
-    // We use this for most things when incr. comp. is turned off.
-    [] Null,
 
     [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) },
 
@@ -642,6 +643,7 @@ define_dep_nodes!( <'tcx>
 
     [] GetSymbolExportLevel(DefId),
 
+    [input] Features,
 );
 
 trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index fa745bf1655..877027a21a2 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -550,7 +550,7 @@ impl<'a> LoweringContext<'a> {
     {
         assert!(!self.is_collecting_in_band_lifetimes);
         assert!(self.lifetimes_to_define.is_empty());
-        self.is_collecting_in_band_lifetimes = self.sess.features.borrow().in_band_lifetimes;
+        self.is_collecting_in_band_lifetimes = self.sess.features_untracked().in_band_lifetimes;
 
         assert!(self.in_band_ty_params.is_empty());
 
@@ -964,7 +964,7 @@ impl<'a> LoweringContext<'a> {
                 let span = t.span;
                 match itctx {
                     ImplTraitContext::Existential => {
-                        let has_feature = self.sess.features.borrow().conservative_impl_trait;
+                        let has_feature = self.sess.features_untracked().conservative_impl_trait;
                         if !t.span.allows_unstable() && !has_feature {
                             emit_feature_err(&self.sess.parse_sess, "conservative_impl_trait",
                                              t.span, GateIssue::Language,
@@ -988,7 +988,7 @@ impl<'a> LoweringContext<'a> {
                         }, lifetimes)
                     },
                     ImplTraitContext::Universal(def_id) => {
-                        let has_feature = self.sess.features.borrow().universal_impl_trait;
+                        let has_feature = self.sess.features_untracked().universal_impl_trait;
                         if !t.span.allows_unstable() && !has_feature {
                             emit_feature_err(&self.sess.parse_sess, "universal_impl_trait",
                                              t.span, GateIssue::Language,
@@ -3713,7 +3713,7 @@ impl<'a> LoweringContext<'a> {
     }
 
     fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) {
-        if self.sess.features.borrow().dyn_trait {
+        if self.sess.features_untracked().dyn_trait {
             self.sess.buffer_lint_with_diagnostic(
                 builtin::BARE_TRAIT_OBJECT, id, span,
                 "trait objects without an explicit `dyn` are deprecated",
diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs
index ed8cea3eb65..d91aa3a3851 100644
--- a/src/librustc/hir/print.rs
+++ b/src/librustc/hir/print.rs
@@ -2208,13 +2208,8 @@ impl<'a> State<'a> {
         if self.next_comment().is_none() {
             self.s.hardbreak()?;
         }
-        loop {
-            match self.next_comment() {
-                Some(ref cmnt) => {
-                    self.print_comment(cmnt)?;
-                }
-                _ => break,
-            }
+        while let Some(ref cmnt) = self.next_comment() {
+            self.print_comment(cmnt)?
         }
         Ok(())
     }
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
index c31a5c9d86d..f935cbfcde9 100644
--- a/src/librustc/ich/impls_syntax.rs
+++ b/src/librustc/ich/impls_syntax.rs
@@ -17,6 +17,7 @@ use std::hash as std_hash;
 use std::mem;
 
 use syntax::ast;
+use syntax::feature_gate;
 use syntax::parse::token;
 use syntax::symbol::InternedString;
 use syntax::tokenstream;
@@ -460,3 +461,21 @@ fn stable_non_narrow_char(swc: ::syntax_pos::NonNarrowChar,
 
     (pos.0 - filemap_start.0, width as u32)
 }
+
+
+
+impl<'gcx> HashStable<StableHashingContext<'gcx>> for feature_gate::Features {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'gcx>,
+                                          hasher: &mut StableHasher<W>) {
+        // Unfortunately we cannot exhaustively list fields here, since the
+        // struct is macro generated.
+        self.declared_stable_lang_features.hash_stable(hcx, hasher);
+        self.declared_lib_features.hash_stable(hcx, hasher);
+
+        self.walk_feature_fields(|feature_name, value| {
+            feature_name.hash_stable(hcx, hasher);
+            value.hash_stable(hcx, hasher);
+        });
+    }
+}
diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs
index 700d06acf11..559b2720076 100644
--- a/src/librustc/infer/error_reporting/mod.rs
+++ b/src/librustc/infer/error_reporting/mod.rs
@@ -56,7 +56,7 @@
 //! time of error detection.
 
 use infer;
-use super::{InferCtxt, TypeTrace, SubregionOrigin, RegionVariableOrigin, ValuePairs};
+use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs};
 use super::region_constraints::GenericKind;
 use super::lexical_region_resolve::RegionResolutionError;
 
@@ -81,54 +81,22 @@ mod need_type_info;
 pub mod nice_region_error;
 
 impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
-    pub fn note_and_explain_region(self,
-                                   region_scope_tree: &region::ScopeTree,
-                                   err: &mut DiagnosticBuilder,
-                                   prefix: &str,
-                                   region: ty::Region<'tcx>,
-                                   suffix: &str) {
-        fn item_scope_tag(item: &hir::Item) -> &'static str {
-            match item.node {
-                hir::ItemImpl(..) => "impl",
-                hir::ItemStruct(..) => "struct",
-                hir::ItemUnion(..) => "union",
-                hir::ItemEnum(..) => "enum",
-                hir::ItemTrait(..) => "trait",
-                hir::ItemFn(..) => "function body",
-                _ => "item"
-            }
-        }
-
-        fn trait_item_scope_tag(item: &hir::TraitItem) -> &'static str {
-            match item.node {
-                hir::TraitItemKind::Method(..) => "method body",
-                hir::TraitItemKind::Const(..) |
-                hir::TraitItemKind::Type(..) => "associated item"
-            }
-        }
-
-        fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str {
-            match item.node {
-                hir::ImplItemKind::Method(..) => "method body",
-                hir::ImplItemKind::Const(..) |
-                hir::ImplItemKind::Type(_) => "associated item"
-            }
-        }
-
-        fn explain_span<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                        heading: &str, span: Span)
-                                        -> (String, Option<Span>) {
-            let lo = tcx.sess.codemap().lookup_char_pos_adj(span.lo());
-            (format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1),
-             Some(span))
-        }
-
+    pub fn note_and_explain_region(
+        self,
+        region_scope_tree: &region::ScopeTree,
+        err: &mut DiagnosticBuilder,
+        prefix: &str,
+        region: ty::Region<'tcx>,
+        suffix: &str,
+    ) {
         let (description, span) = match *region {
             ty::ReScope(scope) => {
                 let new_string;
                 let unknown_scope = || {
-                    format!("{}unknown scope: {:?}{}.  Please report a bug.",
-                            prefix, scope, suffix)
+                    format!(
+                        "{}unknown scope: {:?}{}.  Please report a bug.",
+                        prefix, scope, suffix
+                    )
                 };
                 let span = scope.span(self, region_scope_tree);
                 let tag = match self.hir.find(scope.node_id(self, region_scope_tree)) {
@@ -137,15 +105,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                         hir::ExprCall(..) => "call",
                         hir::ExprMethodCall(..) => "method call",
                         hir::ExprMatch(.., hir::MatchSource::IfLetDesugar { .. }) => "if let",
-                        hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) =>  "while let",
-                        hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) =>  "for",
+                        hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) => "while let",
+                        hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) => "for",
                         hir::ExprMatch(..) => "match",
                         _ => "expression",
                     },
                     Some(hir_map::NodeStmt(_)) => "statement",
-                    Some(hir_map::NodeItem(it)) => item_scope_tag(&it),
-                    Some(hir_map::NodeTraitItem(it)) => trait_item_scope_tag(&it),
-                    Some(hir_map::NodeImplItem(it)) => impl_item_scope_tag(&it),
+                    Some(hir_map::NodeItem(it)) => Self::item_scope_tag(&it),
+                    Some(hir_map::NodeTraitItem(it)) => Self::trait_item_scope_tag(&it),
+                    Some(hir_map::NodeImplItem(it)) => Self::impl_item_scope_tag(&it),
                     Some(_) | None => {
                         err.span_note(span, &unknown_scope());
                         return;
@@ -153,74 +121,24 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                 };
                 let scope_decorated_tag = match scope.data() {
                     region::ScopeData::Node(_) => tag,
-                    region::ScopeData::CallSite(_) => {
-                        "scope of call-site for function"
-                    }
-                    region::ScopeData::Arguments(_) => {
-                        "scope of function body"
-                    }
+                    region::ScopeData::CallSite(_) => "scope of call-site for function",
+                    region::ScopeData::Arguments(_) => "scope of function body",
                     region::ScopeData::Destruction(_) => {
                         new_string = format!("destruction scope surrounding {}", tag);
                         &new_string[..]
                     }
                     region::ScopeData::Remainder(r) => {
-                        new_string = format!("block suffix following statement {}",
-                                             r.first_statement_index.index());
+                        new_string = format!(
+                            "block suffix following statement {}",
+                            r.first_statement_index.index()
+                        );
                         &new_string[..]
                     }
                 };
-                explain_span(self, scope_decorated_tag, span)
+                self.explain_span(scope_decorated_tag, span)
             }
 
-            ty::ReEarlyBound(_) |
-            ty::ReFree(_) => {
-                let scope = region.free_region_binding_scope(self);
-                let node = self.hir.as_local_node_id(scope)
-                                   .unwrap_or(DUMMY_NODE_ID);
-                let unknown;
-                let tag = match self.hir.find(node) {
-                    Some(hir_map::NodeBlock(_)) |
-                    Some(hir_map::NodeExpr(_)) => "body",
-                    Some(hir_map::NodeItem(it)) => item_scope_tag(&it),
-                    Some(hir_map::NodeTraitItem(it)) => trait_item_scope_tag(&it),
-                    Some(hir_map::NodeImplItem(it)) => impl_item_scope_tag(&it),
-
-                    // this really should not happen, but it does:
-                    // FIXME(#27942)
-                    Some(_) => {
-                        unknown = format!("unexpected node ({}) for scope {:?}.  \
-                                           Please report a bug.",
-                                          self.hir.node_to_string(node), scope);
-                        &unknown
-                    }
-                    None => {
-                        unknown = format!("unknown node for scope {:?}.  \
-                                           Please report a bug.", scope);
-                        &unknown
-                    }
-                };
-                let (prefix, span) = match *region {
-                    ty::ReEarlyBound(ref br) => {
-                        (format!("the lifetime {} as defined on", br.name),
-                         self.sess.codemap().def_span(self.hir.span(node)))
-                    }
-                    ty::ReFree(ref fr) => {
-                        match fr.bound_region {
-                            ty::BrAnon(idx) => {
-                                (format!("the anonymous lifetime #{} defined on", idx + 1),
-                                 self.hir.span(node))
-                            }
-                            ty::BrFresh(_) => ("an anonymous lifetime defined on".to_owned(),
-                                               self.hir.span(node)),
-                            _ => (format!("the lifetime {} as defined on", fr.bound_region),
-                                  self.sess.codemap().def_span(self.hir.span(node))),
-                        }
-                    }
-                    _ => bug!()
-                };
-                let (msg, opt_span) = explain_span(self, tag, span);
-                (format!("{} {}", prefix, msg), opt_span)
-            }
+            ty::ReEarlyBound(_) | ty::ReFree(_) => self.msg_span_from_free_region(region),
 
             ty::ReStatic => ("the static lifetime".to_owned(), None),
 
@@ -231,59 +149,168 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             //
             // We shouldn't really be having unification failures with ReVar
             // and ReLateBound though.
-            ty::ReSkolemized(..) |
-            ty::ReVar(_) |
-            ty::ReLateBound(..) |
-            ty::ReErased => {
+            ty::ReSkolemized(..) | ty::ReVar(_) | ty::ReLateBound(..) | ty::ReErased => {
                 (format!("lifetime {:?}", region), None)
             }
 
             // We shouldn't encounter an error message with ReClosureBound.
             ty::ReClosureBound(..) => {
-                bug!(
-                    "encountered unexpected ReClosureBound: {:?}",
-                    region,
+                bug!("encountered unexpected ReClosureBound: {:?}", region,);
+            }
+        };
+
+        TyCtxt::emit_msg_span(err, prefix, description, span, suffix);
+    }
+
+    pub fn note_and_explain_free_region(
+        self,
+        err: &mut DiagnosticBuilder,
+        prefix: &str,
+        region: ty::Region<'tcx>,
+        suffix: &str,
+    ) {
+        let (description, span) = self.msg_span_from_free_region(region);
+
+        TyCtxt::emit_msg_span(err, prefix, description, span, suffix);
+    }
+
+    fn msg_span_from_free_region(self, region: ty::Region<'tcx>) -> (String, Option<Span>) {
+        let scope = region.free_region_binding_scope(self);
+        let node = self.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID);
+        let unknown;
+        let tag = match self.hir.find(node) {
+            Some(hir_map::NodeBlock(_)) | Some(hir_map::NodeExpr(_)) => "body",
+            Some(hir_map::NodeItem(it)) => Self::item_scope_tag(&it),
+            Some(hir_map::NodeTraitItem(it)) => Self::trait_item_scope_tag(&it),
+            Some(hir_map::NodeImplItem(it)) => Self::impl_item_scope_tag(&it),
+
+            // this really should not happen, but it does:
+            // FIXME(#27942)
+            Some(_) => {
+                unknown = format!(
+                    "unexpected node ({}) for scope {:?}.  \
+                     Please report a bug.",
+                    self.hir.node_to_string(node),
+                    scope
+                );
+                &unknown
+            }
+            None => {
+                unknown = format!(
+                    "unknown node for scope {:?}.  \
+                     Please report a bug.",
+                    scope
                 );
+                &unknown
             }
         };
+        let (prefix, span) = match *region {
+            ty::ReEarlyBound(ref br) => (
+                format!("the lifetime {} as defined on", br.name),
+                self.sess.codemap().def_span(self.hir.span(node)),
+            ),
+            ty::ReFree(ref fr) => match fr.bound_region {
+                ty::BrAnon(idx) => (
+                    format!("the anonymous lifetime #{} defined on", idx + 1),
+                    self.hir.span(node),
+                ),
+                ty::BrFresh(_) => (
+                    "an anonymous lifetime defined on".to_owned(),
+                    self.hir.span(node),
+                ),
+                _ => (
+                    format!("the lifetime {} as defined on", fr.bound_region),
+                    self.sess.codemap().def_span(self.hir.span(node)),
+                ),
+            },
+            _ => bug!(),
+        };
+        let (msg, opt_span) = self.explain_span(tag, span);
+        (format!("{} {}", prefix, msg), opt_span)
+    }
+
+    fn emit_msg_span(
+        err: &mut DiagnosticBuilder,
+        prefix: &str,
+        description: String,
+        span: Option<Span>,
+        suffix: &str,
+    ) {
         let message = format!("{}{}{}", prefix, description, suffix);
+
         if let Some(span) = span {
             err.span_note(span, &message);
         } else {
             err.note(&message);
         }
     }
+
+    fn item_scope_tag(item: &hir::Item) -> &'static str {
+        match item.node {
+            hir::ItemImpl(..) => "impl",
+            hir::ItemStruct(..) => "struct",
+            hir::ItemUnion(..) => "union",
+            hir::ItemEnum(..) => "enum",
+            hir::ItemTrait(..) => "trait",
+            hir::ItemFn(..) => "function body",
+            _ => "item",
+        }
+    }
+
+    fn trait_item_scope_tag(item: &hir::TraitItem) -> &'static str {
+        match item.node {
+            hir::TraitItemKind::Method(..) => "method body",
+            hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => "associated item",
+        }
+    }
+
+    fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str {
+        match item.node {
+            hir::ImplItemKind::Method(..) => "method body",
+            hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) => "associated item",
+        }
+    }
+
+    fn explain_span(self, heading: &str, span: Span) -> (String, Option<Span>) {
+        let lo = self.sess.codemap().lookup_char_pos_adj(span.lo());
+        (
+            format!("the {} at {}:{}", heading, lo.line, lo.col.to_usize() + 1),
+            Some(span),
+        )
+    }
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-    pub fn report_region_errors(&self,
-                                region_scope_tree: &region::ScopeTree,
-                                errors: &Vec<RegionResolutionError<'tcx>>,
-                                will_later_be_reported_by_nll: bool) {
+    pub fn report_region_errors(
+        &self,
+        region_scope_tree: &region::ScopeTree,
+        errors: &Vec<RegionResolutionError<'tcx>>,
+        will_later_be_reported_by_nll: bool,
+    ) {
         debug!("report_region_errors(): {} errors to start", errors.len());
 
-        if will_later_be_reported_by_nll && self.tcx.sess.nll() {
+        if will_later_be_reported_by_nll && self.tcx.nll() {
             // With `#![feature(nll)]`, we want to present a nice user
             // experience, so don't even mention the errors from the
             // AST checker.
-            if self.tcx.sess.features.borrow().nll {
+            if self.tcx.features().nll {
                 return;
             }
 
             // But with -Znll, it's nice to have some note for later.
             for error in errors {
                 match *error {
-                    RegionResolutionError::ConcreteFailure(ref origin, ..) |
-                    RegionResolutionError::GenericBoundFailure(ref origin, ..) => {
-                        self.tcx.sess.span_warn(
-                            origin.span(),
-                            "not reporting region error due to -Znll");
+                    RegionResolutionError::ConcreteFailure(ref origin, ..)
+                    | RegionResolutionError::GenericBoundFailure(ref origin, ..) => {
+                        self.tcx
+                            .sess
+                            .span_warn(origin.span(), "not reporting region error due to -Znll");
                     }
 
                     RegionResolutionError::SubSupConflict(ref rvo, ..) => {
-                        self.tcx.sess.span_warn(
-                            rvo.span(),
-                            "not reporting region error due to -Znll");
+                        self.tcx
+                            .sess
+                            .span_warn(rvo.span(), "not reporting region error due to -Znll");
                     }
                 }
             }
@@ -295,7 +322,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         // together into a `ProcessedErrors` group:
         let errors = self.process_errors(errors);
 
-        debug!("report_region_errors: {} errors after preprocessing", errors.len());
+        debug!(
+            "report_region_errors: {} errors after preprocessing",
+            errors.len()
+        );
 
         for error in errors {
             debug!("report_region_errors: error = {:?}", error);
@@ -310,7 +340,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     // the error. If all of these fails, we fall back to a rather
                     // general bit of code that displays the error information
                     RegionResolutionError::ConcreteFailure(origin, sub, sup) => {
-                        self.report_concrete_failure(region_scope_tree, origin, sub, sup).emit();
+                        self.report_concrete_failure(region_scope_tree, origin, sub, sup)
+                            .emit();
                     }
 
                     RegionResolutionError::GenericBoundFailure(origin, param_ty, sub) => {
@@ -323,17 +354,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                         );
                     }
 
-                    RegionResolutionError::SubSupConflict(var_origin,
-                                                          sub_origin,
-                                                          sub_r,
-                                                          sup_origin,
-                                                          sup_r) => {
-                        self.report_sub_sup_conflict(region_scope_tree,
-                                                     var_origin,
-                                                     sub_origin,
-                                                     sub_r,
-                                                     sup_origin,
-                                                     sup_r);
+                    RegionResolutionError::SubSupConflict(
+                        var_origin,
+                        sub_origin,
+                        sub_r,
+                        sup_origin,
+                        sup_r,
+                    ) => {
+                        self.report_sub_sup_conflict(
+                            region_scope_tree,
+                            var_origin,
+                            sub_origin,
+                            sub_r,
+                            sup_origin,
+                            sup_r,
+                        );
                     }
                 }
             }
@@ -350,8 +385,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     // The method also attempts to weed out messages that seem like
     // duplicates that will be unhelpful to the end-user. But
     // obviously it never weeds out ALL errors.
-    fn process_errors(&self, errors: &Vec<RegionResolutionError<'tcx>>)
-                      -> Vec<RegionResolutionError<'tcx>> {
+    fn process_errors(
+        &self,
+        errors: &Vec<RegionResolutionError<'tcx>>,
+    ) -> Vec<RegionResolutionError<'tcx>> {
         debug!("process_errors()");
 
         // We want to avoid reporting generic-bound failures if we can
@@ -368,15 +405,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         let is_bound_failure = |e: &RegionResolutionError<'tcx>| match *e {
             RegionResolutionError::GenericBoundFailure(..) => true,
-            RegionResolutionError::ConcreteFailure(..) |
-            RegionResolutionError::SubSupConflict(..) => false,
+            RegionResolutionError::ConcreteFailure(..)
+            | RegionResolutionError::SubSupConflict(..) => false,
         };
 
-
         let mut errors = if errors.iter().all(|e| is_bound_failure(e)) {
             errors.clone()
         } else {
-            errors.iter().filter(|&e| !is_bound_failure(e)).cloned().collect()
+            errors
+                .iter()
+                .filter(|&e| !is_bound_failure(e))
+                .cloned()
+                .collect()
         };
 
         // sort the errors by span, for better error message stability.
@@ -389,10 +429,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     /// Adds a note if the types come from similarly named crates
-    fn check_and_note_conflicting_crates(&self,
-                                         err: &mut DiagnosticBuilder,
-                                         terr: &TypeError<'tcx>,
-                                         sp: Span) {
+    fn check_and_note_conflicting_crates(
+        &self,
+        err: &mut DiagnosticBuilder,
+        terr: &TypeError<'tcx>,
+        sp: Span,
+    ) {
         let report_path_match = |err: &mut DiagnosticBuilder, did1: DefId, did2: DefId| {
             // Only external crates, if either is from a local
             // module we could have false positives
@@ -403,12 +445,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 let found_abs_path = self.tcx.absolute_item_path_str(did2);
                 // We compare strings because DefPath can be different
                 // for imported and non-imported crates
-                if exp_path == found_path
-                || exp_abs_path == found_abs_path {
+                if exp_path == found_path || exp_abs_path == found_abs_path {
                     let crate_name = self.tcx.crate_name(did1.krate);
-                    err.span_note(sp, &format!("Perhaps two different versions \
-                                                of crate `{}` are being used?",
-                                               crate_name));
+                    err.span_note(
+                        sp,
+                        &format!(
+                            "Perhaps two different versions \
+                             of crate `{}` are being used?",
+                            crate_name
+                        ),
+                    );
                 }
             }
         };
@@ -419,24 +465,21 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                 match (&exp_found.expected.sty, &exp_found.found.sty) {
                     (&ty::TyAdt(exp_adt, _), &ty::TyAdt(found_adt, _)) => {
                         report_path_match(err, exp_adt.did, found_adt.did);
-                    },
-                    _ => ()
+                    }
+                    _ => (),
                 }
-            },
+            }
             TypeError::Traits(ref exp_found) => {
                 report_path_match(err, exp_found.expected, exp_found.found);
-            },
-            _ => () // FIXME(#22750) handle traits and stuff
+            }
+            _ => (), // FIXME(#22750) handle traits and stuff
         }
     }
 
-    fn note_error_origin(&self,
-                         err: &mut DiagnosticBuilder<'tcx>,
-                         cause: &ObligationCause<'tcx>)
-    {
+    fn note_error_origin(&self, err: &mut DiagnosticBuilder<'tcx>, cause: &ObligationCause<'tcx>) {
         match cause.code {
             ObligationCauseCode::MatchExpressionArm { arm_span, source } => match source {
-                hir::MatchSource::IfLetDesugar {..} => {
+                hir::MatchSource::IfLetDesugar { .. } => {
                     let msg = "`if let` arm with an incompatible type";
                     if self.tcx.sess.codemap().is_multiline(arm_span) {
                         err.span_note(arm_span, msg);
@@ -453,7 +496,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     }
                 }
             },
-            _ => ()
+            _ => (),
         }
     }
 
@@ -470,13 +513,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// Bar<Qux>
     /// -------- this type is the same as a type argument in the other type, not highlighted
     /// ```
-    fn highlight_outer(&self,
-                       value: &mut DiagnosticStyledString,
-                       other_value: &mut DiagnosticStyledString,
-                       name: String,
-                       sub: &ty::subst::Substs<'tcx>,
-                       pos: usize,
-                       other_ty: &Ty<'tcx>) {
+    fn highlight_outer(
+        &self,
+        value: &mut DiagnosticStyledString,
+        other_value: &mut DiagnosticStyledString,
+        name: String,
+        sub: &ty::subst::Substs<'tcx>,
+        pos: usize,
+        other_ty: &Ty<'tcx>,
+    ) {
         // `value` and `other_value` hold two incomplete type representation for display.
         // `name` is the path of both types being compared. `sub`
         value.push_highlighted(name);
@@ -486,14 +531,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
 
         // Output the lifetimes fot the first type
-        let lifetimes = sub.regions().map(|lifetime| {
-            let s = format!("{}", lifetime);
-            if s.is_empty() {
-                "'_".to_string()
-            } else {
-                s
-            }
-        }).collect::<Vec<_>>().join(", ");
+        let lifetimes = sub.regions()
+            .map(|lifetime| {
+                let s = format!("{}", lifetime);
+                if s.is_empty() {
+                    "'_".to_string()
+                } else {
+                    s
+                }
+            })
+            .collect::<Vec<_>>()
+            .join(", ");
         if !lifetimes.is_empty() {
             if sub.regions().count() < len {
                 value.push_normal(lifetimes + &", ");
@@ -543,13 +591,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// Bar<Qux>
     /// -------- this type is the same as a type argument in the other type, not highlighted
     /// ```
-    fn cmp_type_arg(&self,
-                    mut t1_out: &mut DiagnosticStyledString,
-                    mut t2_out: &mut DiagnosticStyledString,
-                    path: String,
-                    sub: &ty::subst::Substs<'tcx>,
-                    other_path: String,
-                    other_ty: &Ty<'tcx>) -> Option<()> {
+    fn cmp_type_arg(
+        &self,
+        mut t1_out: &mut DiagnosticStyledString,
+        mut t2_out: &mut DiagnosticStyledString,
+        path: String,
+        sub: &ty::subst::Substs<'tcx>,
+        other_path: String,
+        other_ty: &Ty<'tcx>,
+    ) -> Option<()> {
         for (i, ta) in sub.types().enumerate() {
             if &ta == other_ty {
                 self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty);
@@ -567,11 +617,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     }
 
     /// Add a `,` to the type representation only if it is appropriate.
-    fn push_comma(&self,
-                  value: &mut DiagnosticStyledString,
-                  other_value: &mut DiagnosticStyledString,
-                  len: usize,
-                  pos: usize) {
+    fn push_comma(
+        &self,
+        value: &mut DiagnosticStyledString,
+        other_value: &mut DiagnosticStyledString,
+        len: usize,
+        pos: usize,
+    ) {
         if len > 0 && pos != len - 1 {
             value.push_normal(", ");
             other_value.push_normal(", ");
@@ -580,39 +632,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
     /// Compare two given types, eliding parts that are the same between them and highlighting
     /// relevant differences, and return two representation of those types for highlighted printing.
-    fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>)
-        -> (DiagnosticStyledString, DiagnosticStyledString)
-    {
+    fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) {
         fn equals<'tcx>(a: &Ty<'tcx>, b: &Ty<'tcx>) -> bool {
             match (&a.sty, &b.sty) {
                 (a, b) if *a == *b => true,
-                (&ty::TyInt(_), &ty::TyInfer(ty::InferTy::IntVar(_))) |
-                (&ty::TyInfer(ty::InferTy::IntVar(_)), &ty::TyInt(_)) |
-                (&ty::TyInfer(ty::InferTy::IntVar(_)), &ty::TyInfer(ty::InferTy::IntVar(_))) |
-                (&ty::TyFloat(_), &ty::TyInfer(ty::InferTy::FloatVar(_))) |
-                (&ty::TyInfer(ty::InferTy::FloatVar(_)), &ty::TyFloat(_)) |
-                (&ty::TyInfer(ty::InferTy::FloatVar(_)),
-                 &ty::TyInfer(ty::InferTy::FloatVar(_))) => true,
+                (&ty::TyInt(_), &ty::TyInfer(ty::InferTy::IntVar(_)))
+                | (&ty::TyInfer(ty::InferTy::IntVar(_)), &ty::TyInt(_))
+                | (&ty::TyInfer(ty::InferTy::IntVar(_)), &ty::TyInfer(ty::InferTy::IntVar(_)))
+                | (&ty::TyFloat(_), &ty::TyInfer(ty::InferTy::FloatVar(_)))
+                | (&ty::TyInfer(ty::InferTy::FloatVar(_)), &ty::TyFloat(_))
+                | (
+                    &ty::TyInfer(ty::InferTy::FloatVar(_)),
+                    &ty::TyInfer(ty::InferTy::FloatVar(_)),
+                ) => true,
                 _ => false,
             }
         }
 
-        fn push_ty_ref<'tcx>(r: &ty::Region<'tcx>,
-                             tnm: &ty::TypeAndMut<'tcx>,
-                             s: &mut DiagnosticStyledString) {
+        fn push_ty_ref<'tcx>(
+            r: &ty::Region<'tcx>,
+            tnm: &ty::TypeAndMut<'tcx>,
+            s: &mut DiagnosticStyledString,
+        ) {
             let r = &format!("{}", r);
-            s.push_highlighted(format!("&{}{}{}",
-                                       r,
-                                       if r == "" {
-                                           ""
-                                       } else {
-                                           " "
-                                       },
-                                       if tnm.mutbl == hir::MutMutable {
-                                          "mut "
-                                       } else {
-                                           ""
-                                       }));
+            s.push_highlighted(format!(
+                "&{}{}{}",
+                r,
+                if r == "" { "" } else { " " },
+                if tnm.mutbl == hir::MutMutable {
+                    "mut "
+                } else {
+                    ""
+                }
+            ));
             s.push_normal(format!("{}", tnm.ty));
         }
 
@@ -705,12 +757,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     //     Foo<Bar<Qux>
                     //         ------- this type argument is exactly the same as the other type
                     //     Bar<Qux>
-                    if self.cmp_type_arg(&mut values.0,
-                                         &mut values.1,
-                                         path1.clone(),
-                                         sub1,
-                                         path2.clone(),
-                                         &t2).is_some() {
+                    if self.cmp_type_arg(
+                        &mut values.0,
+                        &mut values.1,
+                        path1.clone(),
+                        sub1,
+                        path2.clone(),
+                        &t2,
+                    ).is_some()
+                    {
                         return values;
                     }
                     // Check for case:
@@ -718,19 +773,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     //     Bar<Qux>
                     //     Foo<Bar<Qux>>
                     //         ------- this type argument is exactly the same as the other type
-                    if self.cmp_type_arg(&mut values.1,
-                                         &mut values.0,
-                                         path2,
-                                         sub2,
-                                         path1,
-                                         &t1).is_some() {
+                    if self.cmp_type_arg(&mut values.1, &mut values.0, path2, sub2, path1, &t1)
+                        .is_some()
+                    {
                         return values;
                     }
 
                     // We couldn't find anything in common, highlight everything.
                     //     let x: Bar<Qux> = y::<Foo<Zar>>();
-                    (DiagnosticStyledString::highlighted(format!("{}", t1)),
-                     DiagnosticStyledString::highlighted(format!("{}", t2)))
+                    (
+                        DiagnosticStyledString::highlighted(format!("{}", t1)),
+                        DiagnosticStyledString::highlighted(format!("{}", t2)),
+                    )
                 }
             }
 
@@ -759,28 +813,36 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             _ => {
                 if t1 == t2 {
                     // The two types are the same, elide and don't highlight.
-                    (DiagnosticStyledString::normal("_"), DiagnosticStyledString::normal("_"))
+                    (
+                        DiagnosticStyledString::normal("_"),
+                        DiagnosticStyledString::normal("_"),
+                    )
                 } else {
                     // We couldn't find anything in common, highlight everything.
-                    (DiagnosticStyledString::highlighted(format!("{}", t1)),
-                     DiagnosticStyledString::highlighted(format!("{}", t2)))
+                    (
+                        DiagnosticStyledString::highlighted(format!("{}", t1)),
+                        DiagnosticStyledString::highlighted(format!("{}", t2)),
+                    )
                 }
             }
         }
     }
 
-    pub fn note_type_err(&self,
-                         diag: &mut DiagnosticBuilder<'tcx>,
-                         cause: &ObligationCause<'tcx>,
-                         secondary_span: Option<(Span, String)>,
-                         mut values: Option<ValuePairs<'tcx>>,
-                         terr: &TypeError<'tcx>)
-    {
+    pub fn note_type_err(
+        &self,
+        diag: &mut DiagnosticBuilder<'tcx>,
+        cause: &ObligationCause<'tcx>,
+        secondary_span: Option<(Span, String)>,
+        mut values: Option<ValuePairs<'tcx>>,
+        terr: &TypeError<'tcx>,
+    ) {
         // For some types of errors, expected-found does not make
         // sense, so just ignore the values we were given.
         match terr {
-            TypeError::CyclicTy(_) => { values = None; }
-            _ => { }
+            TypeError::CyclicTy(_) => {
+                values = None;
+            }
+            _ => {}
         }
 
         let (expected_found, exp_found, is_simple_error) = match values {
@@ -788,8 +850,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             Some(values) => {
                 let (is_simple_error, exp_found) = match values {
                     ValuePairs::Types(exp_found) => {
-                        let is_simple_err = exp_found.expected.is_primitive()
-                            && exp_found.found.is_primitive();
+                        let is_simple_err =
+                            exp_found.expected.is_primitive() && exp_found.found.is_primitive();
 
                         (is_simple_err, Some(exp_found))
                     }
@@ -800,7 +862,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                     None => {
                         // Derived error. Cancel the emitter.
                         self.tcx.sess.diagnostic().cancel(diag);
-                        return
+                        return;
                     }
                 };
                 (vals, exp_found, is_simple_error)
@@ -818,9 +880,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             match (terr, is_simple_error, expected == found) {
                 (&TypeError::Sorts(ref values), false, true) => {
                     diag.note_expected_found_extra(
-                        &"type", expected, found,
+                        &"type",
+                        expected,
+                        found,
                         &format!(" ({})", values.expected.sort_string(self.tcx)),
-                        &format!(" ({})", values.found.sort_string(self.tcx)));
+                        &format!(" ({})", values.found.sort_string(self.tcx)),
+                    );
                 }
                 (_, false, _) => {
                     if let Some(exp_found) = exp_found {
@@ -828,12 +893,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             TypeVariants::TyFnDef(def, _) => {
                                 (Some(def), Some(self.tcx.fn_sig(def).output()))
                             }
-                            _ => (None, None)
+                            _ => (None, None),
                         };
 
                         let exp_is_struct = match exp_found.expected.sty {
                             TypeVariants::TyAdt(def, _) => def.is_struct(),
-                            _ => false
+                            _ => false,
                         };
 
                         if let (Some(def_id), Some(ret_ty)) = (def_id, ret_ty) {
@@ -861,14 +926,15 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         self.note_error_origin(diag, &cause);
     }
 
-    pub fn report_and_explain_type_error(&self,
-                                         trace: TypeTrace<'tcx>,
-                                         terr: &TypeError<'tcx>)
-                                         -> DiagnosticBuilder<'tcx>
-    {
-        debug!("report_and_explain_type_error(trace={:?}, terr={:?})",
-               trace,
-               terr);
+    pub fn report_and_explain_type_error(
+        &self,
+        trace: TypeTrace<'tcx>,
+        terr: &TypeError<'tcx>,
+    ) -> DiagnosticBuilder<'tcx> {
+        debug!(
+            "report_and_explain_type_error(trace={:?}, terr={:?})",
+            trace, terr
+        );
 
         let span = trace.cause.span(&self.tcx);
         let failure_code = trace.cause.as_failure_code(terr);
@@ -890,9 +956,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         diag
     }
 
-    fn values_str(&self, values: &ValuePairs<'tcx>)
-        -> Option<(DiagnosticStyledString, DiagnosticStyledString)>
-    {
+    fn values_str(
+        &self,
+        values: &ValuePairs<'tcx>,
+    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
         match *values {
             infer::Types(ref exp_found) => self.expected_found_str_ty(exp_found),
             infer::TraitRefs(ref exp_found) => self.expected_found_str(exp_found),
@@ -900,9 +967,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
     }
 
-    fn expected_found_str_ty(&self,
-                             exp_found: &ty::error::ExpectedFound<Ty<'tcx>>)
-                             -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
+    fn expected_found_str_ty(
+        &self,
+        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
+    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
         let exp_found = self.resolve_type_vars_if_possible(exp_found);
         if exp_found.references_error() {
             return None;
@@ -914,25 +982,27 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
     /// Returns a string of the form "expected `{}`, found `{}`".
     fn expected_found_str<T: fmt::Display + TypeFoldable<'tcx>>(
         &self,
-        exp_found: &ty::error::ExpectedFound<T>)
-        -> Option<(DiagnosticStyledString, DiagnosticStyledString)>
-    {
+        exp_found: &ty::error::ExpectedFound<T>,
+    ) -> Option<(DiagnosticStyledString, DiagnosticStyledString)> {
         let exp_found = self.resolve_type_vars_if_possible(exp_found);
         if exp_found.references_error() {
             return None;
         }
 
-        Some((DiagnosticStyledString::highlighted(format!("{}", exp_found.expected)),
-              DiagnosticStyledString::highlighted(format!("{}", exp_found.found))))
+        Some((
+            DiagnosticStyledString::highlighted(format!("{}", exp_found.expected)),
+            DiagnosticStyledString::highlighted(format!("{}", exp_found.found)),
+        ))
     }
 
-    pub fn report_generic_bound_failure(&self,
-                                        region_scope_tree: &region::ScopeTree,
-                                        span: Span,
-                                        origin: Option<SubregionOrigin<'tcx>>,
-                                        bound_kind: GenericKind<'tcx>,
-                                        sub: Region<'tcx>)
-    {
+    pub fn report_generic_bound_failure(
+        &self,
+        region_scope_tree: &region::ScopeTree,
+        span: Span,
+        origin: Option<SubregionOrigin<'tcx>>,
+        bound_kind: GenericKind<'tcx>,
+        sub: Region<'tcx>,
+    ) {
         // Attempt to obtain the span of the parameter so we can
         // suggest adding an explicit lifetime bound to it.
         let type_param_span = match (self.in_progress_tables, bound_kind) {
@@ -958,8 +1028,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             // `sp` only covers `T`, change it so that it covers
                             // `T:` when appropriate
                             let sp = if has_lifetimes {
-                                sp.to(self.tcx.sess.codemap().next_point(
-                                        self.tcx.sess.codemap().next_point(sp)))
+                                sp.to(self.tcx
+                                    .sess
+                                    .codemap()
+                                    .next_point(self.tcx.sess.codemap().next_point(sp)))
                             } else {
                                 sp
                             };
@@ -974,37 +1046,39 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         };
 
         let labeled_user_string = match bound_kind {
-            GenericKind::Param(ref p) =>
-                format!("the parameter type `{}`", p),
-            GenericKind::Projection(ref p) =>
-                format!("the associated type `{}`", p),
+            GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
+            GenericKind::Projection(ref p) => format!("the associated type `{}`", p),
         };
 
         if let Some(SubregionOrigin::CompareImplMethodObligation {
-            span, item_name, impl_item_def_id, trait_item_def_id,
-        }) = origin {
-            self.report_extra_impl_obligation(span,
-                                              item_name,
-                                              impl_item_def_id,
-                                              trait_item_def_id,
-                                              &format!("`{}: {}`", bound_kind, sub))
-                .emit();
+            span,
+            item_name,
+            impl_item_def_id,
+            trait_item_def_id,
+        }) = origin
+        {
+            self.report_extra_impl_obligation(
+                span,
+                item_name,
+                impl_item_def_id,
+                trait_item_def_id,
+                &format!("`{}: {}`", bound_kind, sub),
+            ).emit();
             return;
         }
 
-        fn binding_suggestion<'tcx, S: fmt::Display>(err: &mut DiagnosticBuilder<'tcx>,
-                                                     type_param_span: Option<(Span, bool)>,
-                                                     bound_kind: GenericKind<'tcx>,
-                                                     sub: S) {
-            let consider = &format!("consider adding an explicit lifetime bound `{}: {}`...",
-                                    bound_kind,
-                                    sub);
+        fn binding_suggestion<'tcx, S: fmt::Display>(
+            err: &mut DiagnosticBuilder<'tcx>,
+            type_param_span: Option<(Span, bool)>,
+            bound_kind: GenericKind<'tcx>,
+            sub: S,
+        ) {
+            let consider = &format!(
+                "consider adding an explicit lifetime bound `{}: {}`...",
+                bound_kind, sub
+            );
             if let Some((sp, has_lifetimes)) = type_param_span {
-                let tail = if has_lifetimes {
-                    " + "
-                } else {
-                    ""
-                };
+                let tail = if has_lifetimes { " + " } else { "" };
                 let suggestion = format!("{}: {}{}", bound_kind, sub, tail);
                 err.span_suggestion_short(sp, consider, suggestion);
             } else {
@@ -1013,44 +1087,56 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         }
 
         let mut err = match *sub {
-            ty::ReEarlyBound(_) |
-            ty::ReFree(ty::FreeRegion {bound_region: ty::BrNamed(..), ..}) => {
+            ty::ReEarlyBound(_)
+            | ty::ReFree(ty::FreeRegion {
+                bound_region: ty::BrNamed(..),
+                ..
+            }) => {
                 // Does the required lifetime have a nice name we can print?
-                let mut err = struct_span_err!(self.tcx.sess,
-                                               span,
-                                               E0309,
-                                               "{} may not live long enough",
-                                               labeled_user_string);
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0309,
+                    "{} may not live long enough",
+                    labeled_user_string
+                );
                 binding_suggestion(&mut err, type_param_span, bound_kind, sub);
                 err
             }
 
             ty::ReStatic => {
                 // Does the required lifetime have a nice name we can print?
-                let mut err = struct_span_err!(self.tcx.sess,
-                                               span,
-                                               E0310,
-                                               "{} may not live long enough",
-                                               labeled_user_string);
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0310,
+                    "{} may not live long enough",
+                    labeled_user_string
+                );
                 binding_suggestion(&mut err, type_param_span, bound_kind, "'static");
                 err
             }
 
             _ => {
                 // If not, be less specific.
-                let mut err = struct_span_err!(self.tcx.sess,
-                                               span,
-                                               E0311,
-                                               "{} may not live long enough",
-                                               labeled_user_string);
-                err.help(&format!("consider adding an explicit lifetime bound for `{}`",
-                                  bound_kind));
+                let mut err = struct_span_err!(
+                    self.tcx.sess,
+                    span,
+                    E0311,
+                    "{} may not live long enough",
+                    labeled_user_string
+                );
+                err.help(&format!(
+                    "consider adding an explicit lifetime bound for `{}`",
+                    bound_kind
+                ));
                 self.tcx.note_and_explain_region(
                     region_scope_tree,
                     &mut err,
                     &format!("{} must be valid for ", labeled_user_string),
                     sub,
-                    "...");
+                    "...",
+                );
                 err
             }
         };
@@ -1061,26 +1147,31 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
         err.emit();
     }
 
-    fn report_sub_sup_conflict(&self,
-                               region_scope_tree: &region::ScopeTree,
-                               var_origin: RegionVariableOrigin,
-                               sub_origin: SubregionOrigin<'tcx>,
-                               sub_region: Region<'tcx>,
-                               sup_origin: SubregionOrigin<'tcx>,
-                               sup_region: Region<'tcx>) {
-
+    fn report_sub_sup_conflict(
+        &self,
+        region_scope_tree: &region::ScopeTree,
+        var_origin: RegionVariableOrigin,
+        sub_origin: SubregionOrigin<'tcx>,
+        sub_region: Region<'tcx>,
+        sup_origin: SubregionOrigin<'tcx>,
+        sup_region: Region<'tcx>,
+    ) {
         let mut err = self.report_inference_failure(var_origin);
 
-        self.tcx.note_and_explain_region(region_scope_tree, &mut err,
+        self.tcx.note_and_explain_region(
+            region_scope_tree,
+            &mut err,
             "first, the lifetime cannot outlive ",
             sup_region,
-            "...");
+            "...",
+        );
 
         match (&sup_origin, &sub_origin) {
             (&infer::Subtype(ref sup_trace), &infer::Subtype(ref sub_trace)) => {
-                if let (Some((sup_expected, sup_found)),
-                        Some((sub_expected, sub_found))) = (self.values_str(&sup_trace.values),
-                                                            self.values_str(&sub_trace.values)) {
+                if let (Some((sup_expected, sup_found)), Some((sub_expected, sub_found))) = (
+                    self.values_str(&sup_trace.values),
+                    self.values_str(&sub_trace.values),
+                ) {
                     if sub_expected == sup_expected && sub_found == sup_found {
                         self.tcx.note_and_explain_region(
                             region_scope_tree,
@@ -1089,10 +1180,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
                             sub_region,
                             "...",
                         );
-                        err.note(&format!("...so that the {}:\nexpected {}\n   found {}",
-                                          sup_trace.cause.as_requirement_str(),
-                                          sup_expected.content(),
-                                          sup_found.content()));
+                        err.note(&format!(
+                            "...so that the {}:\nexpected {}\n   found {}",
+                            sup_trace.cause.as_requirement_str(),
+                            sup_expected.content(),
+                            sup_found.content()
+                        ));
                         err.emit();
                         return;
                     }
@@ -1103,10 +1196,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 
         self.note_region_origin(&mut err, &sup_origin);
 
-        self.tcx.note_and_explain_region(region_scope_tree, &mut err,
+        self.tcx.note_and_explain_region(
+            region_scope_tree,
+            &mut err,
             "but, the lifetime must be valid for ",
             sub_region,
-            "...");
+            "...",
+        );
 
         self.note_region_origin(&mut err, &sub_origin);
         err.emit();
@@ -1114,9 +1210,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
 }
 
 impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
-    fn report_inference_failure(&self,
-                                var_origin: RegionVariableOrigin)
-                                -> DiagnosticBuilder<'tcx> {
+    fn report_inference_failure(
+        &self,
+        var_origin: RegionVariableOrigin,
+    ) -> DiagnosticBuilder<'tcx> {
         let br_string = |br: ty::BoundRegion| {
             let mut s = br.to_string();
             if !s.is_empty() {
@@ -1131,23 +1228,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             infer::Autoref(_) => " for autoref".to_string(),
             infer::Coercion(_) => " for automatic coercion".to_string(),
             infer::LateBoundRegion(_, br, infer::FnCall) => {
-                format!(" for lifetime parameter {}in function call",
-                        br_string(br))
+                format!(" for lifetime parameter {}in function call", br_string(br))
             }
             infer::LateBoundRegion(_, br, infer::HigherRankedType) => {
                 format!(" for lifetime parameter {}in generic type", br_string(br))
             }
-            infer::LateBoundRegion(_, br, infer::AssocTypeProjection(def_id)) => {
-                format!(" for lifetime parameter {}in trait containing associated type `{}`",
-                        br_string(br), self.tcx.associated_item(def_id).name)
-            }
-            infer::EarlyBoundRegion(_, name) => {
-                format!(" for lifetime parameter `{}`",
-                        name)
-            }
+            infer::LateBoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!(
+                " for lifetime parameter {}in trait containing associated type `{}`",
+                br_string(br),
+                self.tcx.associated_item(def_id).name
+            ),
+            infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name),
             infer::BoundRegionInCoherence(name) => {
-                format!(" for lifetime parameter `{}` in coherence check",
-                        name)
+                format!(" for lifetime parameter `{}` in coherence check", name)
             }
             infer::UpvarRegion(ref upvar_id, _) => {
                 let var_node_id = self.tcx.hir.hir_to_node_id(upvar_id.var_id);
@@ -1157,10 +1250,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
             infer::NLL(..) => bug!("NLL variable found in lexical phase"),
         };
 
-        struct_span_err!(self.tcx.sess, var_origin.span(), E0495,
-                  "cannot infer an appropriate lifetime{} \
-                   due to conflicting requirements",
-                  var_description)
+        struct_span_err!(
+            self.tcx.sess,
+            var_origin.span(),
+            E0495,
+            "cannot infer an appropriate lifetime{} \
+             due to conflicting requirements",
+            var_description
+        )
     }
 }
 
@@ -1178,7 +1275,7 @@ impl<'tcx> ObligationCause<'tcx> {
         match self.code {
             CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"),
             MatchExpressionArm { source, .. } => Error0308(match source {
-                hir::MatchSource::IfLetDesugar{..} => "`if let` arms have incompatible types",
+                hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have incompatible types",
                 _ => "match arms have incompatible types",
             }),
             IfExpression => Error0308("if and else have incompatible types"),
@@ -1193,11 +1290,11 @@ impl<'tcx> ObligationCause<'tcx> {
             // say, also take a look at the error code, maybe we can
             // tailor to that.
             _ => match terr {
-                TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() =>
-                    Error0644("closure/generator type that references itself"),
-                _ =>
-                    Error0308("mismatched types"),
-            }
+                TypeError::CyclicTy(ty) if ty.is_closure() || ty.is_generator() => {
+                    Error0644("closure/generator type that references itself")
+                }
+                _ => Error0308("mismatched types"),
+            },
         }
     }
 
@@ -1207,7 +1304,7 @@ impl<'tcx> ObligationCause<'tcx> {
             CompareImplMethodObligation { .. } => "method type is compatible with trait",
             ExprAssignable => "expression is assignable",
             MatchExpressionArm { source, .. } => match source {
-                hir::MatchSource::IfLetDesugar{..} => "`if let` arms have compatible types",
+                hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have compatible types",
                 _ => "match arms have compatible types",
             },
             IfExpression => "if and else have compatible types",
diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs
index bdb5ad525a7..5dbe2ef516c 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -32,7 +32,6 @@ use ich;
 use ty::{self, TyCtxt};
 use session::{Session, CrateDisambiguator};
 use session::search_paths::PathKind;
-use util::nodemap::NodeSet;
 
 use std::any::Any;
 use std::collections::BTreeMap;
@@ -258,8 +257,7 @@ pub trait CrateStore {
     // utility functions
     fn encode_metadata<'a, 'tcx>(&self,
                                  tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 link_meta: &LinkMeta,
-                                 reachable: &NodeSet)
+                                 link_meta: &LinkMeta)
                                  -> EncodedMetadata;
     fn metadata_encoding_version(&self) -> &[u8];
 }
@@ -342,8 +340,7 @@ impl CrateStore for DummyCrateStore {
     fn extern_mod_stmt_cnum_untracked(&self, emod_id: ast::NodeId) -> Option<CrateNum> { None }
     fn encode_metadata<'a, 'tcx>(&self,
                                  tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 link_meta: &LinkMeta,
-                                 reachable: &NodeSet)
+                                 link_meta: &LinkMeta)
                                  -> EncodedMetadata {
         bug!("encode_metadata")
     }
diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs
index d650dbe88b5..b1418792490 100644
--- a/src/librustc/middle/exported_symbols.rs
+++ b/src/librustc/middle/exported_symbols.rs
@@ -8,12 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use hir::def_id::{DefId, LOCAL_CRATE};
+use std::cmp;
+use ty;
+
 /// The SymbolExportLevel of a symbols specifies from which kinds of crates
 /// the symbol will be exported. `C` symbols will be exported from any
 /// kind of crate, including cdylibs which export very few things.
 /// `Rust` will only be exported if the crate produced is a Rust
 /// dylib.
-#[derive(Eq, PartialEq, Debug, Copy, Clone)]
+#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
 pub enum SymbolExportLevel {
     C,
     Rust,
@@ -34,3 +38,58 @@ impl SymbolExportLevel {
         }
     }
 }
+
+#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable)]
+pub enum ExportedSymbol {
+    NonGeneric(DefId),
+    NoDefId(ty::SymbolName),
+}
+
+impl ExportedSymbol {
+    pub fn symbol_name(&self, tcx: ty::TyCtxt) -> ty::SymbolName {
+        match *self {
+            ExportedSymbol::NonGeneric(def_id) => {
+                tcx.symbol_name(ty::Instance::mono(tcx, def_id))
+            }
+            ExportedSymbol::NoDefId(symbol_name) => {
+                symbol_name
+            }
+        }
+    }
+
+    pub fn compare_stable(&self, tcx: ty::TyCtxt, other: &ExportedSymbol) -> cmp::Ordering {
+        match *self {
+            ExportedSymbol::NonGeneric(self_def_id) => {
+                match *other {
+                    ExportedSymbol::NonGeneric(other_def_id) => {
+                        tcx.def_path_hash(self_def_id).cmp(&tcx.def_path_hash(other_def_id))
+                    }
+                    ExportedSymbol::NoDefId(_) => {
+                        cmp::Ordering::Less
+                    }
+                }
+            }
+            ExportedSymbol::NoDefId(self_symbol_name) => {
+                match *other {
+                    ExportedSymbol::NonGeneric(_) => {
+                        cmp::Ordering::Greater
+                    }
+                    ExportedSymbol::NoDefId(ref other_symbol_name) => {
+                        self_symbol_name.cmp(other_symbol_name)
+                    }
+                }
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum self::ExportedSymbol {
+    NonGeneric(def_id),
+    NoDefId(symbol_name)
+});
+
+pub fn metadata_symbol_name(tcx: ty::TyCtxt) -> String {
+    format!("rust_metadata_{}_{}",
+            tcx.original_crate_name(LOCAL_CRATE),
+            tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex())
+}
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 749685182a8..5658b5b6832 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -206,11 +206,7 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
     // Step 2: Mark all symbols that the symbols on the worklist touch.
     fn propagate(&mut self) {
         let mut scanned = FxHashSet();
-        loop {
-            let search_item = match self.worklist.pop() {
-                Some(item) => item,
-                None => break,
-            };
+        while let Some(search_item) = self.worklist.pop() {
             if !scanned.insert(search_item) {
                 continue
             }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index e80ea16f565..16c33d6bd83 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -131,7 +131,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> {
                    item_sp: Span, kind: AnnotationKind, visit_children: F)
         where F: FnOnce(&mut Self)
     {
-        if self.tcx.sess.features.borrow().staged_api {
+        if self.tcx.features().staged_api {
             // This crate explicitly wants staged API.
             debug!("annotate(id = {:?}, attrs = {:?})", id, attrs);
             if let Some(..) = attr::find_deprecation(self.tcx.sess.diagnostic(), attrs, item_sp) {
@@ -398,7 +398,7 @@ impl<'a, 'tcx> Index<'tcx> {
     pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Index<'tcx> {
         let is_staged_api =
             tcx.sess.opts.debugging_opts.force_unstable_if_unmarked ||
-            tcx.sess.features.borrow().staged_api;
+            tcx.features().staged_api;
         let mut staged_api = FxHashMap();
         staged_api.insert(LOCAL_CRATE, is_staged_api);
         let mut index = Index {
@@ -408,7 +408,7 @@ impl<'a, 'tcx> Index<'tcx> {
             active_features: FxHashSet(),
         };
 
-        let ref active_lib_features = tcx.sess.features.borrow().declared_lib_features;
+        let ref active_lib_features = tcx.features().declared_lib_features;
 
         // Put the active features into a map for quick lookup
         index.active_features = active_lib_features.iter().map(|&(ref s, _)| s.clone()).collect();
@@ -677,7 +677,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
 
             // There's no good place to insert stability check for non-Copy unions,
             // so semi-randomly perform it here in stability.rs
-            hir::ItemUnion(..) if !self.tcx.sess.features.borrow().untagged_unions => {
+            hir::ItemUnion(..) if !self.tcx.features().untagged_unions => {
                 let def_id = self.tcx.hir.local_def_id(item.id);
                 let adt_def = self.tcx.adt_def(def_id);
                 let ty = self.tcx.type_of(def_id);
@@ -721,8 +721,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
 /// were expected to be library features), and the list of features used from
 /// libraries, identify activated features that don't exist and error about them.
 pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
-    let sess = &tcx.sess;
-
     let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE);
 
     if tcx.stability().staged_api[&LOCAL_CRATE] {
@@ -736,12 +734,12 @@ pub fn check_unused_or_stable_features<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         krate.visit_all_item_likes(&mut missing.as_deep_visitor());
     }
 
-    let ref declared_lib_features = sess.features.borrow().declared_lib_features;
+    let ref declared_lib_features = tcx.features().declared_lib_features;
     let mut remaining_lib_features: FxHashMap<Symbol, Span>
         = declared_lib_features.clone().into_iter().collect();
     remaining_lib_features.remove(&Symbol::intern("proc_macro"));
 
-    for &(ref stable_lang_feature, span) in &sess.features.borrow().declared_stable_lang_features {
+    for &(ref stable_lang_feature, span) in &tcx.features().declared_stable_lang_features {
         let version = find_lang_feature_accepted_version(&stable_lang_feature.as_str())
             .expect("unexpectedly couldn't find version feature was stabilized");
         tcx.lint_node(lint::builtin::STABLE_FEATURES,
diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs
index bd87a8f918a..5e9eeb97300 100644
--- a/src/librustc/session/mod.rs
+++ b/src/librustc/session/mod.rs
@@ -20,7 +20,7 @@ use lint::builtin::BuiltinLintDiagnostics;
 use middle::allocator::AllocatorKind;
 use middle::dependency_format;
 use session::search_paths::PathKind;
-use session::config::{BorrowckMode, DebugInfoLevel, OutputType, Epoch};
+use session::config::{DebugInfoLevel, OutputType, Epoch};
 use ty::tls;
 use util::nodemap::{FxHashMap, FxHashSet};
 use util::common::{duration_to_secs_str, ErrorReported};
@@ -93,7 +93,8 @@ pub struct Session {
     /// multiple crates with the same name to coexist. See the
     /// trans::back::symbol_names module for more information.
     pub crate_disambiguator: RefCell<Option<CrateDisambiguator>>,
-    pub features: RefCell<feature_gate::Features>,
+
+    features: RefCell<Option<feature_gate::Features>>,
 
     /// The maximum recursion limit for potentially infinitely recursive
     /// operations such as auto-dereference and monomorphization.
@@ -194,6 +195,7 @@ impl Session {
             None => bug!("accessing disambiguator before initialization"),
         }
     }
+
     pub fn struct_span_warn<'a, S: Into<MultiSpan>>(&'a self,
                                                     sp: S,
                                                     msg: &str)
@@ -456,16 +458,22 @@ impl Session {
         self.opts.debugging_opts.print_llvm_passes
     }
 
-    /// If true, we should use NLL-style region checking instead of
-    /// lexical style.
-    pub fn nll(&self) -> bool {
-        self.features.borrow().nll || self.opts.debugging_opts.nll
+    /// Get the features enabled for the current compilation session.
+    /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents
+    /// dependency tracking. Use tcx.features() instead.
+    #[inline]
+    pub fn features_untracked(&self) -> cell::Ref<feature_gate::Features> {
+        let features = self.features.borrow();
+
+        if features.is_none() {
+            bug!("Access to Session::features before it is initialized");
+        }
+
+        cell::Ref::map(features, |r| r.as_ref().unwrap())
     }
 
-    /// If true, we should use the MIR-based borrowck (we may *also* use
-    /// the AST-based borrowck).
-    pub fn use_mir(&self) -> bool {
-        self.borrowck_mode().use_mir()
+    pub fn init_features(&self, features: feature_gate::Features) {
+        *(self.features.borrow_mut()) = Some(features);
     }
 
     /// If true, we should gather causal information during NLL
@@ -475,42 +483,6 @@ impl Session {
         self.opts.debugging_opts.nll_dump_cause
     }
 
-    /// If true, we should enable two-phase borrows checks. This is
-    /// done with either `-Ztwo-phase-borrows` or with
-    /// `#![feature(nll)]`.
-    pub fn two_phase_borrows(&self) -> bool {
-        self.features.borrow().nll || self.opts.debugging_opts.two_phase_borrows
-    }
-
-    /// What mode(s) of borrowck should we run? AST? MIR? both?
-    /// (Also considers the `#![feature(nll)]` setting.)
-    pub fn borrowck_mode(&self) -> BorrowckMode {
-        match self.opts.borrowck_mode {
-            mode @ BorrowckMode::Mir |
-            mode @ BorrowckMode::Compare => mode,
-
-            mode @ BorrowckMode::Ast => {
-                if self.nll() {
-                    BorrowckMode::Mir
-                } else {
-                    mode
-                }
-            }
-
-        }
-    }
-
-    /// Should we emit EndRegion MIR statements? These are consumed by
-    /// MIR borrowck, but not when NLL is used. They are also consumed
-    /// by the validation stuff.
-    pub fn emit_end_regions(&self) -> bool {
-        // FIXME(#46875) -- we should not emit end regions when NLL is enabled,
-        // but for now we can't stop doing so because it causes false positives
-        self.opts.debugging_opts.emit_end_regions ||
-            self.opts.debugging_opts.mir_emit_validate > 0 ||
-            self.use_mir()
-    }
-
     /// Calculates the flavor of LTO to use for this compilation.
     pub fn lto(&self) -> config::Lto {
         // If our target has codegen requirements ignore the command line
@@ -1029,7 +1001,7 @@ pub fn build_session_(sopts: config::Options,
         crate_types: RefCell::new(Vec::new()),
         dependency_formats: RefCell::new(FxHashMap()),
         crate_disambiguator: RefCell::new(None),
-        features: RefCell::new(feature_gate::Features::new()),
+        features: RefCell::new(None),
         recursion_limit: Cell::new(64),
         type_length_limit: Cell::new(1048576),
         next_node_id: Cell::new(NodeId::new(1)),
diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs
index 43940d7cea3..d11565618a6 100644
--- a/src/librustc/traits/specialize/mod.rs
+++ b/src/librustc/traits/specialize/mod.rs
@@ -164,7 +164,7 @@ pub(super) fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     // The feature gate should prevent introducing new specializations, but not
     // taking advantage of upstream ones.
-    if !tcx.sess.features.borrow().specialization &&
+    if !tcx.features().specialization &&
         (impl1_def_id.is_local() || impl2_def_id.is_local()) {
         return false;
     }
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index d04c4771017..47a3580e867 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -14,7 +14,7 @@ use dep_graph::DepGraph;
 use dep_graph::{DepNode, DepConstructor};
 use errors::DiagnosticBuilder;
 use session::Session;
-use session::config::OutputFilenames;
+use session::config::{BorrowckMode, OutputFilenames};
 use middle;
 use hir::{TraitCandidate, HirId, ItemLocalId};
 use hir::def::{Def, Export};
@@ -46,7 +46,7 @@ use ty::layout::{LayoutDetails, TargetDataLayout};
 use ty::maps;
 use ty::steal::Steal;
 use ty::BindingMode;
-use util::nodemap::{NodeMap, NodeSet, DefIdSet, ItemLocalMap};
+use util::nodemap::{NodeMap, DefIdSet, ItemLocalMap};
 use util::nodemap::{FxHashMap, FxHashSet};
 use rustc_data_structures::accumulate_vec::AccumulateVec;
 use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
@@ -71,6 +71,7 @@ use syntax::abi;
 use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
 use syntax::codemap::MultiSpan;
+use syntax::feature_gate;
 use syntax::symbol::{Symbol, keywords};
 use syntax_pos::Span;
 
@@ -1255,6 +1256,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.all_crate_nums(LOCAL_CRATE)
     }
 
+    pub fn features(self) -> Lrc<feature_gate::Features> {
+        self.features_query(LOCAL_CRATE)
+    }
+
     pub fn def_key(self, id: DefId) -> hir_map::DefKey {
         if id.is_local() {
             self.hir.def_key(id)
@@ -1362,13 +1367,60 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
         self.on_disk_query_result_cache.serialize(self.global_tcx(), encoder)
     }
 
+    /// If true, we should use NLL-style region checking instead of
+    /// lexical style.
+    pub fn nll(self) -> bool {
+        self.features().nll || self.sess.opts.debugging_opts.nll
+    }
+
+    /// If true, we should use the MIR-based borrowck (we may *also* use
+    /// the AST-based borrowck).
+    pub fn use_mir(self) -> bool {
+        self.borrowck_mode().use_mir()
+    }
+
+    /// If true, we should enable two-phase borrows checks. This is
+    /// done with either `-Ztwo-phase-borrows` or with
+    /// `#![feature(nll)]`.
+    pub fn two_phase_borrows(self) -> bool {
+        self.features().nll || self.sess.opts.debugging_opts.two_phase_borrows
+    }
+
+    /// What mode(s) of borrowck should we run? AST? MIR? both?
+    /// (Also considers the `#![feature(nll)]` setting.)
+    pub fn borrowck_mode(&self) -> BorrowckMode {
+        match self.sess.opts.borrowck_mode {
+            mode @ BorrowckMode::Mir |
+            mode @ BorrowckMode::Compare => mode,
+
+            mode @ BorrowckMode::Ast => {
+                if self.nll() {
+                    BorrowckMode::Mir
+                } else {
+                    mode
+                }
+            }
+
+        }
+    }
+
+    /// Should we emit EndRegion MIR statements? These are consumed by
+    /// MIR borrowck, but not when NLL is used. They are also consumed
+    /// by the validation stuff.
+    pub fn emit_end_regions(self) -> bool {
+        // FIXME(#46875) -- we should not emit end regions when NLL is enabled,
+        // but for now we can't stop doing so because it causes false positives
+        self.sess.opts.debugging_opts.emit_end_regions ||
+            self.sess.opts.debugging_opts.mir_emit_validate > 0 ||
+            self.use_mir()
+    }
 }
 
 impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> {
-    pub fn encode_metadata(self, link_meta: &LinkMeta, reachable: &NodeSet)
+    pub fn encode_metadata(self, link_meta: &LinkMeta)
         -> EncodedMetadata
     {
-        self.cstore.encode_metadata(self, link_meta, reachable)
+        self.cstore.encode_metadata(self, link_meta)
     }
 }
 
@@ -2020,7 +2072,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     }
 
     pub fn mk_diverging_default(self) -> Ty<'tcx> {
-        if self.sess.features.borrow().never_type {
+        if self.features().never_type {
             self.types.never
         } else {
             self.intern_tup(&[], true)
@@ -2395,13 +2447,25 @@ pub fn provide(providers: &mut ty::maps::Providers) {
     };
     providers.has_copy_closures = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
-        tcx.sess.features.borrow().copy_closures
+        tcx.features().copy_closures
     };
     providers.has_clone_closures = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
-        tcx.sess.features.borrow().clone_closures
+        tcx.features().clone_closures
     };
     providers.fully_normalize_monormophic_ty = |tcx, ty| {
         tcx.fully_normalize_associated_types_in(&ty)
     };
+    providers.features_query = |tcx, cnum| {
+        assert_eq!(cnum, LOCAL_CRATE);
+        Lrc::new(tcx.sess.features_untracked().clone())
+    };
+    providers.is_panic_runtime = |tcx, cnum| {
+        assert_eq!(cnum, LOCAL_CRATE);
+        attr::contains_name(tcx.hir.krate_attrs(), "panic_runtime")
+    };
+    providers.is_compiler_builtins = |tcx, cnum| {
+        assert_eq!(cnum, LOCAL_CRATE);
+        attr::contains_name(tcx.hir.krate_attrs(), "compiler_builtins")
+    };
 }
diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs
index eb07876b05f..cfc552bdc85 100644
--- a/src/librustc/ty/maps/config.rs
+++ b/src/librustc/ty/maps/config.rs
@@ -212,9 +212,9 @@ impl<'tcx> QueryDescription<'tcx> for queries::item_attrs<'tcx> {
     }
 }
 
-impl<'tcx> QueryDescription<'tcx> for queries::is_exported_symbol<'tcx> {
+impl<'tcx> QueryDescription<'tcx> for queries::is_reachable_non_generic<'tcx> {
     fn describe(_: TyCtxt, _: DefId) -> String {
-        bug!("is_exported_symbol")
+        bug!("is_reachable_non_generic")
     }
 }
 
@@ -383,7 +383,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::is_sanitizer_runtime<'tcx> {
     }
 }
 
-impl<'tcx> QueryDescription<'tcx> for queries::exported_symbol_ids<'tcx> {
+impl<'tcx> QueryDescription<'tcx> for queries::reachable_non_generics<'tcx> {
     fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
         format!("looking up the exported symbols of a crate")
     }
@@ -593,6 +593,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::fully_normalize_monormophic_ty<'t
     }
 }
 
+impl<'tcx> QueryDescription<'tcx> for queries::features_query<'tcx> {
+    fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+        format!("looking up enabled feature gates")
+    }
+}
+
 impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> {
     #[inline]
     fn cache_on_disk(def_id: Self::Key) -> bool {
diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs
index 6edb1d9be35..2ef97b2673d 100644
--- a/src/librustc/ty/maps/mod.rs
+++ b/src/librustc/ty/maps/mod.rs
@@ -26,7 +26,7 @@ use middle::region;
 use middle::resolve_lifetime::{ResolveLifetimes, Region, ObjectLifetimeDefault};
 use middle::stability::{self, DeprecationEntry};
 use middle::lang_items::{LanguageItems, LangItem};
-use middle::exported_symbols::SymbolExportLevel;
+use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol};
 use mir::mono::{CodegenUnit, Stats};
 use mir;
 use session::{CompileResult, CrateDisambiguator};
@@ -52,6 +52,7 @@ use syntax_pos::{Span, DUMMY_SP};
 use syntax_pos::symbol::InternedString;
 use syntax::attr;
 use syntax::ast;
+use syntax::feature_gate;
 use syntax::symbol::Symbol;
 
 #[macro_use]
@@ -237,7 +238,6 @@ define_maps! { <'tcx>
     [] fn fn_arg_names: FnArgNames(DefId) -> Vec<ast::Name>,
     [] fn impl_parent: ImplParent(DefId) -> Option<DefId>,
     [] fn trait_of_item: TraitOfItem(DefId) -> Option<DefId>,
-    [] fn is_exported_symbol: IsExportedSymbol(DefId) -> bool,
     [] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> ExternBodyNestedBodies,
     [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
     [] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Lrc<ItemLocalSet>,
@@ -289,7 +289,23 @@ define_maps! { <'tcx>
     [] fn lint_levels: lint_levels_node(CrateNum) -> Lrc<lint::LintLevelMap>,
 
     [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness,
-    [] fn exported_symbol_ids: ExportedSymbolIds(CrateNum) -> Lrc<DefIdSet>,
+
+    // The DefIds of all non-generic functions and statics in the given crate
+    // that can be reached from outside the crate.
+    //
+    // We expect this items to be available for being linked to.
+    //
+    // This query can also be called for LOCAL_CRATE. In this case it will
+    // compute which items will be reachable to other crates, taking into account
+    // the kind of crate that is currently compiled. Crates with only a
+    // C interface have fewer reachable things.
+    //
+    // Does not include external symbols that don't have a corresponding DefId,
+    // like the compiler-generated `main` function and so on.
+    [] fn reachable_non_generics: ReachableNonGenerics(CrateNum) -> Lrc<DefIdSet>,
+    [] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool,
+
+
     [] fn native_libraries: NativeLibraries(CrateNum) -> Lrc<Vec<NativeLibrary>>,
     [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option<DefId>,
     [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option<DefId>,
@@ -342,7 +358,7 @@ define_maps! { <'tcx>
     [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc<Vec<CrateNum>>,
 
     [] fn exported_symbols: ExportedSymbols(CrateNum)
-        -> Arc<Vec<(String, Option<DefId>, SymbolExportLevel)>>,
+        -> Arc<Vec<(ExportedSymbol, SymbolExportLevel)>>,
     [] fn collect_and_partition_translation_items:
         collect_and_partition_translation_items_node(CrateNum)
         -> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
@@ -374,12 +390,19 @@ define_maps! { <'tcx>
     // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning.
     [] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>)
         -> usize,
+
+    [] fn features_query: features_node(CrateNum) -> Lrc<feature_gate::Features>,
 }
 
 //////////////////////////////////////////////////////////////////////
 // These functions are little shims used to find the dep-node for a
 // given query when there is not a *direct* mapping:
 
+
+fn features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
+    DepConstructor::Features
+}
+
 fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> {
     DepConstructor::EraseRegionsTy { ty }
 }
diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs
index b654b6bc42a..13f286d6a26 100644
--- a/src/librustc/ty/maps/plumbing.rs
+++ b/src/librustc/ty/maps/plumbing.rs
@@ -851,7 +851,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::RvaluePromotableMap => { force!(rvalue_promotable_map, def_id!()); }
         DepKind::ImplParent => { force!(impl_parent, def_id!()); }
         DepKind::TraitOfItem => { force!(trait_of_item, def_id!()); }
-        DepKind::IsExportedSymbol => { force!(is_exported_symbol, def_id!()); }
+        DepKind::IsReachableNonGeneric => { force!(is_reachable_non_generic, def_id!()); }
         DepKind::IsMirAvailable => { force!(is_mir_available, def_id!()); }
         DepKind::ItemAttrs => { force!(item_attrs, def_id!()); }
         DepKind::FnArgNames => { force!(fn_arg_names, def_id!()); }
@@ -868,7 +868,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::GetPanicStrategy => { force!(panic_strategy, krate!()); }
         DepKind::IsNoBuiltins => { force!(is_no_builtins, krate!()); }
         DepKind::ImplDefaultness => { force!(impl_defaultness, def_id!()); }
-        DepKind::ExportedSymbolIds => { force!(exported_symbol_ids, krate!()); }
+        DepKind::ReachableNonGenerics => { force!(reachable_non_generics, krate!()); }
         DepKind::NativeLibraries => { force!(native_libraries, krate!()); }
         DepKind::PluginRegistrarFn => { force!(plugin_registrar_fn, krate!()); }
         DepKind::DeriveRegistrarFn => { force!(derive_registrar_fn, krate!()); }
@@ -936,6 +936,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::TargetFeaturesEnabled => { force!(target_features_enabled, def_id!()); }
 
         DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); }
+        DepKind::Features => { force!(features_query, LOCAL_CRATE); }
     }
 
     true
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 9ba33a57c20..a7c55880e2e 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2335,7 +2335,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
     /// Returns true if the impls are the same polarity and are implementing
     /// a trait which contains no items
     pub fn impls_are_allowed_to_overlap(self, def_id1: DefId, def_id2: DefId) -> bool {
-        if !self.sess.features.borrow().overlapping_marker_traits {
+        if !self.features().overlapping_marker_traits {
             return false;
         }
         let trait1_is_empty = self.impl_trait_ref(def_id1)
@@ -2806,7 +2806,7 @@ impl<'tcx> DtorckConstraint<'tcx> {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable)]
 pub struct SymbolName {
     // FIXME: we don't rely on interning or equality here - better have
     // this be a `&'tcx str`.
@@ -2817,6 +2817,14 @@ impl_stable_hash_for!(struct self::SymbolName {
     name
 });
 
+impl SymbolName {
+    pub fn new(name: &str) -> SymbolName {
+        SymbolName {
+            name: Symbol::intern(name).as_str()
+        }
+    }
+}
+
 impl Deref for SymbolName {
     type Target = str;
 
@@ -2828,3 +2836,9 @@ impl fmt::Display for SymbolName {
         fmt::Display::fmt(&self.name, fmt)
     }
 }
+
+impl fmt::Debug for SymbolName {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.name, fmt)
+    }
+}
diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs
index 4fe6ee45295..bb198adea4a 100644
--- a/src/librustc_borrowck/borrowck/mod.rs
+++ b/src/librustc_borrowck/borrowck/mod.rs
@@ -276,7 +276,7 @@ impl<'b, 'tcx: 'b> BorrowckErrors for BorrowckCtxt<'b, 'tcx> {
                                 o: Origin)
                                 -> DiagnosticBuilder<'a>
     {
-        if !o.should_emit_errors(self.tcx.sess.borrowck_mode()) {
+        if !o.should_emit_errors(self.tcx.borrowck_mode()) {
             self.tcx.sess.diagnostic().cancel(&mut diag);
         }
         diag
diff --git a/src/librustc_const_eval/_match.rs b/src/librustc_const_eval/_match.rs
index 54e3418d4f0..8e3b99f2dbf 100644
--- a/src/librustc_const_eval/_match.rs
+++ b/src/librustc_const_eval/_match.rs
@@ -201,7 +201,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
     }
 
     fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
-        if self.tcx.sess.features.borrow().never_type {
+        if self.tcx.features().never_type {
             self.tcx.is_ty_uninhabited_from(self.module, ty)
         } else {
             false
@@ -227,7 +227,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
                               substs: &'tcx ty::subst::Substs<'tcx>)
                               -> bool
     {
-        if self.tcx.sess.features.borrow().never_type {
+        if self.tcx.features().never_type {
             self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs)
         } else {
             false
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index ae53ed0e114..6f7143c185c 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -212,7 +212,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
             let pat_ty = self.tables.node_id_to_type(scrut.hir_id);
             let module = self.tcx.hir.get_module_parent(scrut.id);
             if inlined_arms.is_empty() {
-                let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type {
+                let scrutinee_is_uninhabited = if self.tcx.features().never_type {
                     self.tcx.is_ty_uninhabited_from(module, pat_ty)
                 } else {
                     self.conservative_is_uninhabited(pat_ty)
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 8e4ec93c14b..2a571fa8264 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -398,7 +398,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
         }).collect::<Result<Vec<_>, _>>()?))))
       }
       hir::ExprIndex(ref arr, ref idx) => {
-        if !tcx.sess.features.borrow().const_indexing {
+        if !tcx.features().const_indexing {
             signal!(e, IndexOpFeatureGated);
         }
         let arr = cx.eval(arr)?;
diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index 02cae52166a..42a17d33fa6 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -415,13 +415,7 @@ impl<O: ForestObligation> ObligationForest<O> {
             }
         }
 
-        loop {
-            // non-standard `while let` to bypass #6393
-            let i = match error_stack.pop() {
-                Some(i) => i,
-                None => break
-            };
-
+        while let Some(i) = error_stack.pop() {
             let node = &self.nodes[i];
 
             match node.state.get() {
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 15afea19213..571cc46bc64 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -650,7 +650,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session,
 
     let (mut krate, features) = syntax::config::features(krate, &sess.parse_sess, sess.opts.test);
     // these need to be set "early" so that expansion sees `quote` if enabled.
-    *sess.features.borrow_mut() = features;
+    sess.init_features(features);
 
     *sess.crate_types.borrow_mut() = collect_crate_types(sess, &krate.attrs);
 
@@ -699,7 +699,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session,
     let mut registry = registry.unwrap_or(Registry::new(sess, krate.span));
 
     time(time_passes, "plugin registration", || {
-        if sess.features.borrow().rustc_diagnostic_macros {
+        if sess.features_untracked().rustc_diagnostic_macros {
             registry.register_macro("__diagnostic_used",
                                     diagnostics::plugin::expand_diagnostic_used);
             registry.register_macro("__register_diagnostic",
@@ -749,7 +749,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session,
                                      crate_loader,
                                      &resolver_arenas);
     resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives;
-    syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote);
+    syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features_untracked().quote);
 
     krate = time(time_passes, "expansion", || {
         // Windows dlls do not have rpaths, so they don't know how to find their
@@ -780,7 +780,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session,
                                          .filter(|p| env::join_paths(iter::once(p)).is_ok()))
                      .unwrap());
         }
-        let features = sess.features.borrow();
+        let features = sess.features_untracked();
         let cfg = syntax::ext::expand::ExpansionConfig {
             features: Some(&features),
             recursion_limit: sess.recursion_limit.get(),
@@ -819,7 +819,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session,
                                          sess.opts.test,
                                          krate,
                                          sess.diagnostic(),
-                                         &sess.features.borrow())
+                                         &sess.features_untracked())
     });
 
     // If we're actually rustdoc then there's no need to actually compile
@@ -886,7 +886,7 @@ pub fn phase_2_configure_and_expand_inner<'a, F>(sess: &'a Session,
         sess.track_errors(|| {
             syntax::feature_gate::check_crate(&krate,
                                               &sess.parse_sess,
-                                              &sess.features.borrow(),
+                                              &sess.features_untracked(),
                                               &attributes,
                                               sess.opts.unstable_features);
         })
diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs
index 5976b80d90f..17a6176b79e 100644
--- a/src/librustc_incremental/assert_dep_graph.rs
+++ b/src/librustc_incremental/assert_dep_graph.rs
@@ -69,7 +69,7 @@ pub fn assert_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
         // if the `rustc_attrs` feature is not enabled, then the
         // attributes we are interested in cannot be present anyway, so
         // skip the walk.
-        if !tcx.sess.features.borrow().rustc_attrs {
+        if !tcx.features().rustc_attrs {
             return;
         }
 
diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs
index c3e283535ec..e114606a631 100644
--- a/src/librustc_incremental/persist/dirty_clean.rs
+++ b/src/librustc_incremental/persist/dirty_clean.rs
@@ -219,7 +219,7 @@ impl Assertion {
 
 pub fn check_dirty_clean_annotations<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     // can't add `#[rustc_dirty]` etc without opting in to this feature
-    if !tcx.sess.features.borrow().rustc_attrs {
+    if !tcx.features().rustc_attrs {
         return;
     }
 
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 66f34a72edf..62ac898337c 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1356,7 +1356,7 @@ impl UnreachablePub {
             // visibility is token at start of declaration (can be macro
             // variable rather than literal `pub`)
             let pub_span = cx.tcx.sess.codemap().span_until_char(def_span, ' ');
-            let replacement = if cx.tcx.sess.features.borrow().crate_visibility_modifier {
+            let replacement = if cx.tcx.features().crate_visibility_modifier {
                 "crate"
             } else {
                 "pub(crate)"
diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs
index ef9b3d38c63..1c4bd0ff4c2 100644
--- a/src/librustc_lint/types.rs
+++ b/src/librustc_lint/types.rs
@@ -150,11 +150,23 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
 
                                 // Detect literal value out of range [min, max] inclusive
                                 // avoiding use of -min to prevent overflow/panic
-                                if (negative && v > max + 1) ||
-                                   (!negative && v > max) {
-                                    cx.span_lint(OVERFLOWING_LITERALS,
-                                                 e.span,
-                                                 &format!("literal out of range for {:?}", t));
+                                if (negative && v > max + 1) || (!negative && v > max) {
+                                    if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
+                                        report_bin_hex_error(
+                                            cx,
+                                            e,
+                                            ty::TyInt(t),
+                                            repr_str,
+                                            v,
+                                            negative,
+                                        );
+                                        return;
+                                    }
+                                    cx.span_lint(
+                                        OVERFLOWING_LITERALS,
+                                        e.span,
+                                        &format!("literal out of range for {:?}", t),
+                                    );
                                     return;
                                 }
                             }
@@ -182,7 +194,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                                         let mut err = cx.struct_span_lint(
                                                              OVERFLOWING_LITERALS,
                                                              parent_expr.span,
-                                                             "only u8 can be casted into char");
+                                                             "only u8 can be cast into char");
                                         err.span_suggestion(parent_expr.span,
                                                             &"use a char literal instead",
                                                             format!("'\\u{{{:X}}}'", lit_val));
@@ -191,9 +203,22 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                                     }
                                 }
                             }
-                            cx.span_lint(OVERFLOWING_LITERALS,
-                                         e.span,
-                                         &format!("literal out of range for {:?}", t));
+                            if let Some(repr_str) = get_bin_hex_repr(cx, lit) {
+                                report_bin_hex_error(
+                                    cx,
+                                    e,
+                                    ty::TyUint(t),
+                                    repr_str,
+                                    lit_val,
+                                    false,
+                                );
+                                return;
+                            }
+                            cx.span_lint(
+                                OVERFLOWING_LITERALS,
+                                e.span,
+                                &format!("literal out of range for {:?}", t),
+                            );
                         }
                     }
                     ty::TyFloat(t) => {
@@ -338,6 +363,120 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
                 _ => false,
             }
         }
+
+        fn get_bin_hex_repr(cx: &LateContext, lit: &ast::Lit) -> Option<String> {
+            let src = cx.sess().codemap().span_to_snippet(lit.span).ok()?;
+            let firstch = src.chars().next()?;
+
+            if firstch == '0' {
+                match src.chars().nth(1) {
+                    Some('x') | Some('b') => return Some(src),
+                    _ => return None,
+                }
+            }
+
+            None
+        }
+
+        // This function finds the next fitting type and generates a suggestion string.
+        // It searches for fitting types in the following way (`X < Y`):
+        //  - `iX`: if literal fits in `uX` => `uX`, else => `iY`
+        //  - `-iX` => `iY`
+        //  - `uX` => `uY`
+        //
+        // No suggestion for: `isize`, `usize`.
+        fn get_type_suggestion<'a>(
+            t: &ty::TypeVariants,
+            val: u128,
+            negative: bool,
+        ) -> Option<String> {
+            use syntax::ast::IntTy::*;
+            use syntax::ast::UintTy::*;
+            macro_rules! find_fit {
+                ($ty:expr, $val:expr, $negative:expr,
+                 $($type:ident => [$($utypes:expr),*] => [$($itypes:expr),*]),+) => {
+                    {
+                        let _neg = if negative { 1 } else { 0 };
+                        match $ty {
+                            $($type => {
+                                $(if !negative && val <= uint_ty_range($utypes).1 {
+                                    return Some(format!("{:?}", $utypes))
+                                })*
+                                $(if val <= int_ty_range($itypes).1 as u128 + _neg {
+                                    return Some(format!("{:?}", $itypes))
+                                })*
+                                None
+                            },)*
+                            _ => None
+                        }
+                    }
+                }
+            }
+            match t {
+                &ty::TyInt(i) => find_fit!(i, val, negative,
+                              I8 => [U8] => [I16, I32, I64, I128],
+                              I16 => [U16] => [I32, I64, I128],
+                              I32 => [U32] => [I64, I128],
+                              I64 => [U64] => [I128],
+                              I128 => [U128] => []),
+                &ty::TyUint(u) => find_fit!(u, val, negative,
+                              U8 => [U8, U16, U32, U64, U128] => [],
+                              U16 => [U16, U32, U64, U128] => [],
+                              U32 => [U32, U64, U128] => [],
+                              U64 => [U64, U128] => [],
+                              U128 => [U128] => []),
+                _ => None,
+            }
+        }
+
+        fn report_bin_hex_error(
+            cx: &LateContext,
+            expr: &hir::Expr,
+            ty: ty::TypeVariants,
+            repr_str: String,
+            val: u128,
+            negative: bool,
+        ) {
+            let (t, actually) = match ty {
+                ty::TyInt(t) => {
+                    let bits = int_ty_bits(t, cx.sess().target.isize_ty);
+                    let actually = (val << (128 - bits)) as i128 >> (128 - bits);
+                    (format!("{:?}", t), actually.to_string())
+                }
+                ty::TyUint(t) => {
+                    let bits = uint_ty_bits(t, cx.sess().target.usize_ty);
+                    let actually = (val << (128 - bits)) >> (128 - bits);
+                    (format!("{:?}", t), actually.to_string())
+                }
+                _ => bug!(),
+            };
+            let mut err = cx.struct_span_lint(
+                OVERFLOWING_LITERALS,
+                expr.span,
+                &format!("literal out of range for {}", t),
+            );
+            err.note(&format!(
+                "the literal `{}` (decimal `{}`) does not fit into \
+                 an `{}` and will become `{}{}`",
+                repr_str, val, t, actually, t
+            ));
+            if let Some(sugg_ty) =
+                get_type_suggestion(&cx.tables.node_id_to_type(expr.hir_id).sty, val, negative)
+            {
+                if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
+                    let (sans_suffix, _) = repr_str.split_at(pos);
+                    err.span_suggestion(
+                        expr.span,
+                        &format!("consider using `{}` instead", sugg_ty),
+                        format!("{}{}", sans_suffix, sugg_ty),
+                    );
+                } else {
+                    err.help(&format!("consider using `{}` instead", sugg_ty));
+                }
+            }
+
+            err.emit();
+        }
     }
 }
 
diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs
index 439533fae49..6ab3172c4fe 100644
--- a/src/librustc_lint/unused.rs
+++ b/src/librustc_lint/unused.rs
@@ -72,7 +72,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
 
         let mut fn_warned = false;
         let mut op_warned = false;
-        if cx.tcx.sess.features.borrow().fn_must_use {
+        if cx.tcx.features().fn_must_use {
             let maybe_def = match expr.node {
                 hir::ExprCall(ref callee, _) => {
                     match callee.node {
diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs
index 876e7e8dc31..789ecd0f613 100644
--- a/src/librustc_metadata/creader.rs
+++ b/src/librustc_metadata/creader.rs
@@ -225,9 +225,6 @@ impl<'a> CrateLoader<'a> {
             crate_root.def_path_table.decode((&metadata, self.sess))
         });
 
-        let exported_symbols = crate_root.exported_symbols
-                                         .decode((&metadata, self.sess))
-                                         .collect();
         let trait_impls = crate_root
             .impls
             .decode((&metadata, self.sess))
@@ -238,7 +235,6 @@ impl<'a> CrateLoader<'a> {
             name,
             extern_crate: Cell::new(None),
             def_path_table: Lrc::new(def_path_table),
-            exported_symbols,
             trait_impls,
             proc_macros: crate_root.macro_derive_registrar.map(|_| {
                 self.load_derive_macros(&crate_root, dylib.clone().map(|p| p.0), span)
diff --git a/src/librustc_metadata/cstore.rs b/src/librustc_metadata/cstore.rs
index 8b59eec0190..2e95c23b4ae 100644
--- a/src/librustc_metadata/cstore.rs
+++ b/src/librustc_metadata/cstore.rs
@@ -78,8 +78,6 @@ pub struct CrateMetadata {
     /// compilation support.
     pub def_path_table: Lrc<DefPathTable>,
 
-    pub exported_symbols: FxHashSet<DefIndex>,
-
     pub trait_impls: FxHashMap<(u32, DefIndex), schema::LazySeq<DefIndex>>,
 
     pub dep_kind: Cell<DepKind>,
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 7b8194d9eab..0b50f5c4496 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -18,6 +18,7 @@ use rustc::ty::maps::QueryConfig;
 use rustc::middle::cstore::{CrateStore, DepKind,
                             MetadataLoader, LinkMeta,
                             LoadedMacro, EncodedMetadata, NativeLibraryKind};
+use rustc::middle::exported_symbols::ExportedSymbol;
 use rustc::middle::stability::DeprecationEntry;
 use rustc::hir::def;
 use rustc::session::{CrateDisambiguator, Session};
@@ -27,10 +28,11 @@ use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX};
 use rustc::hir::map::{DefKey, DefPath, DefPathHash};
 use rustc::hir::map::blocks::FnLikeNode;
 use rustc::hir::map::definitions::DefPathTable;
-use rustc::util::nodemap::{NodeSet, DefIdMap};
+use rustc::util::nodemap::DefIdMap;
 
 use std::any::Any;
 use rustc_data_structures::sync::Lrc;
+use std::sync::Arc;
 
 use syntax::ast;
 use syntax::attr;
@@ -160,9 +162,6 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     fn_arg_names => { cdata.get_fn_arg_names(def_id.index) }
     impl_parent => { cdata.get_parent_impl(def_id.index) }
     trait_of_item => { cdata.get_trait_of_item(def_id.index) }
-    is_exported_symbol => {
-        cdata.exported_symbols.contains(&def_id.index)
-    }
     item_body_nested_bodies => { cdata.item_body_nested_bodies(def_id.index) }
     const_is_rvalue_promotable_to_static => {
         cdata.const_is_rvalue_promotable_to_static(def_id.index)
@@ -179,7 +178,21 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     extern_crate => { Lrc::new(cdata.extern_crate.get()) }
     is_no_builtins => { cdata.is_no_builtins(tcx.sess) }
     impl_defaultness => { cdata.get_impl_defaultness(def_id.index) }
-    exported_symbol_ids => { Lrc::new(cdata.get_exported_symbols()) }
+    reachable_non_generics => {
+        let reachable_non_generics = tcx
+            .exported_symbols(cdata.cnum)
+            .iter()
+            .filter_map(|&(exported_symbol, _)| {
+                if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
+                    return Some(def_id)
+                } else {
+                    None
+                }
+            })
+            .collect();
+
+        Lrc::new(reachable_non_generics)
+    }
     native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess)) }
     plugin_registrar_fn => {
         cdata.root.plugin_registrar_fn.map(|index| {
@@ -238,6 +251,19 @@ provide! { <'tcx> tcx, def_id, other, cdata,
 
     has_copy_closures => { cdata.has_copy_closures(tcx.sess) }
     has_clone_closures => { cdata.has_clone_closures(tcx.sess) }
+
+    exported_symbols => {
+        let cnum = cdata.cnum;
+        assert!(cnum != LOCAL_CRATE);
+
+        // If this crate is a custom derive crate, then we're not even going to
+        // link those in so we skip those crates.
+        if cdata.root.macro_derive_registrar.is_some() {
+            return Arc::new(Vec::new())
+        }
+
+        Arc::new(cdata.exported_symbols())
+    }
 }
 
 pub fn provide<'tcx>(providers: &mut Providers<'tcx>) {
@@ -520,11 +546,10 @@ impl CrateStore for cstore::CStore {
 
     fn encode_metadata<'a, 'tcx>(&self,
                                  tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 link_meta: &LinkMeta,
-                                 reachable: &NodeSet)
+                                 link_meta: &LinkMeta)
                                  -> EncodedMetadata
     {
-        encoder::encode_metadata(tcx, link_meta, reachable)
+        encoder::encode_metadata(tcx, link_meta)
     }
 
     fn metadata_encoding_version(&self) -> &[u8]
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 0c6a286e227..60a0d4e03b5 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -18,6 +18,7 @@ use rustc::hir::map::{DefKey, DefPath, DefPathData, DefPathHash};
 use rustc::hir;
 use rustc::middle::cstore::{LinkagePreference, ExternConstBody,
                             ExternBodyNestedBodies};
+use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc::hir::def::{self, Def, CtorKind};
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex,
                          CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -27,7 +28,6 @@ use rustc::mir;
 use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::codec::TyDecoder;
-use rustc::util::nodemap::DefIdSet;
 use rustc::mir::Mir;
 
 use std::cell::Ref;
@@ -1006,10 +1006,10 @@ impl<'a, 'tcx> CrateMetadata {
         arg_names.decode(self).collect()
     }
 
-    pub fn get_exported_symbols(&self) -> DefIdSet {
-        self.exported_symbols
-            .iter()
-            .map(|&index| self.local_def_id(index))
+    pub fn exported_symbols(&self) -> Vec<(ExportedSymbol, SymbolExportLevel)> {
+        self.root
+            .exported_symbols
+            .decode(self)
             .collect()
     }
 
diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs
index d3f046c5544..d19ab894591 100644
--- a/src/librustc_metadata/encoder.rs
+++ b/src/librustc_metadata/encoder.rs
@@ -20,14 +20,16 @@ use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId, LOCAL_CRATE
 use rustc::hir::map::definitions::DefPathTable;
 use rustc::ich::Fingerprint;
 use rustc::middle::dependency_format::Linkage;
+use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel,
+                                      metadata_symbol_name};
 use rustc::middle::lang_items;
 use rustc::mir;
 use rustc::traits::specialization_graph;
-use rustc::ty::{self, Ty, TyCtxt, ReprOptions};
+use rustc::ty::{self, Ty, TyCtxt, ReprOptions, SymbolName};
 use rustc::ty::codec::{self as ty_codec, TyEncoder};
 
 use rustc::session::config::{self, CrateTypeProcMacro};
-use rustc::util::nodemap::{FxHashMap, NodeSet};
+use rustc::util::nodemap::FxHashMap;
 
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_serialize::{Encodable, Encoder, SpecializedEncoder, opaque};
@@ -53,7 +55,6 @@ pub struct EncodeContext<'a, 'tcx: 'a> {
     opaque: opaque::Encoder<'a>,
     pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
     link_meta: &'a LinkMeta,
-    exported_symbols: &'a NodeSet,
 
     lazy_state: LazyState,
     type_shorthands: FxHashMap<Ty<'tcx>, usize>,
@@ -395,9 +396,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
 
         // Encode exported symbols info.
         i = self.position();
+        let exported_symbols = self.tcx.exported_symbols(LOCAL_CRATE);
         let exported_symbols = self.tracked(
             IsolatedEncoder::encode_exported_symbols,
-            self.exported_symbols);
+            &exported_symbols);
         let exported_symbols_bytes = self.position() - i;
 
         // Encode and index the items.
@@ -1388,9 +1390,25 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> {
     // middle::reachable module but filters out items that either don't have a
     // symbol associated with them (they weren't translated) or if they're an FFI
     // definition (as that's not defined in this crate).
-    fn encode_exported_symbols(&mut self, exported_symbols: &NodeSet) -> LazySeq<DefIndex> {
-        let tcx = self.tcx;
-        self.lazy_seq(exported_symbols.iter().map(|&id| tcx.hir.local_def_id(id).index))
+    fn encode_exported_symbols(&mut self,
+                               exported_symbols: &[(ExportedSymbol, SymbolExportLevel)])
+                               -> LazySeq<(ExportedSymbol, SymbolExportLevel)> {
+
+        // The metadata symbol name is special. It should not show up in
+        // downstream crates.
+        let metadata_symbol_name = SymbolName::new(&metadata_symbol_name(self.tcx));
+
+        self.lazy_seq(exported_symbols
+            .iter()
+            .filter(|&&(ref exported_symbol, _)| {
+                match *exported_symbol {
+                    ExportedSymbol::NoDefId(symbol_name) => {
+                        symbol_name != metadata_symbol_name
+                    },
+                    _ => true,
+                }
+            })
+            .cloned())
     }
 
     fn encode_dylib_dependency_formats(&mut self, _: ()) -> LazySeq<Option<LinkagePreference>> {
@@ -1663,8 +1681,7 @@ impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'a, 'tcx> {
 // generated regardless of trailing bytes that end up in it.
 
 pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 link_meta: &LinkMeta,
-                                 exported_symbols: &NodeSet)
+                                 link_meta: &LinkMeta)
                                  -> EncodedMetadata
 {
     let mut cursor = Cursor::new(vec![]);
@@ -1678,7 +1695,6 @@ pub fn encode_metadata<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             opaque: opaque::Encoder::new(&mut cursor),
             tcx,
             link_meta,
-            exported_symbols,
             lazy_state: LazyState::NoNode,
             type_shorthands: Default::default(),
             predicate_shorthands: Default::default(),
diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs
index c0ce32cc970..2504f8dc251 100644
--- a/src/librustc_metadata/native_libs.rs
+++ b/src/librustc_metadata/native_libs.rs
@@ -146,7 +146,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
                 None => self.tcx.sess.err(msg),
             }
         }
-        if lib.cfg.is_some() && !self.tcx.sess.features.borrow().link_cfg {
+        if lib.cfg.is_some() && !self.tcx.features().link_cfg {
             feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
                                            "link_cfg",
                                            span.unwrap(),
@@ -154,7 +154,7 @@ impl<'a, 'tcx> Collector<'a, 'tcx> {
                                            "is feature gated");
         }
         if lib.kind == cstore::NativeStaticNobundle &&
-           !self.tcx.sess.features.borrow().static_nobundle {
+           !self.tcx.features().static_nobundle {
             feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
                                            "static_nobundle",
                                            span.unwrap(),
diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs
index c542f65dcec..ce94e4f912f 100644
--- a/src/librustc_metadata/schema.rs
+++ b/src/librustc_metadata/schema.rs
@@ -16,6 +16,7 @@ use rustc::hir::def::{self, CtorKind};
 use rustc::hir::def_id::{DefIndex, DefId, CrateNum};
 use rustc::ich::StableHashingContext;
 use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
+use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel};
 use rustc::middle::lang_items;
 use rustc::mir;
 use rustc::session::CrateDisambiguator;
@@ -202,7 +203,8 @@ pub struct CrateRoot {
     pub codemap: LazySeq<syntax_pos::FileMap>,
     pub def_path_table: Lazy<hir::map::definitions::DefPathTable>,
     pub impls: LazySeq<TraitImpls>,
-    pub exported_symbols: LazySeq<DefIndex>,
+    pub exported_symbols: LazySeq<(ExportedSymbol, SymbolExportLevel)>,
+
     pub index: LazySeq<index::Index>,
 }
 
diff --git a/src/librustc_mir/borrow_check/error_reporting.rs b/src/librustc_mir/borrow_check/error_reporting.rs
index 182c9b75196..b77e7cf2ec8 100644
--- a/src/librustc_mir/borrow_check/error_reporting.rs
+++ b/src/librustc_mir/borrow_check/error_reporting.rs
@@ -16,7 +16,7 @@ use rustc::ty::{self, RegionKind};
 use rustc_data_structures::indexed_vec::Idx;
 use rustc_data_structures::sync::Lrc;
 
-use super::{MirBorrowckCtxt, Context};
+use super::{Context, MirBorrowckCtxt};
 use super::{InitializationRequiringAction, PrefixSet};
 use dataflow::{ActiveBorrows, BorrowData, FlowAtLocation, MovingOutStatements};
 use dataflow::move_paths::MovePathIndex;
@@ -96,7 +96,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                         } else {
                             true
                         }
-                    },
+                    }
                     _ => true,
                 };
 
@@ -106,9 +106,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                         None => "value".to_owned(),
                     };
 
-                    err.note(&format!("move occurs because {} has type `{}`, \
-                                       which does not implement the `Copy` trait",
-                                       note_msg, ty));
+                    err.note(&format!(
+                        "move occurs because {} has type `{}`, \
+                         which does not implement the `Copy` trait",
+                        note_msg, ty
+                    ));
                 }
             }
 
@@ -154,7 +156,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             span,
             &self.describe_place(place).unwrap_or("_".to_owned()),
             self.retrieve_borrow_span(borrow),
-            &self.describe_place(&borrow.borrowed_place).unwrap_or("_".to_owned()),
+            &self.describe_place(&borrow.borrowed_place)
+                .unwrap_or("_".to_owned()),
             Origin::Mir,
         );
 
@@ -175,8 +178,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         use rustc::hir::ExprClosure;
         use rustc::mir::AggregateKind;
 
-        let local = match self.mir[location.block].statements.get(location.statement_index) {
-            Some(&Statement { kind: StatementKind::Assign(Place::Local(local), _), .. }) => local,
+        let local = match self.mir[location.block]
+            .statements
+            .get(location.statement_index)
+        {
+            Some(&Statement {
+                kind: StatementKind::Assign(Place::Local(local), _),
+                ..
+            }) => local,
             _ => return None,
         };
 
@@ -202,8 +211,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                             .with_freevars(node_id, |freevars| {
                                 for (v, place) in freevars.iter().zip(places) {
                                     match *place {
-                                        Operand::Copy(Place::Local(l)) |
-                                        Operand::Move(Place::Local(l)) if local == l =>
+                                        Operand::Copy(Place::Local(l))
+                                        | Operand::Move(Place::Local(l)) if local == l =>
                                         {
                                             debug!(
                                                 "find_closure_span: found captured local {:?}",
@@ -232,7 +241,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         context: Context,
         (place, span): (&Place<'tcx>, Span),
         gen_borrow_kind: BorrowKind,
-        issued_borrow: &BorrowData,
+        issued_borrow: &BorrowData<'tcx>,
         end_issued_loan_span: Option<Span>,
     ) {
         let issued_span = self.retrieve_borrow_span(issued_borrow);
@@ -255,8 +264,8 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             "immutable",
             "mutable",
         ) {
-            (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt) |
-            (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => self.tcx
+            (BorrowKind::Shared, lft, _, BorrowKind::Mut { .. }, _, rgt)
+            | (BorrowKind::Mut { .. }, _, lft, BorrowKind::Shared, rgt, _) => self.tcx
                 .cannot_reborrow_already_borrowed(
                     span,
                     &desc_place,
@@ -355,11 +364,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         context: Context,
         borrow: &BorrowData<'tcx>,
         drop_span: Span,
-        borrows: &ActiveBorrows<'cx, 'gcx, 'tcx>
+        borrows: &ActiveBorrows<'cx, 'gcx, 'tcx>,
     ) {
         let end_span = borrows.opt_region_end_span(&borrow.region);
         let scope_tree = borrows.0.scope_tree();
-        let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All).last().unwrap();
+        let root_place = self.prefixes(&borrow.borrowed_place, PrefixSet::All)
+            .last()
+            .unwrap();
 
         let borrow_span = self.mir.source_info(borrow.location).span;
         let proper_span = match *root_place {
@@ -367,13 +378,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             _ => drop_span,
         };
 
-        if self.access_place_error_reported.contains(&(root_place.clone(), borrow_span)) {
-            debug!("suppressing access_place error when borrow doesn't live long enough for {:?}",
-                   borrow_span);
+        if self.access_place_error_reported
+            .contains(&(root_place.clone(), borrow_span))
+        {
+            debug!(
+                "suppressing access_place error when borrow doesn't live long enough for {:?}",
+                borrow_span
+            );
             return;
         }
 
-        self.access_place_error_reported.insert((root_place.clone(), borrow_span));
+        self.access_place_error_reported
+            .insert((root_place.clone(), borrow_span));
 
         match (borrow.region, &self.describe_place(&borrow.borrowed_place)) {
             (RegionKind::ReScope(_), Some(name)) => {
@@ -385,9 +401,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     drop_span,
                     borrow_span,
                     proper_span,
-                    end_span
+                    end_span,
                 );
-            },
+            }
             (RegionKind::ReScope(_), None) => {
                 self.report_scoped_temporary_value_does_not_live_long_enough(
                     context,
@@ -396,14 +412,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     drop_span,
                     borrow_span,
                     proper_span,
-                    end_span
+                    end_span,
                 );
-            },
-            (RegionKind::ReEarlyBound(_), Some(name)) |
-            (RegionKind::ReFree(_), Some(name)) |
-            (RegionKind::ReStatic, Some(name)) |
-            (RegionKind::ReEmpty, Some(name)) |
-            (RegionKind::ReVar(_), Some(name)) => {
+            }
+            (RegionKind::ReEarlyBound(_), Some(name))
+            | (RegionKind::ReFree(_), Some(name))
+            | (RegionKind::ReStatic, Some(name))
+            | (RegionKind::ReEmpty, Some(name))
+            | (RegionKind::ReVar(_), Some(name)) => {
                 self.report_unscoped_local_value_does_not_live_long_enough(
                     context,
                     name,
@@ -414,12 +430,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     proper_span,
                     end_span,
                 );
-            },
-            (RegionKind::ReEarlyBound(_), None) |
-            (RegionKind::ReFree(_), None) |
-            (RegionKind::ReStatic, None) |
-            (RegionKind::ReEmpty, None) |
-            (RegionKind::ReVar(_), None) => {
+            }
+            (RegionKind::ReEarlyBound(_), None)
+            | (RegionKind::ReFree(_), None)
+            | (RegionKind::ReStatic, None)
+            | (RegionKind::ReEmpty, None)
+            | (RegionKind::ReVar(_), None) => {
                 self.report_unscoped_temporary_value_does_not_live_long_enough(
                     context,
                     &scope_tree,
@@ -429,13 +445,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                     proper_span,
                     end_span,
                 );
-            },
-            (RegionKind::ReLateBound(_, _), _) |
-            (RegionKind::ReSkolemized(_, _), _) |
-            (RegionKind::ReClosureBound(_), _) |
-            (RegionKind::ReErased, _) => {
+            }
+            (RegionKind::ReLateBound(_, _), _)
+            | (RegionKind::ReSkolemized(_, _), _)
+            | (RegionKind::ReClosureBound(_), _)
+            | (RegionKind::ReErased, _) => {
                 span_bug!(drop_span, "region does not make sense in this context");
-            },
+            }
         }
     }
 
@@ -450,11 +466,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         _proper_span: Span,
         end_span: Option<Span>,
     ) {
-        let mut err = self.tcx.path_does_not_live_long_enough(borrow_span,
-                                                              &format!("`{}`", name),
-                                                              Origin::Mir);
+        let mut err = self.tcx.path_does_not_live_long_enough(
+            borrow_span,
+            &format!("`{}`", name),
+            Origin::Mir,
+        );
         err.span_label(borrow_span, "borrowed value does not live long enough");
-        err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
+        err.span_label(
+            drop_span,
+            format!("`{}` dropped here while still borrowed", name),
+        );
         if let Some(end) = end_span {
             err.span_label(end, "borrowed value needs to live until here");
         }
@@ -472,11 +493,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         proper_span: Span,
         end_span: Option<Span>,
     ) {
-        let mut err = self.tcx.path_does_not_live_long_enough(proper_span,
-                                                              "borrowed value",
-                                                              Origin::Mir);
+        let mut err =
+            self.tcx
+                .path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
         err.span_label(proper_span, "temporary value does not live long enough");
-        err.span_label(drop_span, "temporary value dropped here while still borrowed");
+        err.span_label(
+            drop_span,
+            "temporary value dropped here while still borrowed",
+        );
         err.note("consider using a `let` binding to increase its lifetime");
         if let Some(end) = end_span {
             err.span_label(end, "temporary value needs to live until here");
@@ -496,14 +520,31 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         _proper_span: Span,
         _end_span: Option<Span>,
     ) {
-        let mut err = self.tcx.path_does_not_live_long_enough(borrow_span,
-                                                              &format!("`{}`", name),
-                                                              Origin::Mir);
+        debug!(
+            "report_unscoped_local_value_does_not_live_long_enough(\
+             {:?}, {:?}, {:?}, {:?}, {:?}, {:?}\
+             )",
+            context, name, scope_tree, borrow, drop_span, borrow_span
+        );
+
+        let mut err = self.tcx.path_does_not_live_long_enough(
+            borrow_span,
+            &format!("`{}`", name),
+            Origin::Mir,
+        );
         err.span_label(borrow_span, "borrowed value does not live long enough");
         err.span_label(drop_span, "borrowed value only lives until here");
-        self.tcx.note_and_explain_region(scope_tree, &mut err,
-                                         "borrowed value must be valid for ",
-                                         borrow.region, "...");
+
+        if !self.tcx.nll() {
+            self.tcx.note_and_explain_region(
+                scope_tree,
+                &mut err,
+                "borrowed value must be valid for ",
+                borrow.region,
+                "...",
+            );
+        }
+
         self.explain_why_borrow_contains_point(context, borrow, &mut err);
         err.emit();
     }
@@ -516,16 +557,31 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         drop_span: Span,
         _borrow_span: Span,
         proper_span: Span,
-        _end_span: Option<Span>
+        _end_span: Option<Span>,
     ) {
-        let mut err = self.tcx.path_does_not_live_long_enough(proper_span,
-                                                              "borrowed value",
-                                                              Origin::Mir);
+        debug!(
+            "report_unscoped_temporary_value_does_not_live_long_enough(\
+             {:?}, {:?}, {:?}, {:?}, {:?}\
+             )",
+            context, scope_tree, borrow, drop_span, proper_span
+        );
+
+        let mut err =
+            self.tcx
+                .path_does_not_live_long_enough(proper_span, "borrowed value", Origin::Mir);
         err.span_label(proper_span, "temporary value does not live long enough");
         err.span_label(drop_span, "temporary value only lives until here");
-        self.tcx.note_and_explain_region(scope_tree, &mut err,
-                                         "borrowed value must be valid for ",
-                                         borrow.region, "...");
+
+        if !self.tcx.nll() {
+            self.tcx.note_and_explain_region(
+                scope_tree,
+                &mut err,
+                "borrowed value must be valid for ",
+                borrow.region,
+                "...",
+            );
+        }
+
         self.explain_why_borrow_contains_point(context, borrow, &mut err);
         err.emit();
     }
@@ -534,7 +590,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         &mut self,
         context: Context,
         (place, span): (&Place<'tcx>, Span),
-        loan: &BorrowData,
+        loan: &BorrowData<'tcx>,
     ) {
         let mut err = self.tcx.cannot_assign_to_borrowed(
             span,
@@ -706,9 +762,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                 ProjectionElem::Field(_, field_type) => {
                     self.describe_field_from_ty(&field_type, field)
                 }
-                ProjectionElem::Index(..) |
-                ProjectionElem::ConstantIndex { .. } |
-                ProjectionElem::Subslice { .. } => {
+                ProjectionElem::Index(..)
+                | ProjectionElem::ConstantIndex { .. }
+                | ProjectionElem::Subslice { .. } => {
                     format!("{}", self.describe_field(&proj.base, field))
                 }
             },
@@ -765,13 +821,11 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
             Place::Local(local) => {
                 let local = &self.mir.local_decls[*local];
                 Some(local.ty)
-            },
+            }
             Place::Static(ref st) => Some(st.ty),
-            Place::Projection(ref proj) => {
-                match proj.elem {
-                    ProjectionElem::Field(_, ty) => Some(ty),
-                    _ => None,
-                }
+            Place::Projection(ref proj) => match proj.elem {
+                ProjectionElem::Field(_, ty) => Some(ty),
+                _ => None,
             },
         }
     }
diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs
index c6ed971f767..1ff0ffaaa68 100644
--- a/src/librustc_mir/borrow_check/mod.rs
+++ b/src/librustc_mir/borrow_check/mod.rs
@@ -72,7 +72,7 @@ fn mir_borrowck<'a, 'tcx>(
     let input_mir = tcx.mir_validated(def_id);
     debug!("run query mir_borrowck: {}", tcx.item_path_str(def_id));
 
-    if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.sess.use_mir() {
+    if !tcx.has_attr(def_id, "rustc_mir_borrowck") && !tcx.use_mir() {
         return None;
     }
 
@@ -101,7 +101,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
     // contain non-lexical lifetimes. It will have a lifetime tied
     // to the inference context.
     let mut mir: Mir<'tcx> = input_mir.clone();
-    let free_regions = if !tcx.sess.nll() {
+    let free_regions = if !tcx.nll() {
         None
     } else {
         let mir = &mut mir;
@@ -204,7 +204,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
         );
         (Some(Rc::new(regioncx)), opt_closure_req)
     } else {
-        assert!(!tcx.sess.nll());
+        assert!(!tcx.nll());
         (None, None)
     };
     let flow_inits = flow_inits; // remove mut
@@ -719,7 +719,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     /// allowed to be split into separate Reservation and
     /// Activation phases.
     fn allow_two_phase_borrow(&self, kind: BorrowKind) -> bool {
-        self.tcx.sess.two_phase_borrows() &&
+        self.tcx.two_phase_borrows() &&
             (kind.allows_two_phase_borrow() ||
              self.tcx.sess.opts.debugging_opts.two_phase_beyond_autoref)
     }
@@ -1253,7 +1253,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
         span: Span,
         flow_state: &Flows<'cx, 'gcx, 'tcx>,
     ) {
-        if !self.tcx.sess.two_phase_borrows() {
+        if !self.tcx.two_phase_borrows() {
             return;
         }
 
diff --git a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
index b6d8e14b747..19f95aeec70 100644
--- a/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/explain_borrow/mod.rs
@@ -21,7 +21,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
     pub(in borrow_check) fn explain_why_borrow_contains_point(
         &self,
         context: Context,
-        borrow: &BorrowData<'_>,
+        borrow: &BorrowData<'tcx>,
         err: &mut DiagnosticBuilder<'_>,
     ) {
         if let Some(regioncx) = &self.nonlexical_regioncx {
@@ -70,9 +70,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
                         }
                     }
 
-                    _ => {
-                        cause.label_diagnostic(mir, err);
+                    Cause::UniversalRegion(region_vid) => {
+                        if let Some(region) = regioncx.to_error_region(region_vid) {
+                            self.tcx.note_and_explain_free_region(
+                                err,
+                                "borrowed value must be valid for ",
+                                region,
+                                "...",
+                            );
+                        }
                     }
+
+                    _ => {}
                 }
             }
         }
diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
index 33c012dfad8..3ffb4370359 100644
--- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs
@@ -26,7 +26,6 @@ use rustc::ty::{self, RegionVid, Ty, TypeFoldable};
 use rustc::util::common::ErrorReported;
 use rustc_data_structures::bitvec::BitVector;
 use rustc_data_structures::indexed_vec::IndexVec;
-use rustc_errors::DiagnosticBuilder;
 use std::fmt;
 use std::rc::Rc;
 use syntax::ast;
@@ -435,7 +434,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
         self.check_type_tests(infcx, mir, mir_def_id, outlives_requirements.as_mut());
 
-        self.check_universal_regions(infcx, mir, mir_def_id, outlives_requirements.as_mut());
+        self.check_universal_regions(infcx, mir_def_id, outlives_requirements.as_mut());
 
         let outlives_requirements = outlives_requirements.unwrap_or(vec![]);
 
@@ -574,10 +573,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
                 // an error that multiple bounds are required.
                 tcx.sess.span_err(
                     type_test.span,
-                    &format!(
-                        "`{}` does not live long enough",
-                        type_test.generic_kind,
-                    ),
+                    &format!("`{}` does not live long enough", type_test.generic_kind,),
                 );
             }
         }
@@ -589,13 +585,13 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// existentially bound, then we check its inferred value and try
     /// to find a good name from that. Returns `None` if we can't find
     /// one (e.g., this is just some random part of the CFG).
-    fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
+    pub fn to_error_region(&self, r: RegionVid) -> Option<ty::Region<'tcx>> {
         if self.universal_regions.is_universal_region(r) {
             return self.definitions[r].external_name;
         } else {
             let inferred_values = self.inferred_values
-                                      .as_ref()
-                                      .expect("region values not yet inferred");
+                .as_ref()
+                .expect("region values not yet inferred");
             let upper_bound = self.universal_upper_bound(r);
             if inferred_values.contains(r, upper_bound) {
                 self.to_error_region(upper_bound)
@@ -807,9 +803,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ) -> bool {
         debug!(
             "eval_region_test(point={:?}, lower_bound={:?}, test={:?})",
-            point,
-            lower_bound,
-            test
+            point, lower_bound, test
         );
 
         match test {
@@ -841,9 +835,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     ) -> bool {
         debug!(
             "eval_outlives({:?}: {:?} @ {:?})",
-            sup_region,
-            sub_region,
-            point
+            sup_region, sub_region, point
         );
 
         // Roughly speaking, do a DFS of all region elements reachable
@@ -897,7 +889,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn check_universal_regions<'gcx>(
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
-        mir: &Mir<'tcx>,
         mir_def_id: DefId,
         mut propagated_outlives_requirements: Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
     ) {
@@ -913,7 +904,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         for (fr, _) in universal_definitions {
             self.check_universal_region(
                 infcx,
-                mir,
                 mir_def_id,
                 fr,
                 &mut propagated_outlives_requirements,
@@ -932,7 +922,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn check_universal_region<'gcx>(
         &self,
         infcx: &InferCtxt<'_, 'gcx, 'tcx>,
-        mir: &Mir<'tcx>,
         mir_def_id: DefId,
         longer_fr: RegionVid,
         propagated_outlives_requirements: &mut Option<&mut Vec<ClosureOutlivesRequirement<'gcx>>>,
@@ -951,8 +940,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
             debug!(
                 "check_universal_region: fr={:?} does not outlive shorter_fr={:?}",
-                longer_fr,
-                shorter_fr,
+                longer_fr, shorter_fr,
             );
 
             let blame_span = self.blame_span(longer_fr, shorter_fr);
@@ -990,7 +978,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             // Note: in this case, we use the unapproximated regions
             // to report the error. This gives better error messages
             // in some cases.
-            self.report_error(infcx, mir, mir_def_id, longer_fr, shorter_fr, blame_span);
+            self.report_error(infcx, mir_def_id, longer_fr, shorter_fr, blame_span);
         }
     }
 
@@ -1005,7 +993,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     fn report_error(
         &self,
         infcx: &InferCtxt<'_, '_, 'tcx>,
-        mir: &Mir<'tcx>,
         mir_def_id: DefId,
         fr: RegionVid,
         outlived_fr: RegionVid,
@@ -1039,12 +1026,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
             &format!("{} does not outlive {}", fr_string, outlived_fr_string,),
         );
 
-        // Find out why `fr` had to outlive `outlived_fr`...
-        let inferred_values = self.inferred_values.as_ref().unwrap();
-        if let Some(cause) = inferred_values.cause(fr, outlived_fr) {
-            cause.label_diagnostic(mir, &mut diag);
-        }
-
         diag.emit();
     }
 
@@ -1134,10 +1115,7 @@ impl fmt::Debug for Constraint {
         write!(
             formatter,
             "({:?}: {:?} @ {:?}) due to {:?}",
-            self.sup,
-            self.sub,
-            self.point,
-            self.span
+            self.sup, self.sub, self.point, self.span
         )
     }
 }
@@ -1187,9 +1165,7 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi
 
         debug!(
             "apply_requirements(location={:?}, closure_def_id={:?}, closure_substs={:?})",
-            location,
-            closure_def_id,
-            closure_substs
+            location, closure_def_id, closure_substs
         );
 
         // Get Tu.
@@ -1217,9 +1193,7 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi
                         "apply_requirements: region={:?} \
                          outlived_region={:?} \
                          outlives_requirement={:?}",
-                        region,
-                        outlived_region,
-                        outlives_requirement,
+                        region, outlived_region, outlives_requirement,
                     );
                     infcx.sub_regions(origin, outlived_region, region);
                 }
@@ -1230,9 +1204,7 @@ impl<'gcx, 'tcx> ClosureRegionRequirementsExt<'gcx, 'tcx> for ClosureRegionRequi
                         "apply_requirements: ty={:?} \
                          outlived_region={:?} \
                          outlives_requirement={:?}",
-                        ty,
-                        outlived_region,
-                        outlives_requirement,
+                        ty, outlived_region, outlives_requirement,
                     );
                     infcx.register_region_obligation(
                         body_id,
@@ -1285,77 +1257,14 @@ impl CauseExt for Rc<Cause> {
 }
 
 impl Cause {
-    pub(crate) fn label_diagnostic(&self, mir: &Mir<'_>, diag: &mut DiagnosticBuilder<'_>) {
-        // The cause information is pretty messy. Only dump it as an
-        // internal debugging aid if -Znll-dump-cause is given.
-        let nll_dump_cause = ty::tls::with(|tcx| tcx.sess.nll_dump_cause());
-        if !nll_dump_cause {
-            return;
-        }
-
-        let mut string = String::new();
-        self.push_diagnostic_string(mir, &mut string);
-        diag.note(&string);
-    }
-
-    fn push_diagnostic_string(&self, mir: &Mir<'_>, string: &mut String) {
-        match self {
-            Cause::LiveVar(local, location) => {
-                string.push_str(&format!("because `{:?}` is live at {:?}", local, location));
-            }
-
-            Cause::DropVar(local, location) => {
-                string.push_str(&format!(
-                    "because `{:?}` is dropped at {:?}",
-                    local,
-                    location
-                ));
-            }
-
-            Cause::LiveOther(location) => {
-                string.push_str(&format!(
-                    "because of a general liveness constraint at {:?}",
-                    location
-                ));
-            }
-
-            Cause::UniversalRegion(region_vid) => {
-                string.push_str(&format!(
-                    "because `{:?}` is universally quantified",
-                    region_vid
-                ));
-            }
-
-            Cause::Outlives {
-                original_cause,
-                constraint_location,
-                constraint_span: _,
-            } => {
-                string.push_str(&format!(
-                    "because of an outlives relation created at `{:?}`\n",
-                    constraint_location
-                ));
-
-                original_cause.push_diagnostic_string(mir, string);
-            }
-        }
-    }
-
     pub(crate) fn root_cause(&self) -> &Cause {
         match self {
-            Cause::LiveVar(..) |
-            Cause::DropVar(..) |
-            Cause::LiveOther(..) |
-            Cause::UniversalRegion(..) => {
-                self
-            }
+            Cause::LiveVar(..)
+            | Cause::DropVar(..)
+            | Cause::LiveOther(..)
+            | Cause::UniversalRegion(..) => self,
 
-            Cause::Outlives {
-                original_cause,
-                ..
-            } => {
-                original_cause.root_cause()
-            }
+            Cause::Outlives { original_cause, .. } => original_cause.root_cause(),
         }
     }
 }
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index a06d39d225c..3af10c5c251 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -1587,7 +1587,7 @@ impl MirPass for TypeckMir {
 
         // When NLL is enabled, the borrow checker runs the typeck
         // itself, so we don't need this MIR pass anymore.
-        if tcx.sess.nll() {
+        if tcx.nll() {
             return;
         }
 
diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs
index 932aad0bb1d..1ed8289d441 100644
--- a/src/librustc_mir/build/cfg.rs
+++ b/src/librustc_mir/build/cfg.rs
@@ -50,7 +50,7 @@ impl<'tcx> CFG<'tcx> {
                                              block: BasicBlock,
                                              source_info: SourceInfo,
                                              region_scope: region::Scope) {
-        if tcx.sess.emit_end_regions() {
+        if tcx.emit_end_regions() {
             if let region::ScopeData::CallSite(_) = region_scope.data() {
                 // The CallSite scope (aka the root scope) is sort of weird, in that it is
                 // supposed to "separate" the "interior" and "exterior" of a closure. Being
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
index b16d7ed2365..abea5583546 100644
--- a/src/librustc_mir/build/matches/simplify.rs
+++ b/src/librustc_mir/build/matches/simplify.rs
@@ -113,7 +113,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
             PatternKind::Variant { adt_def, substs, variant_index, ref subpatterns } => {
                 let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| {
                     i == variant_index || {
-                        self.hir.tcx().sess.features.borrow().never_type &&
+                        self.hir.tcx().features().never_type &&
                         self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs)
                     }
                 });
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index eb4ba21489c..10c2f9f758f 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -736,7 +736,7 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance:
         }
         Some(_) => true,
         None => {
-            if tcx.is_exported_symbol(def_id) ||
+            if tcx.is_reachable_non_generic(def_id) ||
                 tcx.is_foreign_item(def_id)
             {
                 // We can link to the item in question, no instance needed
@@ -984,7 +984,7 @@ impl<'b, 'a, 'v> RootCollector<'b, 'a, 'v> {
             }
             MonoItemCollectionMode::Lazy => {
                 self.entry_fn == Some(def_id) ||
-                self.tcx.is_exported_symbol(def_id) ||
+                self.tcx.is_reachable_non_generic(def_id) ||
                 attr::contains_name(&self.tcx.get_attrs(def_id),
                                     "rustc_std_internal_symbol")
             }
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index 2b558e71483..d65c1e03298 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -363,7 +363,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                     can_be_internalized = false;
                                     Visibility::Hidden
                                 } else if def_id.is_local() {
-                                    if tcx.is_exported_symbol(def_id) {
+                                    if tcx.is_reachable_non_generic(def_id) {
                                         can_be_internalized = false;
                                         default_visibility(def_id)
                                     } else {
@@ -385,7 +385,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         (Linkage::External, visibility)
                     }
                     MonoItem::Static(def_id) => {
-                        let visibility = if tcx.is_exported_symbol(def_id) {
+                        let visibility = if tcx.is_reachable_non_generic(def_id) {
                             can_be_internalized = false;
                             default_visibility(def_id)
                         } else {
@@ -395,7 +395,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                     }
                     MonoItem::GlobalAsm(node_id) => {
                         let def_id = tcx.hir.local_def_id(node_id);
-                        let visibility = if tcx.is_exported_symbol(def_id) {
+                        let visibility = if tcx.is_reachable_non_generic(def_id) {
                             can_be_internalized = false;
                             default_visibility(def_id)
                         } else {
diff --git a/src/librustc_mir/transform/clean_end_regions.rs b/src/librustc_mir/transform/clean_end_regions.rs
index 7986313aa81..6e8985d99d2 100644
--- a/src/librustc_mir/transform/clean_end_regions.rs
+++ b/src/librustc_mir/transform/clean_end_regions.rs
@@ -42,7 +42,7 @@ impl MirPass for CleanEndRegions {
                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           _source: MirSource,
                           mir: &mut Mir<'tcx>) {
-        if !tcx.sess.emit_end_regions() { return; }
+        if !tcx.emit_end_regions() { return; }
 
         let mut gather = GatherBorrowedRegions {
             seen_regions: FxHashSet()
diff --git a/src/librustc_mir/transform/lower_128bit.rs b/src/librustc_mir/transform/lower_128bit.rs
index 981b0b854bd..83cd7bf549d 100644
--- a/src/librustc_mir/transform/lower_128bit.rs
+++ b/src/librustc_mir/transform/lower_128bit.rs
@@ -77,19 +77,12 @@ impl Lower128Bit {
                 };
 
                 let bin_statement = block.statements.pop().unwrap();
-                let (source_info, place, lhs, mut rhs) = match bin_statement {
-                    Statement {
-                        source_info,
-                        kind: StatementKind::Assign(
-                            place,
-                            Rvalue::BinaryOp(_, lhs, rhs))
-                    } => (source_info, place, lhs, rhs),
-                    Statement {
-                        source_info,
-                        kind: StatementKind::Assign(
-                            place,
-                            Rvalue::CheckedBinaryOp(_, lhs, rhs))
-                    } => (source_info, place, lhs, rhs),
+                let source_info = bin_statement.source_info;
+                let (place, lhs, mut rhs) = match bin_statement.kind {
+                    StatementKind::Assign(place, Rvalue::BinaryOp(_, lhs, rhs))
+                    | StatementKind::Assign(place, Rvalue::CheckedBinaryOp(_, lhs, rhs)) => {
+                        (place, lhs, rhs)
+                    }
                     _ => bug!("Statement doesn't match pattern any more?"),
                 };
 
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 0b0ce1fb4d4..8f5831270d6 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -936,7 +936,7 @@ This does not pose a problem by itself because they can't be accessed directly."
                     if self.mode != Mode::Fn &&
 
                         // feature-gate is not enabled,
-                        !self.tcx.sess.features.borrow()
+                        !self.tcx.features()
                             .declared_lib_features
                             .iter()
                             .any(|&(ref sym, _)| sym == feature_name) &&
diff --git a/src/librustc_mir/util/borrowck_errors.rs b/src/librustc_mir/util/borrowck_errors.rs
index 4a7ee397aec..89242ca32bc 100644
--- a/src/librustc_mir/util/borrowck_errors.rs
+++ b/src/librustc_mir/util/borrowck_errors.rs
@@ -514,7 +514,7 @@ impl<'b, 'gcx, 'tcx> BorrowckErrors for TyCtxt<'b, 'gcx, 'tcx> {
                                 o: Origin)
                                 -> DiagnosticBuilder<'a>
     {
-        if !o.should_emit_errors(self.sess.borrowck_mode()) {
+        if !o.should_emit_errors(self.borrowck_mode()) {
             self.sess.diagnostic().cancel(&mut diag);
         }
         diag
diff --git a/src/librustc_plugin/load.rs b/src/librustc_plugin/load.rs
index a46b85d93cb..bf59165a9c4 100644
--- a/src/librustc_plugin/load.rs
+++ b/src/librustc_plugin/load.rs
@@ -52,7 +52,7 @@ pub fn load_plugins(sess: &Session,
     // do not report any error now. since crate attributes are
     // not touched by expansion, every use of plugin without
     // the feature enabled will result in an error later...
-    if sess.features.borrow().plugin {
+    if sess.features_untracked().plugin {
         for attr in &krate.attrs {
             if !attr.check_name("plugin") {
                 continue;
diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs
index b9899f49914..bf7b81c4d0e 100644
--- a/src/librustc_resolve/build_reduced_graph.rs
+++ b/src/librustc_resolve/build_reduced_graph.rs
@@ -590,7 +590,7 @@ impl<'a> Resolver<'a> {
         };
 
         let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
-                                               &self.session.features,
+                                               &self.session.features_untracked(),
                                                &macro_def));
         self.macro_map.insert(def_id, ext.clone());
         ext
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 317bd9217b5..fc1ff248184 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1524,7 +1524,7 @@ impl<'a> Resolver<'a> {
         invocations.insert(Mark::root(),
                            arenas.alloc_invocation_data(InvocationData::root(graph_root)));
 
-        let features = session.features.borrow();
+        let features = session.features_untracked();
 
         let mut macro_defs = FxHashMap();
         macro_defs.insert(Mark::root(), root_def_id);
@@ -2998,7 +2998,7 @@ impl<'a> Resolver<'a> {
                 let prim = self.primitive_type_table.primitive_types[&path[0].node.name];
                 match prim {
                     TyUint(UintTy::U128) | TyInt(IntTy::I128) => {
-                        if !self.session.features.borrow().i128_type {
+                        if !self.session.features_untracked().i128_type {
                             emit_feature_err(&self.session.parse_sess,
                                                 "i128_type", span, GateIssue::Language,
                                                 "128-bit type is unstable");
@@ -3089,7 +3089,7 @@ impl<'a> Resolver<'a> {
                     let prev_name = path[0].node.name;
                     if prev_name == keywords::Extern.name() ||
                        prev_name == keywords::CrateRoot.name() &&
-                       self.session.features.borrow().extern_absolute_paths {
+                       self.session.features_untracked().extern_absolute_paths {
                         // `::extern_crate::a::b`
                         let crate_id = self.crate_loader.resolve_crate_from_path(name, ident.span);
                         let crate_root =
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 81cc5e59bbb..95fa0f3b52f 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -744,7 +744,7 @@ impl<'a> Resolver<'a> {
 
         let def_id = self.definitions.local_def_id(item.id);
         let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
-                                               &self.session.features,
+                                               &self.session.features_untracked(),
                                                item));
         self.macro_map.insert(def_id, ext);
 
@@ -838,7 +838,7 @@ impl<'a> Resolver<'a> {
     }
 
     fn gate_legacy_custom_derive(&mut self, name: Symbol, span: Span) {
-        if !self.session.features.borrow().custom_derive {
+        if !self.session.features_untracked().custom_derive {
             let sess = &self.session.parse_sess;
             let explain = feature_gate::EXPLAIN_CUSTOM_DERIVE;
             emit_feature_err(sess, "custom_derive", span, GateIssue::Language, explain);
diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs
index 438ab3a3513..01c1ded9457 100644
--- a/src/librustc_resolve/resolve_imports.rs
+++ b/src/librustc_resolve/resolve_imports.rs
@@ -609,7 +609,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
         if module_path.len() == 1 && (module_path[0].node.name == keywords::CrateRoot.name() ||
                                       module_path[0].node.name == keywords::Extern.name()) {
             let is_extern = module_path[0].node.name == keywords::Extern.name() ||
-                            self.session.features.borrow().extern_absolute_paths;
+                            self.session.features_untracked().extern_absolute_paths;
             match directive.subclass {
                 GlobImport { .. } if is_extern => {
                     return Some((directive.span,
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index a3ff39a47a2..3fe667f1543 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -768,9 +768,9 @@ fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
     let mut symbols = Vec::new();
 
     let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
-    for &(ref name, _, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
+    for &(symbol, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
         if level.is_below_threshold(export_threshold) {
-            symbols.push(name.clone());
+            symbols.push(symbol.symbol_name(tcx).to_string());
         }
     }
 
@@ -782,9 +782,9 @@ fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
         // For each dependency that we are linking to statically ...
         if *dep_format == Linkage::Static {
             // ... we add its symbol list to our export list.
-            for &(ref name, _, level) in tcx.exported_symbols(cnum).iter() {
+            for &(symbol, level) in tcx.exported_symbols(cnum).iter() {
                 if level.is_below_threshold(export_threshold) {
-                    symbols.push(name.clone());
+                    symbols.push(symbol.symbol_name(tcx).to_string());
                 }
             }
         }
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs
index 3f9e9191cf0..f79651cef3e 100644
--- a/src/librustc_trans/back/lto.rs
+++ b/src/librustc_trans/back/lto.rs
@@ -113,7 +113,7 @@ pub(crate) fn run(cgcx: &CodegenContext,
         Lto::No => panic!("didn't request LTO but we're doing LTO"),
     };
 
-    let symbol_filter = &|&(ref name, _, level): &(String, _, SymbolExportLevel)| {
+    let symbol_filter = &|&(ref name, level): &(String, SymbolExportLevel)| {
         if level.is_below_threshold(export_threshold) {
             let mut bytes = Vec::with_capacity(name.len() + 1);
             bytes.extend(name.bytes());
diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs
index 55ef4e7ed3a..739ae768ca2 100644
--- a/src/librustc_trans/back/symbol_export.rs
+++ b/src/librustc_trans/back/symbol_export.rs
@@ -11,33 +11,27 @@
 use rustc_data_structures::sync::Lrc;
 use std::sync::Arc;
 
-use base;
 use monomorphize::Instance;
+use rustc::hir;
 use rustc::hir::def_id::CrateNum;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
-use rustc::middle::exported_symbols::SymbolExportLevel;
+use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name};
 use rustc::session::config;
-use rustc::ty::TyCtxt;
+use rustc::ty::{TyCtxt, SymbolName};
 use rustc::ty::maps::Providers;
-use rustc::util::nodemap::FxHashMap;
+use rustc::util::nodemap::{FxHashMap, DefIdSet};
 use rustc_allocator::ALLOCATOR_METHODS;
 use syntax::attr;
 
 pub type ExportedSymbols = FxHashMap<
     CrateNum,
-    Arc<Vec<(String, Option<DefId>, SymbolExportLevel)>>,
+    Arc<Vec<(String, SymbolExportLevel)>>,
 >;
 
 pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel {
     crates_export_threshold(&tcx.sess.crate_types.borrow())
 }
 
-pub fn metadata_symbol_name(tcx: TyCtxt) -> String {
-    format!("rust_metadata_{}_{}",
-            tcx.crate_name(LOCAL_CRATE),
-            tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex())
-}
-
 fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel {
     match crate_type {
         config::CrateTypeExecutable |
@@ -60,140 +54,203 @@ pub fn crates_export_threshold(crate_types: &[config::CrateType])
     }
 }
 
-pub fn provide(providers: &mut Providers) {
-    providers.exported_symbol_ids = |tcx, cnum| {
-        let export_threshold = threshold(tcx);
-        Lrc::new(tcx.exported_symbols(cnum)
-            .iter()
-            .filter_map(|&(_, id, level)| {
-                id.and_then(|id| {
-                    if level.is_below_threshold(export_threshold) {
-                        Some(id)
+fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                             cnum: CrateNum)
+                                             -> Lrc<DefIdSet>
+{
+    assert_eq!(cnum, LOCAL_CRATE);
+
+    if !tcx.sess.opts.output_types.should_trans() {
+        return Lrc::new(DefIdSet())
+    }
+
+    let export_threshold = threshold(tcx);
+
+    // We already collect all potentially reachable non-generic items for
+    // `exported_symbols`. Now we just filter them down to what is actually
+    // exported for the given crate we are compiling.
+    let reachable_non_generics = tcx
+        .exported_symbols(LOCAL_CRATE)
+        .iter()
+        .filter_map(|&(exported_symbol, level)| {
+            if let ExportedSymbol::NonGeneric(def_id) = exported_symbol {
+                if level.is_below_threshold(export_threshold) {
+                    return Some(def_id)
+                }
+            }
+
+            None
+        })
+        .collect();
+
+    Lrc::new(reachable_non_generics)
+}
+
+fn is_reachable_non_generic_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                               def_id: DefId)
+                                               -> bool {
+    tcx.reachable_non_generics(def_id.krate).contains(&def_id)
+}
+
+fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                             cnum: CrateNum)
+                                             -> Arc<Vec<(ExportedSymbol,
+                                                         SymbolExportLevel)>>
+{
+    assert_eq!(cnum, LOCAL_CRATE);
+
+    if !tcx.sess.opts.output_types.should_trans() {
+        return Arc::new(vec![])
+    }
+
+    // Check to see if this crate is a "special runtime crate". These
+    // crates, implementation details of the standard library, typically
+    // have a bunch of `pub extern` and `#[no_mangle]` functions as the
+    // ABI between them. We don't want their symbols to have a `C`
+    // export level, however, as they're just implementation details.
+    // Down below we'll hardwire all of the symbols to the `Rust` export
+    // level instead.
+    let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) ||
+        tcx.is_compiler_builtins(LOCAL_CRATE);
+
+    let reachable_non_generics: DefIdSet = tcx.reachable_set(LOCAL_CRATE).0
+        .iter()
+        .filter_map(|&node_id| {
+            // We want to ignore some FFI functions that are not exposed from
+            // this crate. Reachable FFI functions can be lumped into two
+            // categories:
+            //
+            // 1. Those that are included statically via a static library
+            // 2. Those included otherwise (e.g. dynamically or via a framework)
+            //
+            // Although our LLVM module is not literally emitting code for the
+            // statically included symbols, it's an export of our library which
+            // needs to be passed on to the linker and encoded in the metadata.
+            //
+            // As a result, if this id is an FFI item (foreign item) then we only
+            // let it through if it's included statically.
+            match tcx.hir.get(node_id) {
+                hir::map::NodeForeignItem(..) => {
+                    let def_id = tcx.hir.local_def_id(node_id);
+                    if tcx.is_statically_included_foreign_item(def_id) {
+                        Some(def_id)
                     } else {
                         None
                     }
-                })
-            })
-            .collect())
-    };
-
-    providers.is_exported_symbol = |tcx, id| {
-        tcx.exported_symbol_ids(id.krate).contains(&id)
-    };
-
-    providers.exported_symbols = |tcx, cnum| {
-        assert_eq!(cnum, LOCAL_CRATE);
-        let local_exported_symbols = base::find_exported_symbols(tcx);
-
-        let mut local_crate: Vec<_> = local_exported_symbols
-            .iter()
-            .map(|&node_id| {
-                tcx.hir.local_def_id(node_id)
-            })
-            .map(|def_id| {
-                let name = tcx.symbol_name(Instance::mono(tcx, def_id));
-                let export_level = export_level(tcx, def_id);
-                debug!("EXPORTED SYMBOL (local): {} ({:?})", name, export_level);
-                (str::to_owned(&name), Some(def_id), export_level)
-            })
-            .collect();
-
-        if let Some(_) = *tcx.sess.entry_fn.borrow() {
-            local_crate.push(("main".to_string(),
-                              None,
-                              SymbolExportLevel::C));
-        }
+                }
+
+                // Only consider nodes that actually have exported symbols.
+                hir::map::NodeItem(&hir::Item {
+                    node: hir::ItemStatic(..),
+                    ..
+                }) |
+                hir::map::NodeItem(&hir::Item {
+                    node: hir::ItemFn(..), ..
+                }) |
+                hir::map::NodeImplItem(&hir::ImplItem {
+                    node: hir::ImplItemKind::Method(..),
+                    ..
+                }) => {
+                    let def_id = tcx.hir.local_def_id(node_id);
+                    let generics = tcx.generics_of(def_id);
+                    if (generics.parent_types == 0 && generics.types.is_empty()) &&
+                        // Functions marked with #[inline] are only ever translated
+                        // with "internal" linkage and are never exported.
+                        !Instance::mono(tcx, def_id).def.requires_local(tcx) {
+                        Some(def_id)
+                    } else {
+                        None
+                    }
+                }
 
-        if tcx.sess.allocator_kind.get().is_some() {
-            for method in ALLOCATOR_METHODS {
-                local_crate.push((format!("__rust_{}", method.name),
-                                  None,
-                                  SymbolExportLevel::Rust));
+                _ => None
             }
-        }
+        })
+        .collect();
 
-        if let Some(id) = tcx.sess.derive_registrar_fn.get() {
-            let def_id = tcx.hir.local_def_id(id);
-            let disambiguator = tcx.sess.local_crate_disambiguator();
-            let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator);
-            local_crate.push((registrar, Some(def_id), SymbolExportLevel::C));
-        }
+    let mut symbols: Vec<_> = reachable_non_generics
+        .iter()
+        .map(|&def_id| {
+            let export_level = if special_runtime_crate {
+                let name = tcx.symbol_name(Instance::mono(tcx, def_id));
+                // We can probably do better here by just ensuring that
+                // it has hidden visibility rather than public
+                // visibility, as this is primarily here to ensure it's
+                // not stripped during LTO.
+                //
+                // In general though we won't link right if these
+                // symbols are stripped, and LTO currently strips them.
+                if &*name == "rust_eh_personality" ||
+                   &*name == "rust_eh_register_frames" ||
+                   &*name == "rust_eh_unregister_frames" {
+                    SymbolExportLevel::C
+                } else {
+                    SymbolExportLevel::Rust
+                }
+            } else {
+                tcx.symbol_export_level(def_id)
+            };
+            debug!("EXPORTED SYMBOL (local): {} ({:?})",
+                   tcx.symbol_name(Instance::mono(tcx, def_id)),
+                   export_level);
+            (ExportedSymbol::NonGeneric(def_id), export_level)
+        })
+        .collect();
+
+    if let Some(id) = tcx.sess.derive_registrar_fn.get() {
+        let def_id = tcx.hir.local_def_id(id);
+        symbols.push((ExportedSymbol::NonGeneric(def_id), SymbolExportLevel::C));
+    }
+
+    if let Some(id) = tcx.sess.plugin_registrar_fn.get() {
+        let def_id = tcx.hir.local_def_id(id);
+        symbols.push((ExportedSymbol::NonGeneric(def_id), SymbolExportLevel::C));
+    }
+
+    if let Some(_) = *tcx.sess.entry_fn.borrow() {
+        let symbol_name = "main".to_string();
+        let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
+
+        symbols.push((exported_symbol, SymbolExportLevel::C));
+    }
+
+    if tcx.sess.allocator_kind.get().is_some() {
+        for method in ALLOCATOR_METHODS {
+            let symbol_name = format!("__rust_{}", method.name);
+            let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
 
-        if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
-            local_crate.push((metadata_symbol_name(tcx),
-                              None,
-                              SymbolExportLevel::Rust));
+            symbols.push((exported_symbol, SymbolExportLevel::Rust));
         }
+    }
+
+    if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
+        let symbol_name = metadata_symbol_name(tcx);
+        let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name));
 
-        // Sort so we get a stable incr. comp. hash.
-        local_crate.sort_unstable_by(|&(ref name1, ..), &(ref name2, ..)| {
-            name1.cmp(name2)
-        });
+        symbols.push((exported_symbol, SymbolExportLevel::Rust));
+    }
 
-        Arc::new(local_crate)
-    };
+    // Sort so we get a stable incr. comp. hash.
+    symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| {
+        symbol1.compare_stable(tcx, symbol2)
+    });
 
-    providers.symbol_export_level = export_level;
+    Arc::new(symbols)
 }
 
-pub fn provide_extern(providers: &mut Providers) {
-    providers.exported_symbols = |tcx, cnum| {
-        // If this crate is a plugin and/or a custom derive crate, then
-        // we're not even going to link those in so we skip those crates.
-        if tcx.plugin_registrar_fn(cnum).is_some() ||
-           tcx.derive_registrar_fn(cnum).is_some() {
-            return Arc::new(Vec::new())
-        }
+pub fn provide(providers: &mut Providers) {
+    providers.reachable_non_generics = reachable_non_generics_provider;
+    providers.is_reachable_non_generic = is_reachable_non_generic_provider;
+    providers.exported_symbols = exported_symbols_provider_local;
+    providers.symbol_export_level = symbol_export_level_provider;
+}
 
-        // Check to see if this crate is a "special runtime crate". These
-        // crates, implementation details of the standard library, typically
-        // have a bunch of `pub extern` and `#[no_mangle]` functions as the
-        // ABI between them. We don't want their symbols to have a `C`
-        // export level, however, as they're just implementation details.
-        // Down below we'll hardwire all of the symbols to the `Rust` export
-        // level instead.
-        let special_runtime_crate =
-            tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum);
-
-        let mut crate_exports: Vec<_> = tcx
-            .exported_symbol_ids(cnum)
-            .iter()
-            .map(|&def_id| {
-                let name = tcx.symbol_name(Instance::mono(tcx, def_id));
-                let export_level = if special_runtime_crate {
-                    // We can probably do better here by just ensuring that
-                    // it has hidden visibility rather than public
-                    // visibility, as this is primarily here to ensure it's
-                    // not stripped during LTO.
-                    //
-                    // In general though we won't link right if these
-                    // symbols are stripped, and LTO currently strips them.
-                    if &*name == "rust_eh_personality" ||
-                       &*name == "rust_eh_register_frames" ||
-                       &*name == "rust_eh_unregister_frames" {
-                        SymbolExportLevel::C
-                    } else {
-                        SymbolExportLevel::Rust
-                    }
-                } else {
-                    export_level(tcx, def_id)
-                };
-                debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
-                (str::to_owned(&name), Some(def_id), export_level)
-            })
-            .collect();
-
-        // Sort so we get a stable incr. comp. hash.
-        crate_exports.sort_unstable_by(|&(ref name1, ..), &(ref name2, ..)| {
-            name1.cmp(name2)
-        });
-
-        Arc::new(crate_exports)
-    };
-    providers.symbol_export_level = export_level;
+pub fn provide_extern(providers: &mut Providers) {
+    providers.is_reachable_non_generic = is_reachable_non_generic_provider;
+    providers.symbol_export_level = symbol_export_level_provider;
 }
 
-fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
+fn symbol_export_level_provider(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
     // We export anything that's not mangled at the "C" layer as it probably has
     // to do with ABI concerns. We do not, however, apply such treatment to
     // special symbols in the standard library for various plumbing between
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 78b26a37485..c0561ff0c17 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -1332,20 +1332,31 @@ fn start_executing_work(tcx: TyCtxt,
     let coordinator_send = tcx.tx_to_llvm_workers.clone();
     let sess = tcx.sess;
 
-    let exported_symbols = match sess.lto() {
-        Lto::No => None,
-        Lto::ThinLocal => {
-            let mut exported_symbols = FxHashMap();
-            exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE));
-            Some(Arc::new(exported_symbols))
-        }
-        Lto::Yes | Lto::Fat | Lto::Thin => {
-            let mut exported_symbols = FxHashMap();
-            exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE));
-            for &cnum in tcx.crates().iter() {
-                exported_symbols.insert(cnum, tcx.exported_symbols(cnum));
+    // Compute the set of symbols we need to retain when doing LTO (if we need to)
+    let exported_symbols = {
+        let mut exported_symbols = FxHashMap();
+
+        let copy_symbols = |cnum| {
+            let symbols = tcx.exported_symbols(cnum)
+                             .iter()
+                             .map(|&(s, lvl)| (s.symbol_name(tcx).to_string(), lvl))
+                             .collect();
+            Arc::new(symbols)
+        };
+
+        match sess.lto() {
+            Lto::No => None,
+            Lto::ThinLocal => {
+                exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
+                Some(Arc::new(exported_symbols))
+            }
+            Lto::Yes | Lto::Fat | Lto::Thin => {
+                exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
+                for &cnum in tcx.crates().iter() {
+                    exported_symbols.insert(cnum, copy_symbols(cnum));
+                }
+                Some(Arc::new(exported_symbols))
             }
-            Some(Arc::new(exported_symbols))
         }
     };
 
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index c0785f53937..beb7a091bdc 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -30,7 +30,6 @@ use super::ModuleKind;
 
 use abi;
 use back::link;
-use back::symbol_export;
 use back::write::{self, OngoingCrateTranslation, create_target_machine};
 use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param};
 use llvm;
@@ -45,6 +44,7 @@ use rustc::ty::maps::Providers;
 use rustc::dep_graph::{DepNode, DepConstructor};
 use rustc::ty::subst::Kind;
 use rustc::middle::cstore::{self, LinkMeta, LinkagePreference};
+use rustc::middle::exported_symbols;
 use rustc::util::common::{time, print_time_passes_entry};
 use rustc::session::config::{self, NoDebugInfo};
 use rustc::session::Session;
@@ -70,7 +70,7 @@ use time_graph;
 use trans_item::{MonoItem, BaseMonoItemExt, MonoItemExt, DefPathBasedNames};
 use type_::Type;
 use type_of::LayoutLlvmExt;
-use rustc::util::nodemap::{NodeSet, FxHashMap, FxHashSet, DefIdSet};
+use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet};
 use CrateInfo;
 
 use std::any::Any;
@@ -89,7 +89,7 @@ use syntax::ast;
 
 use mir::operand::OperandValue;
 
-pub use rustc_trans_utils::{find_exported_symbols, check_for_rustc_errors_attr};
+pub use rustc_trans_utils::check_for_rustc_errors_attr;
 pub use rustc_mir::monomorphize::item::linkage_by_name;
 
 pub struct StatRecorder<'a, 'tcx: 'a> {
@@ -606,8 +606,7 @@ fn contains_null(s: &str) -> bool {
 
 fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
                             llmod_id: &str,
-                            link_meta: &LinkMeta,
-                            exported_symbols: &NodeSet)
+                            link_meta: &LinkMeta)
                             -> (ContextRef, ModuleRef, EncodedMetadata) {
     use std::io::Write;
     use flate2::Compression;
@@ -643,7 +642,7 @@ fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
                 EncodedMetadata::new());
     }
 
-    let metadata = tcx.encode_metadata(link_meta, exported_symbols);
+    let metadata = tcx.encode_metadata(link_meta);
     if kind == MetadataKind::Uncompressed {
         return (metadata_llcx, metadata_llmod, metadata);
     }
@@ -655,7 +654,7 @@ fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>,
 
     let llmeta = C_bytes_in_context(metadata_llcx, &compressed);
     let llconst = C_struct_in_context(metadata_llcx, &[llmeta], false);
-    let name = symbol_export::metadata_symbol_name(tcx);
+    let name = exported_symbols::metadata_symbol_name(tcx);
     let buf = CString::new(name).unwrap();
     let llglobal = unsafe {
         llvm::LLVMAddGlobal(metadata_llmod, val_ty(llconst).to_ref(), buf.as_ptr())
@@ -718,13 +717,12 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let crate_hash = tcx.crate_hash(LOCAL_CRATE);
     let link_meta = link::build_link_meta(crate_hash);
-    let exported_symbol_node_ids = find_exported_symbols(tcx);
 
     // Translate the metadata.
     let llmod_id = "metadata";
     let (metadata_llcx, metadata_llmod, metadata) =
         time(tcx.sess.time_passes(), "write metadata", || {
-            write_metadata(tcx, llmod_id, &link_meta, &exported_symbol_node_ids)
+            write_metadata(tcx, llmod_id, &link_meta)
         });
 
     let metadata_module = ModuleTranslation {
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 8c40aa6a2ac..54cc561e804 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -151,7 +151,7 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
 
             if cx.tcx.is_translated_item(instance_def_id) {
                 if instance_def_id.is_local() {
-                    if !cx.tcx.is_exported_symbol(instance_def_id) {
+                    if !cx.tcx.is_reachable_non_generic(instance_def_id) {
                         llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
                     }
                 } else {
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 1608c4a87bf..fd9cb8c5a6b 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -134,7 +134,7 @@ pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef {
 
                 let g = declare::define_global(cx, &sym[..], llty).unwrap();
 
-                if !cx.tcx.is_exported_symbol(def_id) {
+                if !cx.tcx.is_reachable_non_generic(def_id) {
                     unsafe {
                         llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden);
                     }
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index a285e5f263a..b93e8c2ad21 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -597,6 +597,12 @@ fn declare_intrinsic(cx: &CodegenCx, key: &str) -> Option<ValueRef> {
     ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64);
     ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128);
 
+    ifn!("llvm.bitreverse.i8", fn(t_i8) -> t_i8);
+    ifn!("llvm.bitreverse.i16", fn(t_i16) -> t_i16);
+    ifn!("llvm.bitreverse.i32", fn(t_i32) -> t_i32);
+    ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64);
+    ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128);
+
     ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1});
     ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1});
     ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1});
diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs
index 9559cd4d9ea..0a3f06b55f1 100644
--- a/src/librustc_trans/debuginfo/utils.rs
+++ b/src/librustc_trans/debuginfo/utils.rs
@@ -32,7 +32,7 @@ pub fn is_node_local_to_unit(cx: &CodegenCx, def_id: DefId) -> bool
     // visible). It might better to use the `exported_items` set from
     // `driver::CrateAnalysis` in the future, but (atm) this set is not
     // available in the translation pass.
-    !cx.tcx.is_exported_symbol(def_id)
+    !cx.tcx.is_reachable_non_generic(def_id)
 }
 
 #[allow(non_snake_case)]
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index b1f1fb52c90..3f87ce7e047 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -287,8 +287,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
             ], None)
         },
         "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "ctpop" | "bswap" |
-        "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
-        "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
+        "bitreverse" | "add_with_overflow" | "sub_with_overflow" |
+        "mul_with_overflow" | "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
         "unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" => {
             let ty = arg_tys[0];
             match int_type_width_signed(ty, cx) {
@@ -315,6 +315,10 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>,
                                         &[args[0].immediate()], None)
                             }
                         }
+                        "bitreverse" => {
+                            bx.call(cx.get_intrinsic(&format!("llvm.bitreverse.i{}", width)),
+                                &[args[0].immediate()], None)
+                        }
                         "add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" => {
                             let intrinsic = format!("llvm.{}{}.with.overflow.i{}",
                                                     if signed { 's' } else { 'u' },
diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs
index bfecb201983..d636a5f2e64 100644
--- a/src/librustc_trans_utils/lib.rs
+++ b/src/librustc_trans_utils/lib.rs
@@ -44,11 +44,7 @@ extern crate rustc_data_structures;
 
 pub extern crate rustc as __rustc;
 
-use rustc::ty::{TyCtxt, Instance};
-use rustc::hir;
-use rustc::hir::def_id::LOCAL_CRATE;
-use rustc::hir::map as hir_map;
-use rustc::util::nodemap::NodeSet;
+use rustc::ty::TyCtxt;
 
 pub mod diagnostics;
 pub mod link;
@@ -70,53 +66,4 @@ pub fn check_for_rustc_errors_attr(tcx: TyCtxt) {
     }
 }
 
-/// The context provided lists a set of reachable ids as calculated by
-/// middle::reachable, but this contains far more ids and symbols than we're
-/// actually exposing from the object file. This function will filter the set in
-/// the context to the set of ids which correspond to symbols that are exposed
-/// from the object file being generated.
-///
-/// This list is later used by linkers to determine the set of symbols needed to
-/// be exposed from a dynamic library and it's also encoded into the metadata.
-pub fn find_exported_symbols<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet {
-    tcx.reachable_set(LOCAL_CRATE).0.iter().cloned().filter(|&id| {
-        // Next, we want to ignore some FFI functions that are not exposed from
-        // this crate. Reachable FFI functions can be lumped into two
-        // categories:
-        //
-        // 1. Those that are included statically via a static library
-        // 2. Those included otherwise (e.g. dynamically or via a framework)
-        //
-        // Although our LLVM module is not literally emitting code for the
-        // statically included symbols, it's an export of our library which
-        // needs to be passed on to the linker and encoded in the metadata.
-        //
-        // As a result, if this id is an FFI item (foreign item) then we only
-        // let it through if it's included statically.
-        match tcx.hir.get(id) {
-            hir_map::NodeForeignItem(..) => {
-                let def_id = tcx.hir.local_def_id(id);
-                tcx.is_statically_included_foreign_item(def_id)
-            }
-
-            // Only consider nodes that actually have exported symbols.
-            hir_map::NodeItem(&hir::Item {
-                node: hir::ItemStatic(..), .. }) |
-            hir_map::NodeItem(&hir::Item {
-                node: hir::ItemFn(..), .. }) |
-            hir_map::NodeImplItem(&hir::ImplItem {
-                node: hir::ImplItemKind::Method(..), .. }) => {
-                let def_id = tcx.hir.local_def_id(id);
-                let generics = tcx.generics_of(def_id);
-                (generics.parent_types == 0 && generics.types.is_empty()) &&
-                // Functions marked with #[inline] are only ever translated
-                // with "internal" linkage and are never exported.
-                !Instance::mono(tcx, def_id).def.requires_local(tcx)
-            }
-
-            _ => false
-        }
-    }).collect()
-}
-
 __build_diagnostic_array! { librustc_trans_utils, DIAGNOSTICS }
diff --git a/src/librustc_trans_utils/symbol_names_test.rs b/src/librustc_trans_utils/symbol_names_test.rs
index 5d7d4f3055b..267c8d2bd03 100644
--- a/src/librustc_trans_utils/symbol_names_test.rs
+++ b/src/librustc_trans_utils/symbol_names_test.rs
@@ -28,7 +28,7 @@ pub fn report_symbol_names<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     // if the `rustc_attrs` feature is not enabled, then the
     // attributes we are interested in cannot be present anyway, so
     // skip the walk.
-    if !tcx.sess.features.borrow().rustc_attrs {
+    if !tcx.features().rustc_attrs {
         return;
     }
 
diff --git a/src/librustc_trans_utils/trans_crate.rs b/src/librustc_trans_utils/trans_crate.rs
index 419371ba3e3..7b2cbe140ae 100644
--- a/src/librustc_trans_utils/trans_crate.rs
+++ b/src/librustc_trans_utils/trans_crate.rs
@@ -247,8 +247,7 @@ impl TransCrate for MetadataOnlyTransCrate {
         tcx.sess.abort_if_errors();
 
         let link_meta = build_link_meta(tcx.crate_hash(LOCAL_CRATE));
-        let exported_symbols = ::find_exported_symbols(tcx);
-        let metadata = tcx.encode_metadata(&link_meta, &exported_symbols);
+        let metadata = tcx.encode_metadata(&link_meta);
 
         box OngoingCrateTranslation {
             metadata: metadata,
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index 6a6c49c9048..0df1225cf26 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -415,7 +415,7 @@ impl<'o, 'gcx: 'tcx, 'tcx> AstConv<'gcx, 'tcx>+'o {
 
         let trait_def = self.tcx().trait_def(trait_def_id);
 
-        if !self.tcx().sess.features.borrow().unboxed_closures &&
+        if !self.tcx().features().unboxed_closures &&
            trait_segment.with_parameters(|p| p.parenthesized) != trait_def.paren_sugar {
             // For now, require that parenthetical notation be used only with `Fn()` etc.
             let msg = if trait_def.paren_sugar {
diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs
index da66a2e52e8..a261c12bcdd 100644
--- a/src/librustc_typeck/check/_match.rs
+++ b/src/librustc_typeck/check/_match.rs
@@ -114,7 +114,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 }
             };
             if pat_adjustments.len() > 0 {
-                if tcx.sess.features.borrow().match_default_bindings {
+                if tcx.features().match_default_bindings {
                     debug!("default binding mode is now {:?}", def_bm);
                     self.inh.tables.borrow_mut()
                         .pat_adjustments_mut()
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index e2d6817697e..abb0acd699c 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -586,7 +586,7 @@ impl<'f, 'gcx, 'tcx> Coerce<'f, 'gcx, 'tcx> {
             }
         }
 
-        if has_unsized_tuple_coercion && !self.tcx.sess.features.borrow().unsized_tuple_coercion {
+        if has_unsized_tuple_coercion && !self.tcx.features().unsized_tuple_coercion {
             feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
                                            "unsized_tuple_coercion",
                                            self.cause.span,
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 23243c3ad66..2e00040d99a 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -275,7 +275,8 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             "volatile_store" =>
                 (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil()),
 
-            "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" | "bswap" =>
+            "ctpop" | "ctlz" | "ctlz_nonzero" | "cttz" | "cttz_nonzero" |
+            "bswap" | "bitreverse" =>
                 (1, vec![param(0)], param(0)),
 
             "add_with_overflow" | "sub_with_overflow"  | "mul_with_overflow" =>
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index c95ead28559..841559013a0 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -324,7 +324,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                 // possible that there will be multiple applicable methods.
                 if !is_suggestion.0 {
                     if reached_raw_pointer
-                    && !self.tcx.sess.features.borrow().arbitrary_self_types {
+                    && !self.tcx.features().arbitrary_self_types {
                         // this case used to be allowed by the compiler,
                         // so we do a future-compat lint here for the 2015 epoch
                         // (see https://github.com/rust-lang/rust/issues/46906)
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index db5a458bb8c..0f59973eab2 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1105,7 +1105,7 @@ fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
     }
     fcx.demand_suptype(span, ret_ty, actual_return_ty);
 
-    if fcx.tcx.sess.features.borrow().termination_trait {
+    if fcx.tcx.features().termination_trait {
         // If the termination trait language item is activated, check that the main return type
         // implements the termination trait.
         if let Some(term_id) = fcx.tcx.lang_items().termination() {
@@ -1616,7 +1616,7 @@ pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let repr_type_ty = def.repr.discr_type().to_ty(tcx);
     if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
-        if !tcx.sess.features.borrow().repr128 {
+        if !tcx.features().repr128 {
             emit_feature_err(&tcx.sess.parse_sess,
                              "repr128",
                              sp,
diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs
index 39e757c52ff..d10ee358e07 100644
--- a/src/librustc_typeck/check/wfcheck.rs
+++ b/src/librustc_typeck/check/wfcheck.rs
@@ -536,7 +536,7 @@ impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
         let is_self_ty = |ty| fcx.infcx.can_eq(fcx.param_env, self_ty, ty).is_ok();
         let self_kind = ExplicitSelf::determine(self_arg_ty, is_self_ty);
 
-        if !fcx.tcx.sess.features.borrow().arbitrary_self_types {
+        if !fcx.tcx.features().arbitrary_self_types {
             match self_kind {
                 ExplicitSelf::ByValue |
                 ExplicitSelf::ByReference(_, _) |
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index f65d627781f..d3de31d630a 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -74,7 +74,7 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_d
         return;
     }
 
-    if tcx.sess.features.borrow().unboxed_closures {
+    if tcx.features().unboxed_closures {
         // the feature gate allows all Fn traits
         return;
     }
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index 1c8d22e4666..f7158593f0b 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -711,7 +711,7 @@ fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     };
 
     let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar");
-    if paren_sugar && !tcx.sess.features.borrow().unboxed_closures {
+    if paren_sugar && !tcx.features().unboxed_closures {
         let mut err = tcx.sess.struct_span_err(
             item.span,
             "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \
@@ -953,7 +953,7 @@ fn generics_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         }
 
         if !allow_defaults && p.default.is_some() {
-            if !tcx.sess.features.borrow().default_type_parameter_fallback {
+            if !tcx.features().default_type_parameter_fallback {
                 tcx.lint_node(
                     lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
                     p.id,
@@ -1692,7 +1692,7 @@ fn compute_sig_of_foreign_fn_decl<'a, 'tcx>(
     // feature gate SIMD types in FFI, since I (huonw) am not sure the
     // ABIs are handled at all correctly.
     if abi != abi::Abi::RustIntrinsic && abi != abi::Abi::PlatformIntrinsic
-            && !tcx.sess.features.borrow().simd_ffi {
+            && !tcx.features().simd_ffi {
         let check = |ast_ty: &hir::Ty, ty: Ty| {
             if ty.is_simd() {
                 tcx.sess.struct_span_err(ast_ty.span,
diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs
index af32738d9d0..d9bd96b0d76 100644
--- a/src/librustc_typeck/lib.rs
+++ b/src/librustc_typeck/lib.rs
@@ -207,7 +207,7 @@ fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             let actual = tcx.fn_sig(main_def_id);
             let expected_return_type = if tcx.lang_items().termination().is_some()
-                && tcx.sess.features.borrow().termination_trait {
+                && tcx.features().termination_trait {
                 // we take the return type of the given main function, the real check is done
                 // in `check_fn`
                 actual.output().skip_binder()
diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs
index f4c9d556c8a..e4477bee5c0 100644
--- a/src/librustdoc/test.rs
+++ b/src/librustdoc/test.rs
@@ -629,7 +629,7 @@ impl<'a, 'hir> HirCollector<'a, 'hir> {
                                             nested: F) {
         let mut attrs = Attributes::from_ast(self.sess.diagnostic(), attrs);
         if let Some(ref cfg) = attrs.cfg {
-            if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features.borrow())) {
+            if !cfg.matches(&self.sess.parse_sess, Some(&self.sess.features_untracked())) {
                 return;
             }
         }
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index 4dfdc23ebee..6f4528a0e24 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -620,7 +620,7 @@ impl<K: Hash + Eq, V> HashMap<K, V, RandomState> {
     ///
     /// ```
     /// use std::collections::HashMap;
-    /// let mut map: HashMap<&str, isize> = HashMap::new();
+    /// let mut map: HashMap<&str, i32> = HashMap::new();
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -637,7 +637,7 @@ impl<K: Hash + Eq, V> HashMap<K, V, RandomState> {
     ///
     /// ```
     /// use std::collections::HashMap;
-    /// let mut map: HashMap<&str, isize> = HashMap::with_capacity(10);
+    /// let mut map: HashMap<&str, i32> = HashMap::with_capacity(10);
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -724,7 +724,7 @@ impl<K, V, S> HashMap<K, V, S>
     /// use std::collections::hash_map::RandomState;
     ///
     /// let hasher = RandomState::new();
-    /// let map: HashMap<isize, isize> = HashMap::with_hasher(hasher);
+    /// let map: HashMap<i32, i32> = HashMap::with_hasher(hasher);
     /// let hasher: &RandomState = map.hasher();
     /// ```
     #[stable(feature = "hashmap_public_hasher", since = "1.9.0")]
@@ -741,7 +741,7 @@ impl<K, V, S> HashMap<K, V, S>
     ///
     /// ```
     /// use std::collections::HashMap;
-    /// let map: HashMap<isize, isize> = HashMap::with_capacity(100);
+    /// let map: HashMap<i32, i32> = HashMap::with_capacity(100);
     /// assert!(map.capacity() >= 100);
     /// ```
     #[inline]
@@ -770,7 +770,7 @@ impl<K, V, S> HashMap<K, V, S>
     ///
     /// ```
     /// use std::collections::HashMap;
-    /// let mut map: HashMap<&str, isize> = HashMap::new();
+    /// let mut map: HashMap<&str, i32> = HashMap::new();
     /// map.reserve(10);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -849,7 +849,7 @@ impl<K, V, S> HashMap<K, V, S>
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map: HashMap<isize, isize> = HashMap::with_capacity(100);
+    /// let mut map: HashMap<i32, i32> = HashMap::with_capacity(100);
     /// map.insert(1, 2);
     /// map.insert(3, 4);
     /// assert!(map.capacity() >= 100);
@@ -1306,7 +1306,7 @@ impl<K, V, S> HashMap<K, V, S>
     /// ```
     /// use std::collections::HashMap;
     ///
-    /// let mut map: HashMap<isize, isize> = (0..8).map(|x|(x, x*10)).collect();
+    /// let mut map: HashMap<i32, i32> = (0..8).map(|x|(x, x*10)).collect();
     /// map.retain(|&k, _| k % 2 == 0);
     /// assert_eq!(map.len(), 4);
     /// ```
@@ -1722,7 +1722,7 @@ impl<K, V, S> IntoIterator for HashMap<K, V, S>
     /// map.insert("c", 3);
     ///
     /// // Not possible with .iter()
-    /// let vec: Vec<(&str, isize)> = map.into_iter().collect();
+    /// let vec: Vec<(&str, i32)> = map.into_iter().collect();
     /// ```
     fn into_iter(self) -> IntoIter<K, V> {
         IntoIter { inner: self.table.into_iter() }
@@ -1750,7 +1750,7 @@ impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for Iter<'a, K, V> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1773,7 +1773,7 @@ impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {
         self.inner.len()
     }
 }
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for IterMut<'a, K, V> {}
 
 #[stable(feature = "std_debug", since = "1.16.0")]
@@ -1808,7 +1808,7 @@ impl<K, V> ExactSizeIterator for IntoIter<K, V> {
         self.inner.len()
     }
 }
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<K, V> FusedIterator for IntoIter<K, V> {}
 
 #[stable(feature = "std_debug", since = "1.16.0")]
@@ -1840,7 +1840,7 @@ impl<'a, K, V> ExactSizeIterator for Keys<'a, K, V> {
         self.inner.len()
     }
 }
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for Keys<'a, K, V> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1863,7 +1863,7 @@ impl<'a, K, V> ExactSizeIterator for Values<'a, K, V> {
         self.inner.len()
     }
 }
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for Values<'a, K, V> {}
 
 #[stable(feature = "map_values_mut", since = "1.10.0")]
@@ -1886,7 +1886,7 @@ impl<'a, K, V> ExactSizeIterator for ValuesMut<'a, K, V> {
         self.inner.len()
     }
 }
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for ValuesMut<'a, K, V> {}
 
 #[stable(feature = "std_debug", since = "1.16.0")]
@@ -1921,7 +1921,7 @@ impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> {
         self.inner.len()
     }
 }
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K, V> FusedIterator for Drain<'a, K, V> {}
 
 #[stable(feature = "std_debug", since = "1.16.0")]
@@ -2786,24 +2786,24 @@ mod test_map {
         assert_eq!(m2.len(), 2);
     }
 
-    thread_local! { static DROP_VECTOR: RefCell<Vec<isize>> = RefCell::new(Vec::new()) }
+    thread_local! { static DROP_VECTOR: RefCell<Vec<i32>> = RefCell::new(Vec::new()) }
 
     #[derive(Hash, PartialEq, Eq)]
-    struct Dropable {
+    struct Droppable {
         k: usize,
     }
 
-    impl Dropable {
-        fn new(k: usize) -> Dropable {
+    impl Droppable {
+        fn new(k: usize) -> Droppable {
             DROP_VECTOR.with(|slot| {
                 slot.borrow_mut()[k] += 1;
             });
 
-            Dropable { k: k }
+            Droppable { k: k }
         }
     }
 
-    impl Drop for Dropable {
+    impl Drop for Droppable {
         fn drop(&mut self) {
             DROP_VECTOR.with(|slot| {
                 slot.borrow_mut()[self.k] -= 1;
@@ -2811,9 +2811,9 @@ mod test_map {
         }
     }
 
-    impl Clone for Dropable {
-        fn clone(&self) -> Dropable {
-            Dropable::new(self.k)
+    impl Clone for Droppable {
+        fn clone(&self) -> Droppable {
+            Droppable::new(self.k)
         }
     }
 
@@ -2833,8 +2833,8 @@ mod test_map {
             });
 
             for i in 0..100 {
-                let d1 = Dropable::new(i);
-                let d2 = Dropable::new(i + 100);
+                let d1 = Droppable::new(i);
+                let d2 = Droppable::new(i + 100);
                 m.insert(d1, d2);
             }
 
@@ -2845,7 +2845,7 @@ mod test_map {
             });
 
             for i in 0..50 {
-                let k = Dropable::new(i);
+                let k = Droppable::new(i);
                 let v = m.remove(&k);
 
                 assert!(v.is_some());
@@ -2892,8 +2892,8 @@ mod test_map {
             });
 
             for i in 0..100 {
-                let d1 = Dropable::new(i);
-                let d2 = Dropable::new(i + 100);
+                let d1 = Droppable::new(i);
+                let d2 = Droppable::new(i + 100);
                 hm.insert(d1, d2);
             }
 
@@ -2943,13 +2943,13 @@ mod test_map {
 
     #[test]
     fn test_empty_remove() {
-        let mut m: HashMap<isize, bool> = HashMap::new();
+        let mut m: HashMap<i32, bool> = HashMap::new();
         assert_eq!(m.remove(&0), None);
     }
 
     #[test]
     fn test_empty_entry() {
-        let mut m: HashMap<isize, bool> = HashMap::new();
+        let mut m: HashMap<i32, bool> = HashMap::new();
         match m.entry(0) {
             Occupied(_) => panic!(),
             Vacant(_) => {}
@@ -2960,7 +2960,7 @@ mod test_map {
 
     #[test]
     fn test_empty_iter() {
-        let mut m: HashMap<isize, bool> = HashMap::new();
+        let mut m: HashMap<i32, bool> = HashMap::new();
         assert_eq!(m.drain().next(), None);
         assert_eq!(m.keys().next(), None);
         assert_eq!(m.values().next(), None);
@@ -3461,7 +3461,7 @@ mod test_map {
     fn test_entry_take_doesnt_corrupt() {
         #![allow(deprecated)] //rand
         // Test for #19292
-        fn check(m: &HashMap<isize, ()>) {
+        fn check(m: &HashMap<i32, ()>) {
             for k in m.keys() {
                 assert!(m.contains_key(k),
                         "{} is in keys() but not in the map?", k);
@@ -3570,7 +3570,7 @@ mod test_map {
 
     #[test]
     fn test_retain() {
-        let mut map: HashMap<isize, isize> = (0..100).map(|x|(x, x*10)).collect();
+        let mut map: HashMap<i32, i32> = (0..100).map(|x|(x, x*10)).collect();
 
         map.retain(|&k, _| k % 2 == 0);
         assert_eq!(map.len(), 50);
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index e9427fb40a0..9e63ba2717a 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -724,7 +724,7 @@ impl<T, S> HashSet<T, S>
     /// use std::collections::HashSet;
     ///
     /// let xs = [1,2,3,4,5,6];
-    /// let mut set: HashSet<isize> = xs.iter().cloned().collect();
+    /// let mut set: HashSet<i32> = xs.iter().cloned().collect();
     /// set.retain(|&k| k % 2 == 0);
     /// assert_eq!(set.len(), 3);
     /// ```
@@ -1097,7 +1097,7 @@ impl<'a, K> ExactSizeIterator for Iter<'a, K> {
         self.iter.len()
     }
 }
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K> FusedIterator for Iter<'a, K> {}
 
 #[stable(feature = "std_debug", since = "1.16.0")]
@@ -1124,7 +1124,7 @@ impl<K> ExactSizeIterator for IntoIter<K> {
         self.iter.len()
     }
 }
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<K> FusedIterator for IntoIter<K> {}
 
 #[stable(feature = "std_debug", since = "1.16.0")]
@@ -1155,7 +1155,7 @@ impl<'a, K> ExactSizeIterator for Drain<'a, K> {
         self.iter.len()
     }
 }
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, K> FusedIterator for Drain<'a, K> {}
 
 #[stable(feature = "std_debug", since = "1.16.0")]
@@ -1208,7 +1208,7 @@ impl<'a, T, S> fmt::Debug for Intersection<'a, T, S>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T, S> FusedIterator for Intersection<'a, T, S>
     where T: Eq + Hash,
           S: BuildHasher
@@ -1244,7 +1244,7 @@ impl<'a, T, S> Iterator for Difference<'a, T, S>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T, S> FusedIterator for Difference<'a, T, S>
     where T: Eq + Hash,
           S: BuildHasher
@@ -1283,7 +1283,7 @@ impl<'a, T, S> Iterator for SymmetricDifference<'a, T, S>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T, S> FusedIterator for SymmetricDifference<'a, T, S>
     where T: Eq + Hash,
           S: BuildHasher
@@ -1307,7 +1307,7 @@ impl<'a, T, S> Clone for Union<'a, T, S> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a, T, S> FusedIterator for Union<'a, T, S>
     where T: Eq + Hash,
           S: BuildHasher
@@ -1745,7 +1745,7 @@ mod test_set {
     #[test]
     fn test_retain() {
         let xs = [1, 2, 3, 4, 5, 6];
-        let mut set: HashSet<isize> = xs.iter().cloned().collect();
+        let mut set: HashSet<i32> = xs.iter().cloned().collect();
         set.retain(|&k| k % 2 == 0);
         assert_eq!(set.len(), 3);
         assert!(set.contains(&2));
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index 2519d830435..c88c2bc9137 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -875,6 +875,8 @@ impl CStr {
     ///   `ptr`.
     /// * There is no guarantee that the memory pointed to by `ptr` contains a
     ///   valid nul terminator byte at the end of the string.
+    /// * It is not guaranteed that the memory pointed by `ptr` won't change
+    ///   before the `CStr` has been destroyed.
     ///
     /// > **Note**: This operation is intended to be a 0-cost cast but it is
     /// > currently implemented with an up-front calculation of the length of
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index a7e1c0ce732..da15941374d 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -266,7 +266,6 @@
 #![feature(float_from_str_radix)]
 #![feature(fn_traits)]
 #![feature(fnbox)]
-#![feature(fused)]
 #![feature(generic_param_attrs)]
 #![feature(hashmap_hasher)]
 #![feature(heap_api)]
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
index 1608a752a46..cd2af99d6ac 100644
--- a/src/libstd/path.rs
+++ b/src/libstd/path.rs
@@ -905,7 +905,7 @@ impl<'a> DoubleEndedIterator for Iter<'a> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a> FusedIterator for Iter<'a> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1008,7 +1008,7 @@ impl<'a> DoubleEndedIterator for Components<'a> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a> FusedIterator for Components<'a> {}
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1076,7 +1076,7 @@ impl<'a> Iterator for Ancestors<'a> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[unstable(feature = "path_ancestors", issue = "48581")]
 impl<'a> FusedIterator for Ancestors<'a> {}
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/src/libstd/sys_common/wtf8.rs b/src/libstd/sys_common/wtf8.rs
index 46d554d6411..9fff8b91f96 100644
--- a/src/libstd/sys_common/wtf8.rs
+++ b/src/libstd/sys_common/wtf8.rs
@@ -428,20 +428,15 @@ impl fmt::Debug for Wtf8 {
 
         formatter.write_str("\"")?;
         let mut pos = 0;
-        loop {
-            match self.next_surrogate(pos) {
-                None => break,
-                Some((surrogate_pos, surrogate)) => {
-                    write_str_escaped(
-                        formatter,
-                        unsafe { str::from_utf8_unchecked(
-                            &self.bytes[pos .. surrogate_pos]
-                        )},
-                    )?;
-                    write!(formatter, "\\u{{{:x}}}", surrogate)?;
-                    pos = surrogate_pos + 3;
-                }
-            }
+        while let Some((surrogate_pos, surrogate)) = self.next_surrogate(pos) {
+            write_str_escaped(
+                formatter,
+                unsafe { str::from_utf8_unchecked(
+                    &self.bytes[pos .. surrogate_pos]
+                )},
+            )?;
+            write!(formatter, "\\u{{{:x}}}", surrogate)?;
+            pos = surrogate_pos + 3;
         }
         write_str_escaped(
             formatter,
diff --git a/src/libstd_unicode/char.rs b/src/libstd_unicode/char.rs
index 5dd9c627750..de8b46d5f1b 100644
--- a/src/libstd_unicode/char.rs
+++ b/src/libstd_unicode/char.rs
@@ -70,7 +70,7 @@ impl Iterator for ToLowercase {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl FusedIterator for ToLowercase {}
 
 /// Returns an iterator that yields the uppercase equivalent of a `char`.
@@ -92,7 +92,7 @@ impl Iterator for ToUppercase {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl FusedIterator for ToUppercase {}
 
 #[derive(Debug, Clone)]
diff --git a/src/libstd_unicode/lib.rs b/src/libstd_unicode/lib.rs
index dcae7d0af40..f155b62e3cc 100644
--- a/src/libstd_unicode/lib.rs
+++ b/src/libstd_unicode/lib.rs
@@ -36,7 +36,6 @@
 #![feature(str_internals)]
 #![feature(decode_utf8)]
 #![feature(fn_traits)]
-#![feature(fused)]
 #![feature(lang_items)]
 #![feature(non_exhaustive)]
 #![feature(staged_api)]
diff --git a/src/libstd_unicode/u_str.rs b/src/libstd_unicode/u_str.rs
index 5d1611acb7e..a72e1210d93 100644
--- a/src/libstd_unicode/u_str.rs
+++ b/src/libstd_unicode/u_str.rs
@@ -127,7 +127,6 @@ impl<I> Iterator for Utf16Encoder<I>
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
 impl<I> FusedIterator for Utf16Encoder<I>
     where I: FusedIterator<Item = char> {}
 
@@ -186,5 +185,5 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> {
     }
 }
 
-#[unstable(feature = "fused", issue = "35602")]
+#[stable(feature = "fused", since = "1.26.0")]
 impl<'a> FusedIterator for SplitWhitespace<'a> {}
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index 728b3e4076d..9162a582599 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -26,7 +26,6 @@ use parse::token::Token::*;
 use symbol::Symbol;
 use tokenstream::{TokenStream, TokenTree};
 
-use std::cell::RefCell;
 use std::collections::HashMap;
 use std::collections::hash_map::Entry;
 
@@ -184,7 +183,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
 // Holy self-referential!
 
 /// Converts a `macro_rules!` invocation into a syntax extension.
-pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item) -> SyntaxExtension {
+pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> SyntaxExtension {
     let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs"));
     let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs"));
 
@@ -296,7 +295,7 @@ pub fn compile(sess: &ParseSess, features: &RefCell<Features>, def: &ast::Item)
 }
 
 fn check_lhs_nt_follows(sess: &ParseSess,
-                        features: &RefCell<Features>,
+                        features: &Features,
                         attrs: &[ast::Attribute],
                         lhs: &quoted::TokenTree) -> bool {
     // lhs is going to be like TokenTree::Delimited(...), where the
@@ -353,7 +352,7 @@ fn check_rhs(sess: &ParseSess, rhs: &quoted::TokenTree) -> bool {
 }
 
 fn check_matcher(sess: &ParseSess,
-                 features: &RefCell<Features>,
+                 features: &Features,
                  attrs: &[ast::Attribute],
                  matcher: &[quoted::TokenTree]) -> bool {
     let first_sets = FirstSets::new(matcher);
@@ -601,7 +600,7 @@ impl TokenSet {
 // Requires that `first_sets` is pre-computed for `matcher`;
 // see `FirstSets::new`.
 fn check_matcher_core(sess: &ParseSess,
-                      features: &RefCell<Features>,
+                      features: &Features,
                       attrs: &[ast::Attribute],
                       first_sets: &FirstSets,
                       matcher: &[quoted::TokenTree],
@@ -869,7 +868,7 @@ fn is_in_follow(tok: &quoted::TokenTree, frag: &str) -> Result<bool, (String, &'
 }
 
 fn has_legal_fragment_specifier(sess: &ParseSess,
-                                features: &RefCell<Features>,
+                                features: &Features,
                                 attrs: &[ast::Attribute],
                                 tok: &quoted::TokenTree) -> Result<(), String> {
     debug!("has_legal_fragment_specifier({:?})", tok);
@@ -884,7 +883,7 @@ fn has_legal_fragment_specifier(sess: &ParseSess,
 }
 
 fn is_legal_fragment_specifier(sess: &ParseSess,
-                               features: &RefCell<Features>,
+                               features: &Features,
                                attrs: &[ast::Attribute],
                                frag_name: &str,
                                frag_span: Span) -> bool {
@@ -892,7 +891,7 @@ fn is_legal_fragment_specifier(sess: &ParseSess,
         "item" | "block" | "stmt" | "expr" | "pat" |
         "path" | "ty" | "ident" | "meta" | "tt" | "" => true,
         "lifetime" => {
-            if !features.borrow().macro_lifetime_matcher &&
+            if !features.macro_lifetime_matcher &&
                !attr::contains_name(attrs, "allow_internal_unstable") {
                 let explain = feature_gate::EXPLAIN_LIFETIME_MATCHER;
                 emit_feature_err(sess,
@@ -904,7 +903,7 @@ fn is_legal_fragment_specifier(sess: &ParseSess,
             true
         },
         "vis" => {
-            if !features.borrow().macro_vis_matcher &&
+            if !features.macro_vis_matcher &&
                !attr::contains_name(attrs, "allow_internal_unstable") {
                 let explain = feature_gate::EXPLAIN_VIS_MATCHER;
                 emit_feature_err(sess,
diff --git a/src/libsyntax/ext/tt/quoted.rs b/src/libsyntax/ext/tt/quoted.rs
index c9d7f78c2e3..122bb9ba024 100644
--- a/src/libsyntax/ext/tt/quoted.rs
+++ b/src/libsyntax/ext/tt/quoted.rs
@@ -17,7 +17,6 @@ use symbol::keywords;
 use syntax_pos::{BytePos, Span, DUMMY_SP};
 use tokenstream;
 
-use std::cell::RefCell;
 use std::iter::Peekable;
 use rustc_data_structures::sync::Lrc;
 
@@ -183,7 +182,7 @@ pub fn parse(
     input: tokenstream::TokenStream,
     expect_matchers: bool,
     sess: &ParseSess,
-    features: &RefCell<Features>,
+    features: &Features,
     attrs: &[ast::Attribute],
 ) -> Vec<TokenTree> {
     // Will contain the final collection of `self::TokenTree`
@@ -251,7 +250,7 @@ fn parse_tree<I>(
     trees: &mut Peekable<I>,
     expect_matchers: bool,
     sess: &ParseSess,
-    features: &RefCell<Features>,
+    features: &Features,
     attrs: &[ast::Attribute],
 ) -> TokenTree
 where
@@ -382,7 +381,7 @@ fn parse_sep_and_kleene_op<I>(
     input: &mut Peekable<I>,
     span: Span,
     sess: &ParseSess,
-    features: &RefCell<Features>,
+    features: &Features,
     attrs: &[ast::Attribute],
 ) -> (Option<token::Token>, KleeneOp)
 where
@@ -415,7 +414,7 @@ where
                 match parse_kleene_op(input, span) {
                     // #2 is a KleeneOp (this is the only valid option) :)
                     Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => {
-                        if !features.borrow().macro_at_most_once_rep
+                        if !features.macro_at_most_once_rep
                             && !attr::contains_name(attrs, "allow_internal_unstable")
                         {
                             let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
@@ -438,7 +437,7 @@ where
                     Err(span) => span,
                 }
             } else {
-                if !features.borrow().macro_at_most_once_rep
+                if !features.macro_at_most_once_rep
                     && !attr::contains_name(attrs, "allow_internal_unstable")
                 {
                     let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
@@ -460,7 +459,7 @@ where
         Ok(Err((tok, span))) => match parse_kleene_op(input, span) {
             // #2 is a KleeneOp :D
             Ok(Ok(op)) if op == KleeneOp::ZeroOrOne => {
-                if !features.borrow().macro_at_most_once_rep
+                if !features.macro_at_most_once_rep
                     && !attr::contains_name(attrs, "allow_internal_unstable")
                 {
                     let explain = feature_gate::EXPLAIN_MACRO_AT_MOST_ONCE_REP;
@@ -487,7 +486,7 @@ where
         Err(span) => span,
     };
 
-    if !features.borrow().macro_at_most_once_rep
+    if !features.macro_at_most_once_rep
         && !attr::contains_name(attrs, "allow_internal_unstable")
     {
         sess.span_diagnostic
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 058df1d5169..45d82bc7af3 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -62,6 +62,7 @@ macro_rules! declare_features {
             &[$((stringify!($feature), $ver, $issue, set!($feature))),+];
 
         /// A set of features to be used by later passes.
+        #[derive(Clone)]
         pub struct Features {
             /// `#![feature]` attrs for stable language features, for error reporting
             pub declared_stable_lang_features: Vec<(Symbol, Span)>,
@@ -78,6 +79,12 @@ macro_rules! declare_features {
                     $($feature: false),+
                 }
             }
+
+            pub fn walk_feature_fields<F>(&self, mut f: F)
+                where F: FnMut(&str, bool)
+            {
+                $(f(stringify!($feature), self.$feature);)+
+            }
         }
     };
 
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index b5368b3ecab..94195ccc72c 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -132,6 +132,18 @@ impl<'a> StringReader<'a> {
         self.advance_token()?;
         Ok(ret_val)
     }
+
+    fn fail_unterminated_raw_string(&self, pos: BytePos, hash_count: usize) {
+        let mut err = self.struct_span_fatal(pos, pos, "unterminated raw string");
+        err.span_label(self.mk_sp(pos, pos), "unterminated raw string");
+        if hash_count > 0 {
+            err.note(&format!("this raw string should be terminated with `\"{}`",
+                              "#".repeat(hash_count)));
+        }
+        err.emit();
+        FatalError.raise();
+    }
+
     fn fatal(&self, m: &str) -> FatalError {
         self.fatal_span(self.peek_span, m)
     }
@@ -269,6 +281,15 @@ impl<'a> StringReader<'a> {
         Self::push_escaped_char_for_msg(&mut m, c);
         self.fatal_span_(from_pos, to_pos, &m[..])
     }
+
+    fn struct_span_fatal(&self,
+                         from_pos: BytePos,
+                         to_pos: BytePos,
+                         m: &str)
+                         -> DiagnosticBuilder<'a> {
+        self.sess.span_diagnostic.struct_span_fatal(self.mk_sp(from_pos, to_pos), m)
+    }
+
     fn struct_fatal_span_char(&self,
                               from_pos: BytePos,
                               to_pos: BytePos,
@@ -1404,8 +1425,7 @@ impl<'a> StringReader<'a> {
                 }
 
                 if self.is_eof() {
-                    let last_bpos = self.pos;
-                    self.fatal_span_(start_bpos, last_bpos, "unterminated raw string").raise();
+                    self.fail_unterminated_raw_string(start_bpos, hash_count);
                 } else if !self.ch_is('"') {
                     let last_bpos = self.pos;
                     let curr_char = self.ch.unwrap();
@@ -1421,8 +1441,7 @@ impl<'a> StringReader<'a> {
                 let mut valid = true;
                 'outer: loop {
                     if self.is_eof() {
-                        let last_bpos = self.pos;
-                        self.fatal_span_(start_bpos, last_bpos, "unterminated raw string").raise();
+                        self.fail_unterminated_raw_string(start_bpos, hash_count);
                     }
                     // if self.ch_is('"') {
                     // content_end_bpos = self.pos;
@@ -1636,8 +1655,7 @@ impl<'a> StringReader<'a> {
         }
 
         if self.is_eof() {
-            let pos = self.pos;
-            self.fatal_span_(start_bpos, pos, "unterminated raw string").raise();
+            self.fail_unterminated_raw_string(start_bpos, hash_count);
         } else if !self.ch_is('"') {
             let pos = self.pos;
             let ch = self.ch.unwrap();
@@ -1653,8 +1671,7 @@ impl<'a> StringReader<'a> {
         'outer: loop {
             match self.ch {
                 None => {
-                    let pos = self.pos;
-                    self.fatal_span_(start_bpos, pos, "unterminated raw string").raise()
+                    self.fail_unterminated_raw_string(start_bpos, hash_count);
                 }
                 Some('"') => {
                     content_end_bpos = self.pos;
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 92584f5b519..da2a22df997 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3114,7 +3114,7 @@ impl<'a> Parser<'a> {
                         let expr_str = self.sess.codemap().span_to_snippet(expr.span)
                                                 .unwrap_or(pprust::expr_to_string(&expr));
                         err.span_suggestion(expr.span,
-                                            &format!("try {} the casted value", op_verb),
+                                            &format!("try {} the cast value", op_verb),
                                             format!("({})", expr_str));
                         err.emit();
 
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index a7822414c69..8fd95aa1ca8 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -732,18 +732,13 @@ pub fn expand_preparsed_format_args(ecx: &mut ExtCtxt,
     let mut parser = parse::Parser::new(fmt_str);
     let mut pieces = vec![];
 
-    loop {
-        match parser.next() {
-            Some(mut piece) => {
-                if !parser.errors.is_empty() {
-                    break;
-                }
-                cx.verify_piece(&piece);
-                cx.resolve_name_inplace(&mut piece);
-                pieces.push(piece);
-            }
-            None => break,
+    while let Some(mut piece) = parser.next() {
+        if !parser.errors.is_empty() {
+            break;
         }
+        cx.verify_piece(&piece);
+        cx.resolve_name_inplace(&mut piece);
+        pieces.push(piece);
     }
 
     let numbered_position_args = pieces.iter().any(|arg: &parse::Piece| {
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 9f746adbe65..ed9eb5d5c92 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -322,12 +322,7 @@ impl Span {
     pub fn macro_backtrace(mut self) -> Vec<MacroBacktrace> {
         let mut prev_span = DUMMY_SP;
         let mut result = vec![];
-        loop {
-            let info = match self.ctxt().outer().expn_info() {
-                Some(info) => info,
-                None => break,
-            };
-
+        while let Some(info) = self.ctxt().outer().expn_info() {
             let (pre, post) = match info.callee.format {
                 ExpnFormat::MacroAttribute(..) => ("#[", "]"),
                 ExpnFormat::MacroBang(..) => ("", "!"),
diff --git a/src/test/codegen/abi-main-signature-16bit-c-int.rs b/src/test/codegen/abi-main-signature-16bit-c-int.rs
index fbe2fd10e7a..1e02fe4befd 100644
--- a/src/test/codegen/abi-main-signature-16bit-c-int.rs
+++ b/src/test/codegen/abi-main-signature-16bit-c-int.rs
@@ -18,7 +18,6 @@
 // ignore-hexagon
 // ignore-mips
 // ignore-powerpc
-// ignore-powerpc64
 // ignore-s390x
 // ignore-sparc
 // ignore-wasm32
diff --git a/src/test/codegen/fastcall-inreg.rs b/src/test/codegen/fastcall-inreg.rs
index 346c5da8d1b..b24899cc363 100644
--- a/src/test/codegen/fastcall-inreg.rs
+++ b/src/test/codegen/fastcall-inreg.rs
@@ -25,8 +25,6 @@
 // ignore-mips64
 // ignore-mips64el
 // ignore-msp430
-// ignore-powerpc64
-// ignore-powerpc64le
 // ignore-powerpc
 // ignore-r600
 // ignore-amdgcn
diff --git a/src/test/codegen/global_asm.rs b/src/test/codegen/global_asm.rs
index 5bd0c1b4076..5661592d0c7 100644
--- a/src/test/codegen/global_asm.rs
+++ b/src/test/codegen/global_asm.rs
@@ -21,8 +21,6 @@
 // ignore-mips64
 // ignore-mips64el
 // ignore-msp430
-// ignore-powerpc64
-// ignore-powerpc64le
 // ignore-powerpc
 // ignore-r600
 // ignore-amdgcn
diff --git a/src/test/codegen/global_asm_include.rs b/src/test/codegen/global_asm_include.rs
index 401b1fad566..d8b5db12404 100644
--- a/src/test/codegen/global_asm_include.rs
+++ b/src/test/codegen/global_asm_include.rs
@@ -21,8 +21,6 @@
 // ignore-mips64
 // ignore-mips64el
 // ignore-msp430
-// ignore-powerpc64
-// ignore-powerpc64le
 // ignore-powerpc
 // ignore-r600
 // ignore-amdgcn
diff --git a/src/test/codegen/global_asm_x2.rs b/src/test/codegen/global_asm_x2.rs
index 8b59165e9e6..caa0506550d 100644
--- a/src/test/codegen/global_asm_x2.rs
+++ b/src/test/codegen/global_asm_x2.rs
@@ -21,8 +21,6 @@
 // ignore-mips64
 // ignore-mips64el
 // ignore-msp430
-// ignore-powerpc64
-// ignore-powerpc64le
 // ignore-powerpc
 // ignore-r600
 // ignore-amdgcn
diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs
index 2eeed2b788c..655e67cf7ee 100644
--- a/src/test/codegen/repr-transparent-aggregates-1.rs
+++ b/src/test/codegen/repr-transparent-aggregates-1.rs
@@ -14,7 +14,6 @@
 // ignore-mips
 // ignore-mips64
 // ignore-powerpc
-// ignore-powerpc64
 // See repr-transparent.rs
 
 #![crate_type="lib"]
diff --git a/src/test/incremental/feature_gate.rs b/src/test/incremental/feature_gate.rs
new file mode 100644
index 00000000000..de2f9ab52f6
--- /dev/null
+++ b/src/test/incremental/feature_gate.rs
@@ -0,0 +1,23 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// This test makes sure that we detect changed feature gates.
+
+// revisions:rpass1 cfail2
+// compile-flags: -Z query-dep-graph
+
+#![feature(rustc_attrs)]
+#![cfg_attr(rpass1, feature(nll))]
+
+fn main() {
+    let mut v = vec![1];
+    v.push(v[0]);
+    //[cfail2]~^ ERROR cannot borrow
+}
diff --git a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs
index 9ebc438ad5a..fd8f7b9e384 100644
--- a/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs
+++ b/src/test/run-pass-fulldeps/auxiliary/procedural_mbe_matching.rs
@@ -41,7 +41,7 @@ fn expand_mbe_matches(cx: &mut ExtCtxt, _: Span, args: &[TokenTree])
     let mbe_matcher = quoted::parse(mbe_matcher.into_iter().collect(),
                                     true,
                                     cx.parse_sess,
-                                    &RefCell::new(Features::new()),
+                                    &Features::new(),
                                     &[]);
     let map = match TokenTree::parse(cx, &mbe_matcher, args.iter().cloned().collect()) {
         Success(map) => map,
diff --git a/src/test/run-pass/extern-types-pointer-cast.rs b/src/test/run-pass/extern-types-pointer-cast.rs
index 628a570665a..0dede8eb70d 100644
--- a/src/test/run-pass/extern-types-pointer-cast.rs
+++ b/src/test/run-pass/extern-types-pointer-cast.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// Test that pointers to extern types can be casted from/to usize,
+// Test that pointers to extern types can be cast from/to usize,
 // despite being !Sized.
 
 #![feature(extern_types)]
diff --git a/src/test/run-pass/intrinsics-integer.rs b/src/test/run-pass/intrinsics-integer.rs
index 4896f02da20..bfa3a1e128a 100644
--- a/src/test/run-pass/intrinsics-integer.rs
+++ b/src/test/run-pass/intrinsics-integer.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(intrinsics)]
+#![feature(intrinsics, i128_type)]
 
 mod rusti {
     extern "rust-intrinsic" {
@@ -18,6 +18,7 @@ mod rusti {
         pub fn cttz<T>(x: T) -> T;
         pub fn cttz_nonzero<T>(x: T) -> T;
         pub fn bswap<T>(x: T) -> T;
+        pub fn bitreverse<T>(x: T) -> T;
     }
 }
 
@@ -29,106 +30,127 @@ pub fn main() {
         assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0);
         assert_eq!(ctpop(0u32), 0); assert_eq!(ctpop(0i32), 0);
         assert_eq!(ctpop(0u64), 0); assert_eq!(ctpop(0i64), 0);
+        assert_eq!(ctpop(0u128), 0); assert_eq!(ctpop(0i128), 0);
 
         assert_eq!(ctpop(1u8), 1); assert_eq!(ctpop(1i8), 1);
         assert_eq!(ctpop(1u16), 1); assert_eq!(ctpop(1i16), 1);
         assert_eq!(ctpop(1u32), 1); assert_eq!(ctpop(1i32), 1);
         assert_eq!(ctpop(1u64), 1); assert_eq!(ctpop(1i64), 1);
+        assert_eq!(ctpop(1u128), 1); assert_eq!(ctpop(1i128), 1);
 
         assert_eq!(ctpop(10u8), 2); assert_eq!(ctpop(10i8), 2);
         assert_eq!(ctpop(10u16), 2); assert_eq!(ctpop(10i16), 2);
         assert_eq!(ctpop(10u32), 2); assert_eq!(ctpop(10i32), 2);
         assert_eq!(ctpop(10u64), 2); assert_eq!(ctpop(10i64), 2);
+        assert_eq!(ctpop(10u128), 2); assert_eq!(ctpop(10i128), 2);
 
         assert_eq!(ctpop(100u8), 3); assert_eq!(ctpop(100i8), 3);
         assert_eq!(ctpop(100u16), 3); assert_eq!(ctpop(100i16), 3);
         assert_eq!(ctpop(100u32), 3); assert_eq!(ctpop(100i32), 3);
         assert_eq!(ctpop(100u64), 3); assert_eq!(ctpop(100i64), 3);
+        assert_eq!(ctpop(100u128), 3); assert_eq!(ctpop(100i128), 3);
 
         assert_eq!(ctpop(-1i8 as u8), 8); assert_eq!(ctpop(-1i8), 8);
         assert_eq!(ctpop(-1i16 as u16), 16); assert_eq!(ctpop(-1i16), 16);
         assert_eq!(ctpop(-1i32 as u32), 32); assert_eq!(ctpop(-1i32), 32);
         assert_eq!(ctpop(-1i64 as u64), 64); assert_eq!(ctpop(-1i64), 64);
+        assert_eq!(ctpop(-1i128 as u128), 128); assert_eq!(ctpop(-1i128), 128);
 
         assert_eq!(ctlz(0u8), 8); assert_eq!(ctlz(0i8), 8);
         assert_eq!(ctlz(0u16), 16); assert_eq!(ctlz(0i16), 16);
         assert_eq!(ctlz(0u32), 32); assert_eq!(ctlz(0i32), 32);
         assert_eq!(ctlz(0u64), 64); assert_eq!(ctlz(0i64), 64);
+        assert_eq!(ctlz(0u128), 128); assert_eq!(ctlz(0i128), 128);
 
         assert_eq!(ctlz(1u8), 7); assert_eq!(ctlz(1i8), 7);
         assert_eq!(ctlz(1u16), 15); assert_eq!(ctlz(1i16), 15);
         assert_eq!(ctlz(1u32), 31); assert_eq!(ctlz(1i32), 31);
         assert_eq!(ctlz(1u64), 63); assert_eq!(ctlz(1i64), 63);
+        assert_eq!(ctlz(1u128), 127); assert_eq!(ctlz(1i128), 127);
 
         assert_eq!(ctlz(10u8), 4); assert_eq!(ctlz(10i8), 4);
         assert_eq!(ctlz(10u16), 12); assert_eq!(ctlz(10i16), 12);
         assert_eq!(ctlz(10u32), 28); assert_eq!(ctlz(10i32), 28);
         assert_eq!(ctlz(10u64), 60); assert_eq!(ctlz(10i64), 60);
+        assert_eq!(ctlz(10u128), 124); assert_eq!(ctlz(10i128), 124);
 
         assert_eq!(ctlz(100u8), 1); assert_eq!(ctlz(100i8), 1);
         assert_eq!(ctlz(100u16), 9); assert_eq!(ctlz(100i16), 9);
         assert_eq!(ctlz(100u32), 25); assert_eq!(ctlz(100i32), 25);
         assert_eq!(ctlz(100u64), 57); assert_eq!(ctlz(100i64), 57);
+        assert_eq!(ctlz(100u128), 121); assert_eq!(ctlz(100i128), 121);
 
         assert_eq!(ctlz_nonzero(1u8), 7); assert_eq!(ctlz_nonzero(1i8), 7);
         assert_eq!(ctlz_nonzero(1u16), 15); assert_eq!(ctlz_nonzero(1i16), 15);
         assert_eq!(ctlz_nonzero(1u32), 31); assert_eq!(ctlz_nonzero(1i32), 31);
         assert_eq!(ctlz_nonzero(1u64), 63); assert_eq!(ctlz_nonzero(1i64), 63);
+        assert_eq!(ctlz_nonzero(1u128), 127); assert_eq!(ctlz_nonzero(1i128), 127);
 
         assert_eq!(ctlz_nonzero(10u8), 4); assert_eq!(ctlz_nonzero(10i8), 4);
         assert_eq!(ctlz_nonzero(10u16), 12); assert_eq!(ctlz_nonzero(10i16), 12);
         assert_eq!(ctlz_nonzero(10u32), 28); assert_eq!(ctlz_nonzero(10i32), 28);
         assert_eq!(ctlz_nonzero(10u64), 60); assert_eq!(ctlz_nonzero(10i64), 60);
+        assert_eq!(ctlz_nonzero(10u128), 124); assert_eq!(ctlz_nonzero(10i128), 124);
 
         assert_eq!(ctlz_nonzero(100u8), 1); assert_eq!(ctlz_nonzero(100i8), 1);
         assert_eq!(ctlz_nonzero(100u16), 9); assert_eq!(ctlz_nonzero(100i16), 9);
         assert_eq!(ctlz_nonzero(100u32), 25); assert_eq!(ctlz_nonzero(100i32), 25);
         assert_eq!(ctlz_nonzero(100u64), 57); assert_eq!(ctlz_nonzero(100i64), 57);
+        assert_eq!(ctlz_nonzero(100u128), 121); assert_eq!(ctlz_nonzero(100i128), 121);
 
         assert_eq!(cttz(-1i8 as u8), 0); assert_eq!(cttz(-1i8), 0);
         assert_eq!(cttz(-1i16 as u16), 0); assert_eq!(cttz(-1i16), 0);
         assert_eq!(cttz(-1i32 as u32), 0); assert_eq!(cttz(-1i32), 0);
         assert_eq!(cttz(-1i64 as u64), 0); assert_eq!(cttz(-1i64), 0);
+        assert_eq!(cttz(-1i128 as u128), 0); assert_eq!(cttz(-1i128), 0);
 
         assert_eq!(cttz(0u8), 8); assert_eq!(cttz(0i8), 8);
         assert_eq!(cttz(0u16), 16); assert_eq!(cttz(0i16), 16);
         assert_eq!(cttz(0u32), 32); assert_eq!(cttz(0i32), 32);
         assert_eq!(cttz(0u64), 64); assert_eq!(cttz(0i64), 64);
+        assert_eq!(cttz(0u128), 128); assert_eq!(cttz(0i128), 128);
 
         assert_eq!(cttz(1u8), 0); assert_eq!(cttz(1i8), 0);
         assert_eq!(cttz(1u16), 0); assert_eq!(cttz(1i16), 0);
         assert_eq!(cttz(1u32), 0); assert_eq!(cttz(1i32), 0);
         assert_eq!(cttz(1u64), 0); assert_eq!(cttz(1i64), 0);
+        assert_eq!(cttz(1u128), 0); assert_eq!(cttz(1i128), 0);
 
         assert_eq!(cttz(10u8), 1); assert_eq!(cttz(10i8), 1);
         assert_eq!(cttz(10u16), 1); assert_eq!(cttz(10i16), 1);
         assert_eq!(cttz(10u32), 1); assert_eq!(cttz(10i32), 1);
         assert_eq!(cttz(10u64), 1); assert_eq!(cttz(10i64), 1);
+        assert_eq!(cttz(10u128), 1); assert_eq!(cttz(10i128), 1);
 
         assert_eq!(cttz(100u8), 2); assert_eq!(cttz(100i8), 2);
         assert_eq!(cttz(100u16), 2); assert_eq!(cttz(100i16), 2);
         assert_eq!(cttz(100u32), 2); assert_eq!(cttz(100i32), 2);
         assert_eq!(cttz(100u64), 2); assert_eq!(cttz(100i64), 2);
+        assert_eq!(cttz(100u128), 2); assert_eq!(cttz(100i128), 2);
 
         assert_eq!(cttz_nonzero(-1i8 as u8), 0); assert_eq!(cttz_nonzero(-1i8), 0);
         assert_eq!(cttz_nonzero(-1i16 as u16), 0); assert_eq!(cttz_nonzero(-1i16), 0);
         assert_eq!(cttz_nonzero(-1i32 as u32), 0); assert_eq!(cttz_nonzero(-1i32), 0);
         assert_eq!(cttz_nonzero(-1i64 as u64), 0); assert_eq!(cttz_nonzero(-1i64), 0);
+        assert_eq!(cttz_nonzero(-1i128 as u128), 0); assert_eq!(cttz_nonzero(-1i128), 0);
 
         assert_eq!(cttz_nonzero(1u8), 0); assert_eq!(cttz_nonzero(1i8), 0);
         assert_eq!(cttz_nonzero(1u16), 0); assert_eq!(cttz_nonzero(1i16), 0);
         assert_eq!(cttz_nonzero(1u32), 0); assert_eq!(cttz_nonzero(1i32), 0);
         assert_eq!(cttz_nonzero(1u64), 0); assert_eq!(cttz_nonzero(1i64), 0);
+        assert_eq!(cttz_nonzero(1u128), 0); assert_eq!(cttz_nonzero(1i128), 0);
 
         assert_eq!(cttz_nonzero(10u8), 1); assert_eq!(cttz_nonzero(10i8), 1);
         assert_eq!(cttz_nonzero(10u16), 1); assert_eq!(cttz_nonzero(10i16), 1);
         assert_eq!(cttz_nonzero(10u32), 1); assert_eq!(cttz_nonzero(10i32), 1);
         assert_eq!(cttz_nonzero(10u64), 1); assert_eq!(cttz_nonzero(10i64), 1);
+        assert_eq!(cttz_nonzero(10u128), 1); assert_eq!(cttz_nonzero(10i128), 1);
 
         assert_eq!(cttz_nonzero(100u8), 2); assert_eq!(cttz_nonzero(100i8), 2);
         assert_eq!(cttz_nonzero(100u16), 2); assert_eq!(cttz_nonzero(100i16), 2);
         assert_eq!(cttz_nonzero(100u32), 2); assert_eq!(cttz_nonzero(100i32), 2);
         assert_eq!(cttz_nonzero(100u64), 2); assert_eq!(cttz_nonzero(100i64), 2);
+        assert_eq!(cttz_nonzero(100u128), 2); assert_eq!(cttz_nonzero(100i128), 2);
 
         assert_eq!(bswap(0x0Au8), 0x0A); // no-op
         assert_eq!(bswap(0x0Ai8), 0x0A); // no-op
@@ -138,5 +160,18 @@ pub fn main() {
         assert_eq!(bswap(0x0ABBCC0Di32), 0x0DCCBB0A);
         assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201);
         assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201);
+        assert_eq!(bswap(0x0122334455667708u128), 0x08776655443322010000000000000000);
+        assert_eq!(bswap(0x0122334455667708i128), 0x08776655443322010000000000000000);
+
+        assert_eq!(bitreverse(0x0Au8), 0x50);
+        assert_eq!(bitreverse(0x0Ai8), 0x50);
+        assert_eq!(bitreverse(0x0A0Cu16), 0x3050);
+        assert_eq!(bitreverse(0x0A0Ci16), 0x3050);
+        assert_eq!(bitreverse(0x0ABBCC0Eu32), 0x7033DD50);
+        assert_eq!(bitreverse(0x0ABBCC0Ei32), 0x7033DD50);
+        assert_eq!(bitreverse(0x0122334455667708u64), 0x10EE66AA22CC4480);
+        assert_eq!(bitreverse(0x0122334455667708i64), 0x10EE66AA22CC4480);
+        assert_eq!(bitreverse(0x0122334455667708u128), 0x10EE66AA22CC44800000000000000000);
+        assert_eq!(bitreverse(0x0122334455667708i128), 0x10EE66AA22CC44800000000000000000);
     }
 }
diff --git a/src/test/run-pass/issue-36053.rs b/src/test/run-pass/issue-36053.rs
index 2411996cf05..ece58eedc56 100644
--- a/src/test/run-pass/issue-36053.rs
+++ b/src/test/run-pass/issue-36053.rs
@@ -14,7 +14,6 @@
 // `FusedIterator` in std but I was not able to isolate that into an
 // external crate.
 
-#![feature(fused)]
 use std::iter::FusedIterator;
 
 struct Thing<'a>(&'a str);
diff --git a/src/test/ui/cast_char.rs b/src/test/ui/cast_char.rs
index cd8ade5e51a..4dfa5037bc5 100644
--- a/src/test/ui/cast_char.rs
+++ b/src/test/ui/cast_char.rs
@@ -12,9 +12,9 @@
 
 fn main() {
     const XYZ: char = 0x1F888 as char;
-    //~^ ERROR only u8 can be casted into char
+    //~^ ERROR only u8 can be cast into char
     const XY: char = 129160 as char;
-    //~^ ERROR only u8 can be casted into char
+    //~^ ERROR only u8 can be cast into char
     const ZYX: char = '\u{01F888}';
     println!("{}", XYZ);
 }
diff --git a/src/test/ui/cast_char.stderr b/src/test/ui/cast_char.stderr
index 481715fd9ce..600d7e61a09 100644
--- a/src/test/ui/cast_char.stderr
+++ b/src/test/ui/cast_char.stderr
@@ -1,4 +1,4 @@
-error: only u8 can be casted into char
+error: only u8 can be cast into char
   --> $DIR/cast_char.rs:14:23
    |
 LL |     const XYZ: char = 0x1F888 as char;
@@ -10,7 +10,7 @@ note: lint level defined here
 LL | #![deny(overflowing_literals)]
    |         ^^^^^^^^^^^^^^^^^^^^
 
-error: only u8 can be casted into char
+error: only u8 can be cast into char
   --> $DIR/cast_char.rs:16:22
    |
 LL |     const XY: char = 129160 as char;
diff --git a/src/test/ui/issue-22644.stderr b/src/test/ui/issue-22644.stderr
index d5e87f89417..257b9bd235d 100644
--- a/src/test/ui/issue-22644.stderr
+++ b/src/test/ui/issue-22644.stderr
@@ -5,7 +5,7 @@ LL |     println!("{}", a as usize < long_name); //~ ERROR `<` is interpreted as
    |                    ---------- ^ --------- interpreted as generic arguments
    |                    |          |
    |                    |          not interpreted as comparison
-   |                    help: try comparing the casted value: `(a as usize)`
+   |                    help: try comparing the cast value: `(a as usize)`
 
 error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
   --> $DIR/issue-22644.rs:17:33
@@ -14,7 +14,7 @@ LL |     println!("{}{}", a as usize < long_name, long_name);
    |                      ---------- ^ -------------------- interpreted as generic arguments
    |                      |          |
    |                      |          not interpreted as comparison
-   |                      help: try comparing the casted value: `(a as usize)`
+   |                      help: try comparing the cast value: `(a as usize)`
 
 error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
   --> $DIR/issue-22644.rs:19:31
@@ -23,7 +23,7 @@ LL |     println!("{}", a as usize < 4); //~ ERROR `<` is interpreted as a start
    |                    ---------- ^ - interpreted as generic arguments
    |                    |          |
    |                    |          not interpreted as comparison
-   |                    help: try comparing the casted value: `(a as usize)`
+   |                    help: try comparing the cast value: `(a as usize)`
 
 error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
   --> $DIR/issue-22644.rs:21:31
@@ -32,7 +32,7 @@ LL |     println!("{}{}", a: usize < long_name, long_name);
    |                      -------- ^ -------------------- interpreted as generic arguments
    |                      |        |
    |                      |        not interpreted as comparison
-   |                      help: try comparing the casted value: `(a: usize)`
+   |                      help: try comparing the cast value: `(a: usize)`
 
 error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
   --> $DIR/issue-22644.rs:23:29
@@ -41,7 +41,7 @@ LL |     println!("{}", a: usize < 4); //~ ERROR `<` is interpreted as a start o
    |                    -------- ^ - interpreted as generic arguments
    |                    |        |
    |                    |        not interpreted as comparison
-   |                    help: try comparing the casted value: `(a: usize)`
+   |                    help: try comparing the cast value: `(a: usize)`
 
 error: `<` is interpreted as a start of generic arguments for `usize`, not a comparison
   --> $DIR/issue-22644.rs:28:20
@@ -50,7 +50,7 @@ LL |                    < //~ ERROR `<` is interpreted as a start of generic
    |                    ^ not interpreted as comparison
 LL |                    4);
    |                    - interpreted as generic arguments
-help: try comparing the casted value
+help: try comparing the cast value
    |
 LL |     println!("{}", (a
 LL |                    as
@@ -64,7 +64,7 @@ LL |                    < //~ ERROR `<` is interpreted as a start of generic
    |                    ^ not interpreted as comparison
 LL |                    5);
    |                    - interpreted as generic arguments
-help: try comparing the casted value
+help: try comparing the cast value
    |
 LL |     println!("{}", (a
 LL | 
@@ -81,7 +81,7 @@ LL |     println!("{}", a as usize << long_name); //~ ERROR `<` is interpreted a
    |                    ---------- ^^ --------- interpreted as generic arguments
    |                    |          |
    |                    |          not interpreted as shift
-   |                    help: try shifting the casted value: `(a as usize)`
+   |                    help: try shifting the cast value: `(a as usize)`
 
 error: expected type, found `4`
   --> $DIR/issue-22644.rs:42:28
diff --git a/src/test/ui/issue-42954.stderr b/src/test/ui/issue-42954.stderr
index 1a3984181f6..9164434006f 100644
--- a/src/test/ui/issue-42954.stderr
+++ b/src/test/ui/issue-42954.stderr
@@ -5,7 +5,7 @@ LL |         $i as u32 < 0 //~ `<` is interpreted as a start of generic argument
    |         --------- ^ - interpreted as generic arguments
    |         |         |
    |         |         not interpreted as comparison
-   |         help: try comparing the casted value: `($i as u32)`
+   |         help: try comparing the cast value: `($i as u32)`
 ...
 LL |     is_plainly_printable!(c);
    |     ------------------------- in this macro invocation
diff --git a/src/test/ui/lint/type-overflow.rs b/src/test/ui/lint/type-overflow.rs
new file mode 100644
index 00000000000..495989587e5
--- /dev/null
+++ b/src/test/ui/lint/type-overflow.rs
@@ -0,0 +1,33 @@
+// Copyright 2018 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.
+
+// must-compile-successfully
+
+#![feature(i128_type)]
+
+fn main() {
+    let error = 255i8; //~WARNING literal out of range for i8
+
+    let ok = 0b1000_0001; // should be ok -> i32
+    let ok = 0b0111_1111i8; // should be ok -> 127i8
+
+    let fail = 0b1000_0001i8; //~WARNING literal out of range for i8
+
+    let fail = 0x8000_0000_0000_0000i64; //~WARNING literal out of range for i64
+
+    let fail = 0x1_FFFF_FFFFu32; //~WARNING literal out of range for u32
+
+    let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
+    //~^ WARNING literal out of range for i128
+
+    let fail = 0x8FFF_FFFF_FFFF_FFFE; //~WARNING literal out of range for i32
+
+    let fail = -0b1111_1111i8; //~WARNING literal out of range for i8
+}
diff --git a/src/test/ui/lint/type-overflow.stderr b/src/test/ui/lint/type-overflow.stderr
new file mode 100644
index 00000000000..d3fcb1335e2
--- /dev/null
+++ b/src/test/ui/lint/type-overflow.stderr
@@ -0,0 +1,58 @@
+warning: literal out of range for i8
+  --> $DIR/type-overflow.rs:16:17
+   |
+LL |     let error = 255i8; //~WARNING literal out of range for i8
+   |                 ^^^^^
+   |
+   = note: #[warn(overflowing_literals)] on by default
+
+warning: literal out of range for i8
+  --> $DIR/type-overflow.rs:21:16
+   |
+LL |     let fail = 0b1000_0001i8; //~WARNING literal out of range for i8
+   |                ^^^^^^^^^^^^^ help: consider using `u8` instead: `0b1000_0001u8`
+   |
+   = note: the literal `0b1000_0001i8` (decimal `129`) does not fit into an `i8` and will become `-127i8`
+
+warning: literal out of range for i64
+  --> $DIR/type-overflow.rs:23:16
+   |
+LL |     let fail = 0x8000_0000_0000_0000i64; //~WARNING literal out of range for i64
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `u64` instead: `0x8000_0000_0000_0000u64`
+   |
+   = note: the literal `0x8000_0000_0000_0000i64` (decimal `9223372036854775808`) does not fit into an `i64` and will become `-9223372036854775808i64`
+
+warning: literal out of range for u32
+  --> $DIR/type-overflow.rs:25:16
+   |
+LL |     let fail = 0x1_FFFF_FFFFu32; //~WARNING literal out of range for u32
+   |                ^^^^^^^^^^^^^^^^ help: consider using `u64` instead: `0x1_FFFF_FFFFu64`
+   |
+   = note: the literal `0x1_FFFF_FFFFu32` (decimal `8589934591`) does not fit into an `u32` and will become `4294967295u32`
+
+warning: literal out of range for i128
+  --> $DIR/type-overflow.rs:27:22
+   |
+LL |     let fail: i128 = 0x8000_0000_0000_0000_0000_0000_0000_0000;
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the literal `0x8000_0000_0000_0000_0000_0000_0000_0000` (decimal `170141183460469231731687303715884105728`) does not fit into an `i128` and will become `-170141183460469231731687303715884105728i128`
+   = help: consider using `u128` instead
+
+warning: literal out of range for i32
+  --> $DIR/type-overflow.rs:30:16
+   |
+LL |     let fail = 0x8FFF_FFFF_FFFF_FFFE; //~WARNING literal out of range for i32
+   |                ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: the literal `0x8FFF_FFFF_FFFF_FFFE` (decimal `10376293541461622782`) does not fit into an `i32` and will become `-2i32`
+   = help: consider using `i128` instead
+
+warning: literal out of range for i8
+  --> $DIR/type-overflow.rs:32:17
+   |
+LL |     let fail = -0b1111_1111i8; //~WARNING literal out of range for i8
+   |                 ^^^^^^^^^^^^^ help: consider using `i16` instead: `0b1111_1111i16`
+   |
+   = note: the literal `0b1111_1111i8` (decimal `255`) does not fit into an `i8` and will become `-1i8`
+
diff --git a/src/test/ui/nll/borrowed-local-error.rs b/src/test/ui/nll/borrowed-local-error.rs
new file mode 100644
index 00000000000..785a38da959
--- /dev/null
+++ b/src/test/ui/nll/borrowed-local-error.rs
@@ -0,0 +1,26 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Znll-dump-cause
+
+#![feature(nll)]
+
+fn gimme(x: &(u32,)) -> &u32 {
+    &x.0
+}
+
+fn main() {
+    let x = gimme({
+        let v = (22,);
+        &v
+        //~^ ERROR `v` does not live long enough [E0597]
+    });
+    println!("{:?}", x);
+}
diff --git a/src/test/ui/nll/borrowed-local-error.stderr b/src/test/ui/nll/borrowed-local-error.stderr
new file mode 100644
index 00000000000..3bc19785548
--- /dev/null
+++ b/src/test/ui/nll/borrowed-local-error.stderr
@@ -0,0 +1,17 @@
+error[E0597]: `v` does not live long enough
+  --> $DIR/borrowed-local-error.rs:22:9
+   |
+LL |       let x = gimme({
+   |  _____________-
+LL | |         let v = (22,);
+LL | |         &v
+   | |         ^^ borrowed value does not live long enough
+LL | |         //~^ ERROR `v` does not live long enough [E0597]
+LL | |     });
+   | |_____-- borrow later used here
+   |       |
+   |       borrowed value only lives until here
+
+error: aborting due to previous error
+
+If you want more information on this error, try using "rustc --explain E0597"
diff --git a/src/test/ui/nll/borrowed-temporary-error.rs b/src/test/ui/nll/borrowed-temporary-error.rs
new file mode 100644
index 00000000000..e1a6112d173
--- /dev/null
+++ b/src/test/ui/nll/borrowed-temporary-error.rs
@@ -0,0 +1,26 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Znll-dump-cause
+
+#![feature(nll)]
+
+fn gimme(x: &(u32,)) -> &u32 {
+    &x.0
+}
+
+fn main() {
+    let x = gimme({
+        let v = 22;
+        &(v,)
+        //~^ ERROR borrowed value does not live long enough [E0597]
+    });
+    println!("{:?}", x);
+}
diff --git a/src/test/ui/nll/borrowed-temporary-error.stderr b/src/test/ui/nll/borrowed-temporary-error.stderr
new file mode 100644
index 00000000000..f5cb1dccc37
--- /dev/null
+++ b/src/test/ui/nll/borrowed-temporary-error.stderr
@@ -0,0 +1,14 @@
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/borrowed-temporary-error.rs:22:10
+   |
+LL |         &(v,)
+   |          ^^^^ temporary value does not live long enough
+LL |         //~^ ERROR borrowed value does not live long enough [E0597]
+LL |     });
+   |       - temporary value only lives until here
+LL |     println!("{:?}", x);
+   |                      - borrow later used here
+
+error: aborting due to previous error
+
+If you want more information on this error, try using "rustc --explain E0597"
diff --git a/src/test/ui/nll/borrowed-universal-error-2.rs b/src/test/ui/nll/borrowed-universal-error-2.rs
new file mode 100644
index 00000000000..da03a9fc39b
--- /dev/null
+++ b/src/test/ui/nll/borrowed-universal-error-2.rs
@@ -0,0 +1,22 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Znll-dump-cause
+
+#![feature(nll)]
+#![allow(warnings)]
+
+fn foo<'a>(x: &'a (u32,)) -> &'a u32 {
+    let v = 22;
+    &v
+    //~^ ERROR `v` does not live long enough [E0597]
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/borrowed-universal-error-2.stderr b/src/test/ui/nll/borrowed-universal-error-2.stderr
new file mode 100644
index 00000000000..ff999a71e0f
--- /dev/null
+++ b/src/test/ui/nll/borrowed-universal-error-2.stderr
@@ -0,0 +1,18 @@
+error[E0597]: `v` does not live long enough
+  --> $DIR/borrowed-universal-error-2.rs:18:5
+   |
+LL |     &v
+   |     ^^ borrowed value does not live long enough
+LL |     //~^ ERROR `v` does not live long enough [E0597]
+LL | }
+   | - borrowed value only lives until here
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 16:1...
+  --> $DIR/borrowed-universal-error-2.rs:16:1
+   |
+LL | fn foo<'a>(x: &'a (u32,)) -> &'a u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+If you want more information on this error, try using "rustc --explain E0597"
diff --git a/src/test/ui/nll/borrowed-universal-error.rs b/src/test/ui/nll/borrowed-universal-error.rs
new file mode 100644
index 00000000000..fdc4c29071e
--- /dev/null
+++ b/src/test/ui/nll/borrowed-universal-error.rs
@@ -0,0 +1,26 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Znll-dump-cause
+
+#![feature(nll)]
+#![allow(warnings)]
+
+fn gimme(x: &(u32,)) -> &u32 {
+    &x.0
+}
+
+fn foo<'a>(x: &'a (u32,)) -> &'a u32 {
+    let v = 22;
+    gimme(&(v,))
+    //~^ ERROR borrowed value does not live long enough [E0597]
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/borrowed-universal-error.stderr b/src/test/ui/nll/borrowed-universal-error.stderr
new file mode 100644
index 00000000000..4a3d0c6d959
--- /dev/null
+++ b/src/test/ui/nll/borrowed-universal-error.stderr
@@ -0,0 +1,18 @@
+error[E0597]: borrowed value does not live long enough
+  --> $DIR/borrowed-universal-error.rs:22:12
+   |
+LL |     gimme(&(v,))
+   |            ^^^^ temporary value does not live long enough
+LL |     //~^ ERROR borrowed value does not live long enough [E0597]
+LL | }
+   | - temporary value only lives until here
+   |
+note: borrowed value must be valid for the lifetime 'a as defined on the function body at 20:1...
+  --> $DIR/borrowed-universal-error.rs:20:1
+   |
+LL | fn foo<'a>(x: &'a (u32,)) -> &'a u32 {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+If you want more information on this error, try using "rustc --explain E0597"
diff --git a/src/test/ui/nll/capture-ref-in-struct.stderr b/src/test/ui/nll/capture-ref-in-struct.stderr
index 316a918e4ee..1c545906893 100644
--- a/src/test/ui/nll/capture-ref-in-struct.stderr
+++ b/src/test/ui/nll/capture-ref-in-struct.stderr
@@ -9,8 +9,6 @@ LL |     }
 LL | 
 LL |     deref(p);
    |           - borrow later used here
-   |
-   = note: borrowed value must be valid for lifetime '_#5r...
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr
index 93a7bab3386..18ffdc58349 100644
--- a/src/test/ui/nll/closure-requirements/escape-argument.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr
@@ -34,8 +34,6 @@ LL |     }
 LL | 
 LL |     deref(p);
    |           - borrow later used here
-   |
-   = note: borrowed value must be valid for lifetime '_#6r...
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
index b6c1d808ff5..7b2b2f74872 100644
--- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr
@@ -61,8 +61,6 @@ LL |       }
 LL | 
 LL |       deref(p);
    |             - borrow later used here
-   |
-   = note: borrowed value must be valid for lifetime '_#4r...
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
index 3cb6524f3b4..0a45603a42c 100644
--- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
+++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr
@@ -38,8 +38,6 @@ LL |     }
 LL | 
 LL |     deref(p);
    |           - borrow later used here
-   |
-   = note: borrowed value must be valid for lifetime '_#4r...
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
index eb4d264bf82..21ed421fe96 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr
@@ -78,8 +78,6 @@ LL |     let cell = Cell::new(&a);
 ...
 LL | }
    | - borrowed value only lives until here
-   |
-   = note: borrowed value must be valid for lifetime '_#2r...
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/return-ref-mut-issue-46557.stderr b/src/test/ui/nll/return-ref-mut-issue-46557.stderr
index f7e85e4277b..c77e0772ce9 100644
--- a/src/test/ui/nll/return-ref-mut-issue-46557.stderr
+++ b/src/test/ui/nll/return-ref-mut-issue-46557.stderr
@@ -6,8 +6,6 @@ LL |     let ref mut x = 1234543; //~ ERROR borrowed value does not live long en
 LL |     x
 LL | }
    | - temporary value only lives until here
-   |
-   = note: borrowed value must be valid for lifetime '_#2r...
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/raw_string.rs b/src/test/ui/raw_string.rs
new file mode 100644
index 00000000000..f1eb91d44fd
--- /dev/null
+++ b/src/test/ui/raw_string.rs
@@ -0,0 +1,14 @@
+// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+    let x = r##"lol"#;
+    //~^ ERROR unterminated raw string
+}
diff --git a/src/test/ui/raw_string.stderr b/src/test/ui/raw_string.stderr
new file mode 100644
index 00000000000..b8aa596ef95
--- /dev/null
+++ b/src/test/ui/raw_string.stderr
@@ -0,0 +1,8 @@
+error: unterminated raw string
+  --> $DIR/raw_string.rs:12:13
+   |
+LL |     let x = r##"lol"#;
+   |             ^ unterminated raw string
+   |
+   = note: this raw string should be terminated with `"##`
+
diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs
index 3c9dae915b5..cf63cb2e5d9 100644
--- a/src/tools/compiletest/src/util.rs
+++ b/src/tools/compiletest/src/util.rs
@@ -43,7 +43,6 @@ const ARCH_TABLE: &'static [(&'static str, &'static str)] = &[
     ("mips", "mips"),
     ("msp430", "msp430"),
     ("powerpc", "powerpc"),
-    ("powerpc64", "powerpc64"),
     ("s390x", "s390x"),
     ("sparc", "sparc"),
     ("x86_64", "x86_64"),
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index 664aecfcbdb..f7b491823f8 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -2,3 +2,8 @@
 name = "tidy"
 version = "0.1.0"
 authors = ["Alex Crichton <alex@alexcrichton.com>"]
+
+[dependencies]
+serde = "1.0.8"
+serde_derive = "1.0.8"
+serde_json = "1.0.2"
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 4dedf6bfe77..f40c7a72a45 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -10,9 +10,13 @@
 
 //! Check license of third-party deps by inspecting src/vendor
 
+use std::collections::{BTreeSet, HashSet};
 use std::fs::File;
 use std::io::Read;
 use std::path::Path;
+use std::process::Command;
+
+use serde_json;
 
 static LICENSES: &'static [&'static str] = &[
     "MIT/Apache-2.0",
@@ -24,52 +28,182 @@ static LICENSES: &'static [&'static str] = &[
     "Unlicense/MIT",
 ];
 
-// These are exceptions to Rust's permissive licensing policy, and
-// should be considered bugs. Exceptions are only allowed in Rust
-// tooling. It is _crucial_ that no exception crates be dependencies
-// of the Rust runtime (std / test).
+/// These are exceptions to Rust's permissive licensing policy, and
+/// should be considered bugs. Exceptions are only allowed in Rust
+/// tooling. It is _crucial_ that no exception crates be dependencies
+/// of the Rust runtime (std / test).
 static EXCEPTIONS: &'static [&'static str] = &[
-    "mdbook", // MPL2, mdbook
-    "openssl", // BSD+advertising clause, cargo, mdbook
-    "pest", // MPL2, mdbook via handlebars
-    "thread-id", // Apache-2.0, mdbook
-    "toml-query", // MPL-2.0, mdbook
-    "is-match", // MPL-2.0, mdbook
-    "cssparser", // MPL-2.0, rustdoc
-    "smallvec", // MPL-2.0, rustdoc
+    "mdbook",             // MPL2, mdbook
+    "openssl",            // BSD+advertising clause, cargo, mdbook
+    "pest",               // MPL2, mdbook via handlebars
+    "thread-id",          // Apache-2.0, mdbook
+    "toml-query",         // MPL-2.0, mdbook
+    "is-match",           // MPL-2.0, mdbook
+    "cssparser",          // MPL-2.0, rustdoc
+    "smallvec",           // MPL-2.0, rustdoc
     "fuchsia-zircon-sys", // BSD-3-Clause, rustdoc, rustc, cargo
-    "fuchsia-zircon", // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
-    "cssparser-macros", // MPL-2.0, rustdoc
-    "selectors", // MPL-2.0, rustdoc
-    "clippy_lints", // MPL-2.0 rls
+    "fuchsia-zircon",     // BSD-3-Clause, rustdoc, rustc, cargo (jobserver & tempdir)
+    "cssparser-macros",   // MPL-2.0, rustdoc
+    "selectors",          // MPL-2.0, rustdoc
+    "clippy_lints",       // MPL-2.0 rls
+];
+
+/// Which crates to check against the whitelist?
+static WHITELIST_CRATES: &'static [CrateVersion] = &[
+    CrateVersion("rustc", "0.0.0"),
+    CrateVersion("rustc_trans", "0.0.0"),
 ];
 
+/// Whitelist of crates rustc is allowed to depend on. Avoid adding to the list if possible.
+static WHITELIST: &'static [Crate] = &[
+    Crate("ar"),
+    Crate("backtrace"),
+    Crate("backtrace-sys"),
+    Crate("bitflags"),
+    Crate("byteorder"),
+    Crate("cc"),
+    Crate("cfg-if"),
+    Crate("cmake"),
+    Crate("ena"),
+    Crate("filetime"),
+    Crate("flate2"),
+    Crate("fuchsia-zircon"),
+    Crate("fuchsia-zircon-sys"),
+    Crate("jobserver"),
+    Crate("kernel32-sys"),
+    Crate("lazy_static"),
+    Crate("libc"),
+    Crate("log"),
+    Crate("log_settings"),
+    Crate("miniz-sys"),
+    Crate("num_cpus"),
+    Crate("owning_ref"),
+    Crate("parking_lot"),
+    Crate("parking_lot_core"),
+    Crate("rand"),
+    Crate("redox_syscall"),
+    Crate("rustc-demangle"),
+    Crate("smallvec"),
+    Crate("stable_deref_trait"),
+    Crate("tempdir"),
+    Crate("unicode-width"),
+    Crate("winapi"),
+    Crate("winapi-build"),
+    Crate("winapi-i686-pc-windows-gnu"),
+    Crate("winapi-x86_64-pc-windows-gnu"),
+];
+
+// Some types for Serde to deserialize the output of `cargo metadata` to...
+
+#[derive(Deserialize)]
+struct Output {
+    resolve: Resolve,
+}
+
+#[derive(Deserialize)]
+struct Resolve {
+    nodes: Vec<ResolveNode>,
+}
+
+#[derive(Deserialize)]
+struct ResolveNode {
+    id: String,
+    dependencies: Vec<String>,
+}
+
+/// A unique identifier for a crate
+#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
+struct Crate<'a>(&'a str); // (name,)
+
+#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug, Hash)]
+struct CrateVersion<'a>(&'a str, &'a str); // (name, version)
+
+impl<'a> Crate<'a> {
+    pub fn id_str(&self) -> String {
+        format!("{} ", self.0)
+    }
+}
+
+impl<'a> CrateVersion<'a> {
+    /// Returns the struct and whether or not the dep is in-tree
+    pub fn from_str(s: &'a str) -> (Self, bool) {
+        let mut parts = s.split(" ");
+        let name = parts.next().unwrap();
+        let version = parts.next().unwrap();
+        let path = parts.next().unwrap();
+
+        let is_path_dep = path.starts_with("(path+");
+
+        (CrateVersion(name, version), is_path_dep)
+    }
+
+    pub fn id_str(&self) -> String {
+        format!("{} {}", self.0, self.1)
+    }
+}
+
+impl<'a> From<CrateVersion<'a>> for Crate<'a> {
+    fn from(cv: CrateVersion<'a>) -> Crate<'a> {
+        Crate(cv.0)
+    }
+}
+
+/// Checks the dependency at the given path. Changes `bad` to `true` if a check failed.
+///
+/// Specifically, this checks that the license is correct.
 pub fn check(path: &Path, bad: &mut bool) {
+    // Check licences
     let path = path.join("vendor");
     assert!(path.exists(), "vendor directory missing");
     let mut saw_dir = false;
-    'next_path: for dir in t!(path.read_dir()) {
+    for dir in t!(path.read_dir()) {
         saw_dir = true;
         let dir = t!(dir);
 
         // skip our exceptions
-        for exception in EXCEPTIONS {
-            if dir.path()
+        if EXCEPTIONS.iter().any(|exception| {
+            dir.path()
                 .to_str()
                 .unwrap()
-                .contains(&format!("src/vendor/{}", exception)) {
-                continue 'next_path;
-            }
+                .contains(&format!("src/vendor/{}", exception))
+        }) {
+            continue;
         }
 
         let toml = dir.path().join("Cargo.toml");
-        if !check_license(&toml) {
-            *bad = true;
-        }
+        *bad = *bad || !check_license(&toml);
     }
     assert!(saw_dir, "no vendored source");
 }
 
+/// Checks the dependency of WHITELIST_CRATES at the given path. Changes `bad` to `true` if a check
+/// failed.
+///
+/// Specifically, this checks that the dependencies are on the WHITELIST.
+pub fn check_whitelist(path: &Path, cargo: &Path, bad: &mut bool) {
+    // Get dependencies from cargo metadata
+    let resolve = get_deps(path, cargo);
+
+    // Get the whitelist into a convenient form
+    let whitelist: HashSet<_> = WHITELIST.iter().cloned().collect();
+
+    // Check dependencies
+    let mut visited = BTreeSet::new();
+    let mut unapproved = BTreeSet::new();
+    for &krate in WHITELIST_CRATES.iter() {
+        let mut bad = check_crate_whitelist(&whitelist, &resolve, &mut visited, krate, false);
+        unapproved.append(&mut bad);
+    }
+
+    if unapproved.len() > 0 {
+        println!("Dependencies not on the whitelist:");
+        for dep in unapproved {
+            println!("* {}", dep.id_str());
+        }
+        *bad = true;
+    }
+}
+
 fn check_license(path: &Path) -> bool {
     if !path.exists() {
         panic!("{} does not exist", path.display());
@@ -102,9 +236,71 @@ fn extract_license(line: &str) -> String {
     let first_quote = line.find('"');
     let last_quote = line.rfind('"');
     if let (Some(f), Some(l)) = (first_quote, last_quote) {
-        let license = &line[f + 1 .. l];
+        let license = &line[f + 1..l];
         license.into()
     } else {
         "bad-license-parse".into()
     }
 }
+
+/// Get the dependencies of the crate at the given path using `cargo metadata`.
+fn get_deps(path: &Path, cargo: &Path) -> Resolve {
+    // Run `cargo metadata` to get the set of dependencies
+    let output = Command::new(cargo)
+        .arg("metadata")
+        .arg("--format-version")
+        .arg("1")
+        .arg("--manifest-path")
+        .arg(path.join("Cargo.toml"))
+        .output()
+        .expect("Unable to run `cargo metadata`")
+        .stdout;
+    let output = String::from_utf8_lossy(&output);
+    let output: Output = serde_json::from_str(&output).unwrap();
+
+    output.resolve
+}
+
+/// Checks the dependencies of the given crate from the given cargo metadata to see if they are on
+/// the whitelist. Returns a list of illegal dependencies.
+fn check_crate_whitelist<'a, 'b>(
+    whitelist: &'a HashSet<Crate>,
+    resolve: &'a Resolve,
+    visited: &'b mut BTreeSet<CrateVersion<'a>>,
+    krate: CrateVersion<'a>,
+    must_be_on_whitelist: bool,
+) -> BTreeSet<Crate<'a>> {
+    // Will contain bad deps
+    let mut unapproved = BTreeSet::new();
+
+    // Check if we have already visited this crate
+    if visited.contains(&krate) {
+        return unapproved;
+    }
+
+    visited.insert(krate);
+
+    // If this path is in-tree, we don't require it to be on the whitelist
+    if must_be_on_whitelist {
+        // If this dependency is not on the WHITELIST, add to bad set
+        if !whitelist.contains(&krate.into()) {
+            unapproved.insert(krate.into());
+        }
+    }
+
+    // Do a DFS in the crate graph (it's a DAG, so we know we have no cycles!)
+    let to_check = resolve
+        .nodes
+        .iter()
+        .find(|n| n.id.starts_with(&krate.id_str()))
+        .expect("crate does not exist");
+
+    for dep in to_check.dependencies.iter() {
+        let (krate, is_path_dep) = CrateVersion::from_str(dep);
+
+        let mut bad = check_crate_whitelist(whitelist, resolve, visited, krate, !is_path_dep);
+        unapproved.append(&mut bad);
+    }
+
+    unapproved
+}
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index 5134c869912..c927ff19b27 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -15,6 +15,11 @@
 
 #![deny(warnings)]
 
+extern crate serde;
+extern crate serde_json;
+#[macro_use]
+extern crate serde_derive;
+
 use std::fs;
 
 use std::path::Path;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index f6640c902bc..afa3ebd1983 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -24,9 +24,12 @@ use std::path::PathBuf;
 use std::env;
 
 fn main() {
-    let path = env::args_os().skip(1).next().expect("need an argument");
+    let path = env::args_os().skip(1).next().expect("need path to src");
     let path = PathBuf::from(path);
 
+    let cargo = env::args_os().skip(2).next().expect("need path to cargo");
+    let cargo = PathBuf::from(cargo);
+
     let args: Vec<String> = env::args().skip(1).collect();
 
     let mut bad = false;
@@ -41,6 +44,7 @@ fn main() {
     if !args.iter().any(|s| *s == "--no-vendor") {
         deps::check(&path, &mut bad);
     }
+    deps::check_whitelist(&path, &cargo, &mut bad);
 
     if bad {
         eprintln!("some tidy checks failed");