about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2017-04-07 07:19:44 -0700
committerEsteban Küber <esteban@kuber.com.ar>2017-04-07 14:55:45 -0700
commit8c31412c2f84c7d76602b2598c5c1352da61d022 (patch)
treecbc08b79f16f1533e27d84dee16e90f9f319a679
parentb83352e44c36e81db7f00eb60e78ff3828c51c9e (diff)
parent4c59c92bc4d4d6e5b2b66c4cc08dd1a058283a0d (diff)
downloadrust-8c31412c2f84c7d76602b2598c5c1352da61d022.tar.gz
rust-8c31412c2f84c7d76602b2598c5c1352da61d022.zip
Merge branch 'master' into ty-placeholder
-rw-r--r--.gitmodules2
-rw-r--r--.travis.yml22
-rw-r--r--appveyor.yml4
m---------cargo0
-rw-r--r--src/bootstrap/bootstrap.py18
-rw-r--r--src/bootstrap/clean.rs42
-rw-r--r--src/bootstrap/flags.rs286
-rw-r--r--src/bootstrap/install.rs9
-rw-r--r--src/bootstrap/step.rs11
-rw-r--r--src/ci/docker/armhf-gnu/Dockerfile2
-rw-r--r--src/ci/docker/cross/Dockerfile2
-rw-r--r--src/ci/docker/dist-aarch64-linux/Dockerfile (renamed from src/ci/docker/dist-armv7-aarch64-linux/Dockerfile)14
-rw-r--r--src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config (renamed from src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config)0
-rwxr-xr-xsrc/ci/docker/dist-aarch64-linux/build-toolchains.sh37
-rw-r--r--src/ci/docker/dist-android/Dockerfile2
-rw-r--r--src/ci/docker/dist-arm-linux/Dockerfile11
-rwxr-xr-xsrc/ci/docker/dist-arm-linux/build-toolchains.sh8
-rw-r--r--src/ci/docker/dist-armhf-linux/Dockerfile77
-rw-r--r--src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config (renamed from src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config)0
-rwxr-xr-xsrc/ci/docker/dist-armhf-linux/build-toolchains.sh37
-rw-r--r--src/ci/docker/dist-armv7-linux/Dockerfile77
-rw-r--r--src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config (renamed from src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config)0
-rwxr-xr-xsrc/ci/docker/dist-armv7-linux/build-toolchains.sh (renamed from src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh)8
-rw-r--r--src/ci/docker/dist-fuchsia/Dockerfile2
-rw-r--r--src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile2
-rw-r--r--src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh9
-rw-r--r--src/ci/docker/dist-i686-freebsd/Dockerfile (renamed from src/ci/docker/dist-freebsd/Dockerfile)9
-rwxr-xr-xsrc/ci/docker/dist-i686-freebsd/build-toolchain.sh (renamed from src/ci/docker/dist-freebsd/build-toolchain.sh)0
-rw-r--r--src/ci/docker/dist-i686-linux/Dockerfile (renamed from src/ci/docker/dist-x86-linux/Dockerfile)9
-rwxr-xr-xsrc/ci/docker/dist-i686-linux/build-binutils.sh (renamed from src/ci/docker/dist-x86-linux/build-binutils.sh)0
-rwxr-xr-xsrc/ci/docker/dist-i686-linux/build-cmake.sh (renamed from src/ci/docker/dist-x86-linux/build-cmake.sh)0
-rwxr-xr-xsrc/ci/docker/dist-i686-linux/build-curl.sh (renamed from src/ci/docker/dist-x86-linux/build-curl.sh)0
-rwxr-xr-xsrc/ci/docker/dist-i686-linux/build-gcc.sh (renamed from src/ci/docker/dist-x86-linux/build-gcc.sh)0
-rwxr-xr-xsrc/ci/docker/dist-i686-linux/build-git.sh (renamed from src/ci/docker/dist-x86-linux/build-git.sh)0
-rwxr-xr-xsrc/ci/docker/dist-i686-linux/build-headers.sh (renamed from src/ci/docker/dist-x86-linux/build-headers.sh)0
-rwxr-xr-xsrc/ci/docker/dist-i686-linux/build-openssl.sh (renamed from src/ci/docker/dist-x86-linux/build-openssl.sh)0
-rwxr-xr-xsrc/ci/docker/dist-i686-linux/build-python.sh (renamed from src/ci/docker/dist-x86-linux/build-python.sh)0
-rw-r--r--src/ci/docker/dist-i686-linux/shared.sh (renamed from src/ci/docker/dist-x86-linux/shared.sh)0
-rw-r--r--src/ci/docker/dist-mips-linux/Dockerfile4
-rw-r--r--src/ci/docker/dist-mips64-linux/Dockerfile4
-rw-r--r--src/ci/docker/dist-mips64el-linux/Dockerfile31
-rw-r--r--src/ci/docker/dist-mipsel-linux/Dockerfile31
-rw-r--r--src/ci/docker/dist-powerpc-linux/Dockerfile2
-rw-r--r--src/ci/docker/dist-powerpc64-linux/Dockerfile12
-rw-r--r--src/ci/docker/dist-powerpc64le-linux/Dockerfile77
-rwxr-xr-xsrc/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh (renamed from src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh)0
-rw-r--r--src/ci/docker/dist-powerpc64le-linux/shared.sh25
-rw-r--r--src/ci/docker/dist-s390x-linux/Dockerfile (renamed from src/ci/docker/dist-s390x-linux-netbsd/Dockerfile)13
-rwxr-xr-xsrc/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh (renamed from src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh)0
-rw-r--r--src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch (renamed from src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch)0
-rw-r--r--src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config (renamed from src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config)0
-rw-r--r--src/ci/docker/dist-x86_64-freebsd/Dockerfile39
-rwxr-xr-xsrc/ci/docker/dist-x86_64-freebsd/build-toolchain.sh112
-rw-r--r--src/ci/docker/dist-x86_64-linux/Dockerfile101
-rwxr-xr-xsrc/ci/docker/dist-x86_64-linux/build-binutils.sh26
-rwxr-xr-xsrc/ci/docker/dist-x86_64-linux/build-cmake.sh25
-rwxr-xr-xsrc/ci/docker/dist-x86_64-linux/build-curl.sh43
-rwxr-xr-xsrc/ci/docker/dist-x86_64-linux/build-gcc.sh33
-rwxr-xr-xsrc/ci/docker/dist-x86_64-linux/build-git.sh24
-rwxr-xr-xsrc/ci/docker/dist-x86_64-linux/build-headers.sh25
-rwxr-xr-xsrc/ci/docker/dist-x86_64-linux/build-openssl.sh27
-rwxr-xr-xsrc/ci/docker/dist-x86_64-linux/build-python.sh30
-rw-r--r--src/ci/docker/dist-x86_64-linux/shared.sh25
-rw-r--r--src/ci/docker/dist-x86_64-musl/Dockerfile2
-rw-r--r--src/ci/docker/dist-x86_64-musl/build-musl.sh2
-rw-r--r--src/ci/docker/dist-x86_64-netbsd/Dockerfile78
-rwxr-xr-xsrc/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh (renamed from src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh)0
-rw-r--r--src/ci/docker/emscripten/Dockerfile2
-rw-r--r--src/ci/docker/i686-gnu-nopt/Dockerfile2
-rw-r--r--src/ci/docker/i686-gnu/Dockerfile2
-rw-r--r--src/ci/docker/x86_64-gnu-aux/Dockerfile2
-rw-r--r--src/ci/docker/x86_64-gnu-debug/Dockerfile2
-rw-r--r--src/ci/docker/x86_64-gnu-distcheck/Dockerfile2
-rw-r--r--src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile2
-rw-r--r--src/ci/docker/x86_64-gnu-incremental/Dockerfile2
-rw-r--r--src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile2
-rw-r--r--src/ci/docker/x86_64-gnu-nopt/Dockerfile2
-rw-r--r--src/ci/docker/x86_64-gnu/Dockerfile2
-rw-r--r--src/doc/unstable-book/src/SUMMARY.md4
-rw-r--r--src/doc/unstable-book/src/offset-to.md7
-rw-r--r--src/doc/unstable-book/src/slice-rsplit.md10
-rw-r--r--src/doc/unstable-book/src/used.md153
-rw-r--r--src/doc/unstable-book/src/windows-subsystem.md10
-rw-r--r--src/etc/char_private.py132
-rw-r--r--src/etc/make-win-dist.py3
-rw-r--r--src/libcollections/Cargo.toml4
-rw-r--r--src/libcollections/lib.rs2
-rw-r--r--src/libcollections/linked_list.rs4
-rw-r--r--src/libcollections/slice.rs68
-rw-r--r--src/libcollections/tests/binary_heap.rs (renamed from src/libcollectionstest/binary_heap.rs)0
-rw-r--r--src/libcollections/tests/btree/map.rs (renamed from src/libcollectionstest/btree/map.rs)0
-rw-r--r--src/libcollections/tests/btree/mod.rs (renamed from src/libcollectionstest/btree/mod.rs)0
-rw-r--r--src/libcollections/tests/btree/set.rs (renamed from src/libcollectionstest/btree/set.rs)0
-rw-r--r--src/libcollections/tests/cow_str.rs (renamed from src/libcollectionstest/cow_str.rs)0
-rw-r--r--src/libcollections/tests/fmt.rs (renamed from src/libcollectionstest/fmt.rs)0
-rw-r--r--src/libcollections/tests/lib.rs (renamed from src/libcollectionstest/lib.rs)0
-rw-r--r--src/libcollections/tests/linked_list.rs (renamed from src/libcollectionstest/linked_list.rs)0
-rw-r--r--src/libcollections/tests/slice.rs (renamed from src/libcollectionstest/slice.rs)0
-rw-r--r--src/libcollections/tests/str.rs (renamed from src/libcollectionstest/str.rs)0
-rw-r--r--src/libcollections/tests/string.rs (renamed from src/libcollectionstest/string.rs)0
-rw-r--r--src/libcollections/tests/vec.rs (renamed from src/libcollectionstest/vec.rs)0
-rw-r--r--src/libcollections/tests/vec_deque.rs (renamed from src/libcollectionstest/vec_deque.rs)0
-rw-r--r--src/libcollections/vec.rs65
-rw-r--r--src/libcollections/vec_deque.rs18
-rw-r--r--src/libcore/Cargo.toml4
-rw-r--r--src/libcore/char_private.rs1238
-rw-r--r--src/libcore/intrinsics.rs96
-rw-r--r--src/libcore/iter/mod.rs12
-rw-r--r--src/libcore/iter/traits.rs2
-rw-r--r--src/libcore/num/bignum.rs2
-rw-r--r--src/libcore/num/dec2flt/rawfp.rs13
-rw-r--r--src/libcore/num/diy_float.rs2
-rw-r--r--src/libcore/num/flt2dec/mod.rs2
-rw-r--r--src/libcore/num/mod.rs2
-rw-r--r--src/libcore/option.rs24
-rw-r--r--src/libcore/ptr.rs76
-rw-r--r--src/libcore/slice/mod.rs172
-rw-r--r--src/libcore/str/mod.rs34
-rw-r--r--src/libcore/sync/atomic.rs44
-rw-r--r--src/libcore/tests/any.rs (renamed from src/libcoretest/any.rs)0
-rw-r--r--src/libcore/tests/array.rs (renamed from src/libcoretest/array.rs)0
-rw-r--r--src/libcore/tests/atomic.rs (renamed from src/libcoretest/atomic.rs)0
-rw-r--r--src/libcore/tests/cell.rs (renamed from src/libcoretest/cell.rs)0
-rw-r--r--src/libcore/tests/char.rs (renamed from src/libcoretest/char.rs)0
-rw-r--r--src/libcore/tests/clone.rs (renamed from src/libcoretest/clone.rs)0
-rw-r--r--src/libcore/tests/cmp.rs (renamed from src/libcoretest/cmp.rs)0
-rw-r--r--src/libcore/tests/fmt/builders.rs (renamed from src/libcoretest/fmt/builders.rs)0
-rw-r--r--src/libcore/tests/fmt/float.rs (renamed from src/libcoretest/fmt/float.rs)0
-rw-r--r--src/libcore/tests/fmt/mod.rs (renamed from src/libcoretest/fmt/mod.rs)0
-rw-r--r--src/libcore/tests/fmt/num.rs (renamed from src/libcoretest/fmt/num.rs)0
-rw-r--r--src/libcore/tests/hash/mod.rs (renamed from src/libcoretest/hash/mod.rs)0
-rw-r--r--src/libcore/tests/hash/sip.rs (renamed from src/libcoretest/hash/sip.rs)0
-rw-r--r--src/libcore/tests/intrinsics.rs (renamed from src/libcoretest/intrinsics.rs)0
-rw-r--r--src/libcore/tests/iter.rs (renamed from src/libcoretest/iter.rs)0
-rw-r--r--src/libcore/tests/lib.rs (renamed from src/libcoretest/lib.rs)0
-rw-r--r--src/libcore/tests/mem.rs (renamed from src/libcoretest/mem.rs)0
-rw-r--r--src/libcore/tests/nonzero.rs (renamed from src/libcoretest/nonzero.rs)0
-rw-r--r--src/libcore/tests/num/bignum.rs (renamed from src/libcoretest/num/bignum.rs)0
-rw-r--r--src/libcore/tests/num/dec2flt/mod.rs (renamed from src/libcoretest/num/dec2flt/mod.rs)0
-rw-r--r--src/libcore/tests/num/dec2flt/parse.rs (renamed from src/libcoretest/num/dec2flt/parse.rs)0
-rw-r--r--src/libcore/tests/num/dec2flt/rawfp.rs (renamed from src/libcoretest/num/dec2flt/rawfp.rs)0
-rw-r--r--src/libcore/tests/num/flt2dec/estimator.rs (renamed from src/libcoretest/num/flt2dec/estimator.rs)0
-rw-r--r--src/libcore/tests/num/flt2dec/mod.rs (renamed from src/libcoretest/num/flt2dec/mod.rs)0
-rw-r--r--src/libcore/tests/num/flt2dec/strategy/dragon.rs (renamed from src/libcoretest/num/flt2dec/strategy/dragon.rs)0
-rw-r--r--src/libcore/tests/num/flt2dec/strategy/grisu.rs (renamed from src/libcoretest/num/flt2dec/strategy/grisu.rs)0
-rw-r--r--src/libcore/tests/num/i16.rs (renamed from src/libcoretest/num/i16.rs)0
-rw-r--r--src/libcore/tests/num/i32.rs (renamed from src/libcoretest/num/i32.rs)0
-rw-r--r--src/libcore/tests/num/i64.rs (renamed from src/libcoretest/num/i64.rs)0
-rw-r--r--src/libcore/tests/num/i8.rs (renamed from src/libcoretest/num/i8.rs)0
-rw-r--r--src/libcore/tests/num/int_macros.rs (renamed from src/libcoretest/num/int_macros.rs)0
-rw-r--r--src/libcore/tests/num/mod.rs (renamed from src/libcoretest/num/mod.rs)0
-rw-r--r--src/libcore/tests/num/u16.rs (renamed from src/libcoretest/num/u16.rs)0
-rw-r--r--src/libcore/tests/num/u32.rs (renamed from src/libcoretest/num/u32.rs)0
-rw-r--r--src/libcore/tests/num/u64.rs (renamed from src/libcoretest/num/u64.rs)0
-rw-r--r--src/libcore/tests/num/u8.rs (renamed from src/libcoretest/num/u8.rs)0
-rw-r--r--src/libcore/tests/num/uint_macros.rs (renamed from src/libcoretest/num/uint_macros.rs)0
-rw-r--r--src/libcore/tests/ops.rs (renamed from src/libcoretest/ops.rs)0
-rw-r--r--src/libcore/tests/option.rs (renamed from src/libcoretest/option.rs)0
-rw-r--r--src/libcore/tests/ptr.rs (renamed from src/libcoretest/ptr.rs)0
-rw-r--r--src/libcore/tests/result.rs (renamed from src/libcoretest/result.rs)0
-rw-r--r--src/libcore/tests/slice.rs (renamed from src/libcoretest/slice.rs)0
-rw-r--r--src/libcore/tests/str.rs (renamed from src/libcoretest/str.rs)2
-rw-r--r--src/libcore/tests/tuple.rs (renamed from src/libcoretest/tuple.rs)0
-rw-r--r--src/librustc/hir/map/definitions.rs4
-rw-r--r--src/librustc/ich/hcx.rs300
-rw-r--r--src/librustc/ich/impls_const_math.rs71
-rw-r--r--src/librustc/ich/impls_hir.rs1106
-rw-r--r--src/librustc/ich/impls_mir.rs407
-rw-r--r--src/librustc/ich/impls_syntax.rs301
-rw-r--r--src/librustc/ich/impls_ty.rs415
-rw-r--r--src/librustc/ich/mod.rs28
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/macros.rs79
-rw-r--r--src/librustc/middle/mem_categorization.rs18
-rw-r--r--src/librustc/middle/reachable.rs17
-rw-r--r--src/librustc/mir/cache.rs11
-rw-r--r--src/librustc/mir/mod.rs18
-rw-r--r--src/librustc/ty/layout.rs2
-rw-r--r--src/librustc/ty/maps.rs12
-rw-r--r--src/librustc/ty/mod.rs29
-rw-r--r--src/librustc_const_eval/eval.rs11
-rw-r--r--src/librustc_data_structures/lib.rs2
-rw-r--r--src/librustc_data_structures/stable_hasher.rs192
-rw-r--r--src/librustc_driver/driver.rs8
-rw-r--r--src/librustc_incremental/calculate_svh/mod.rs197
-rw-r--r--src/librustc_incremental/calculate_svh/svh_visitor.rs1113
-rw-r--r--src/librustc_incremental/lib.rs1
-rw-r--r--src/librustc_llvm/build.rs6
-rw-r--r--src/librustc_llvm/ffi.rs7
-rw-r--r--src/librustc_mir/build/cfg.rs3
-rw-r--r--src/librustc_resolve/macros.rs6
-rw-r--r--src/librustc_save_analysis/dump_visitor.rs76
-rw-r--r--src/librustc_save_analysis/lib.rs59
-rw-r--r--src/librustc_trans/assert_module_sources.rs7
-rw-r--r--src/librustc_trans/back/link.rs31
-rw-r--r--src/librustc_trans/back/linker.rs127
-rw-r--r--src/librustc_trans/base.rs19
-rw-r--r--src/librustc_trans/consts.rs6
-rw-r--r--src/librustc_trans/context.rs9
-rw-r--r--src/librustc_trans/mir/block.rs2
-rw-r--r--src/librustc_typeck/check/method/suggest.rs26
-rw-r--r--src/librustc_typeck/check/mod.rs1
-rw-r--r--src/librustc_typeck/check/op.rs21
-rw-r--r--src/librustc_typeck/coherence/inherent_impls_overlap.rs17
-rw-r--r--src/librustdoc/html/markdown.rs603
-rw-r--r--src/librustdoc/html/render.rs12
-rw-r--r--src/librustdoc/markdown.rs4
-rw-r--r--src/librustdoc/passes/unindent_comments.rs13
-rw-r--r--src/libstd/ascii.rs66
-rw-r--r--src/libstd/collections/hash/map.rs32
-rw-r--r--src/libstd/collections/hash/table.rs324
-rw-r--r--src/libstd/fs.rs23
-rw-r--r--src/libstd/io/buffered.rs17
-rw-r--r--src/libstd/io/mod.rs9
-rw-r--r--src/libstd/net/tcp.rs4
-rw-r--r--src/libstd/prelude/mod.rs12
-rw-r--r--src/libstd/process.rs21
-rw-r--r--src/libstd/sync/barrier.rs9
-rw-r--r--src/libstd/sync/mpsc/mod.rs218
-rw-r--r--src/libstd/sync/mutex.rs14
-rw-r--r--src/libstd/sys/unix/ext/io.rs15
-rw-r--r--src/libstd/sys/unix/mod.rs2
-rw-r--r--src/libstd/sys/unix/pipe.rs22
-rw-r--r--src/libstd/sys/windows/ext/fs.rs2
-rw-r--r--src/libstd/sys/windows/ext/process.rs1
-rw-r--r--src/libstd/thread/mod.rs6
-rw-r--r--src/libsyntax/ext/derive.rs3
-rw-r--r--src/libsyntax/feature_gate.rs20
-rw-r--r--src/libsyntax/parse/parser.rs116
-rw-r--r--src/libsyntax/ptr.rs12
-rw-r--r--src/libsyntax/util/rc_slice.rs13
-rw-r--r--src/libsyntax_pos/lib.rs32
-rw-r--r--src/libtest/stats.rs6
-rw-r--r--src/libunwind/build.rs3
-rw-r--r--src/libunwind/lib.rs1
-rw-r--r--src/test/codegen/personality_lifetimes.rs41
-rw-r--r--src/test/compile-fail/feature-gate-used.rs15
-rw-r--r--src/test/compile-fail/issue-40610.rs16
-rw-r--r--src/test/compile-fail/issue-40861.rs16
-rw-r--r--src/test/compile-fail/windows-subsystem-invalid.rs1
-rw-r--r--src/test/parse-fail/match-refactor-to-expr.rs4
-rw-r--r--src/test/run-make/multiple-emits/Makefile7
-rw-r--r--src/test/run-make/multiple-emits/foo.rs11
-rw-r--r--src/test/run-make/save-analysis-fail/foo.rs5
-rw-r--r--src/test/run-make/save-analysis/foo.rs17
-rw-r--r--src/test/run-make/used/Makefile11
-rw-r--r--src/test/run-make/used/used.rs17
-rw-r--r--src/test/run-make/windows-subsystem/console.rs1
-rw-r--r--src/test/run-make/windows-subsystem/windows.rs1
-rw-r--r--src/test/run-pass/const-err.rs4
-rw-r--r--src/test/run-pass/issue-40962.rs (renamed from src/test/compile-fail/windows-subsystem-gated.rs)12
-rw-r--r--src/test/rustdoc/check-hard-break.rs20
-rw-r--r--src/test/rustdoc/check-rule-image-footnote.rs44
-rw-r--r--src/test/rustdoc/test-lists.rs36
-rw-r--r--src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs (renamed from src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs)2
-rw-r--r--src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr10
-rw-r--r--src/test/ui/codemap_tests/overlapping_inherent_impls.rs (renamed from src/test/compile-fail/inherent-overlap.rs)6
-rw-r--r--src/test/ui/codemap_tests/overlapping_inherent_impls.stderr29
-rw-r--r--src/test/ui/did_you_mean/issue-39544.rs6
-rw-r--r--src/test/ui/did_you_mean/issue-39544.stderr8
-rw-r--r--src/test/ui/did_you_mean/issue-40006.rs21
-rw-r--r--src/test/ui/did_you_mean/issue-40006.stderr8
-rw-r--r--src/test/ui/resolve/token-error-correct-3.stderr7
-rw-r--r--src/test/ui/resolve/token-error-correct.stderr2
-rw-r--r--src/test/ui/span/issue-34264.stderr6
-rw-r--r--src/test/ui/suggestions/confuse-field-and-method/private-field.rs29
-rw-r--r--src/test/ui/suggestions/confuse-field-and-method/private-field.stderr8
-rw-r--r--src/test/ui/token/bounds-obj-parens.rs (renamed from src/test/parse-fail/bounds-obj-parens.rs)4
-rw-r--r--src/test/ui/token/bounds-obj-parens.stderr8
-rw-r--r--src/test/ui/token/issue-10636-2.rs (renamed from src/test/compile-fail/issue-10636-2.rs)2
-rw-r--r--src/test/ui/token/issue-10636-2.stderr28
-rw-r--r--src/test/ui/token/macro-incomplete-parse.rs (renamed from src/test/compile-fail/macro-incomplete-parse.rs)2
-rw-r--r--src/test/ui/token/macro-incomplete-parse.stderr32
-rw-r--r--src/test/ui/token/trailing-plus-in-bounds.rs (renamed from src/test/parse-fail/trailing-plus-in-bounds.rs)4
-rw-r--r--src/test/ui/token/trailing-plus-in-bounds.stderr8
-rw-r--r--src/tools/error_index_generator/main.rs4
-rw-r--r--src/tools/tidy/src/pal.rs2
-rw-r--r--src/tools/tidy/src/style.rs3
278 files changed, 7309 insertions, 3328 deletions
diff --git a/.gitmodules b/.gitmodules
index 53d17874924..3533f0df5d1 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -25,4 +25,4 @@
 	url = https://github.com/rust-lang-nursery/reference.git
 [submodule "book"]
 	path = src/doc/book
-	url = https://github.com/rust-lang/book
+	url = https://github.com/rust-lang/book.git
diff --git a/.travis.yml b/.travis.yml
index 8fe92ff7d02..0ffba70d2ef 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -15,19 +15,27 @@ matrix:
     - env: IMAGE=arm-android
     - env: IMAGE=armhf-gnu
     - env: IMAGE=cross DEPLOY=1
+    - env: IMAGE=dist-aarch64-linux DEPLOY=1
     - env: IMAGE=dist-android DEPLOY=1
     - env: IMAGE=dist-arm-linux DEPLOY=1
-    - env: IMAGE=dist-armv7-aarch64-linux DEPLOY=1
-    - env: IMAGE=dist-freebsd DEPLOY=1
-    - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1
+    - env: IMAGE=dist-armhf-linux DEPLOY=1
+    - env: IMAGE=dist-armv7-linux DEPLOY=1
     - env: IMAGE=dist-fuchsia DEPLOY=1
+    - env: IMAGE=dist-i586-gnu-i686-musl DEPLOY=1
+    - env: IMAGE=dist-i686-freebsd DEPLOY=1
+    - env: IMAGE=dist-i686-linux DEPLOY=1
     - env: IMAGE=dist-mips-linux DEPLOY=1
     - env: IMAGE=dist-mips64-linux DEPLOY=1
+    - env: IMAGE=dist-mips64el-linux DEPLOY=1
+    - env: IMAGE=dist-mipsel-linux DEPLOY=1
     - env: IMAGE=dist-powerpc-linux DEPLOY=1
     - env: IMAGE=dist-powerpc64-linux DEPLOY=1
-    - env: IMAGE=dist-s390x-linux-netbsd DEPLOY=1
-    - env: IMAGE=dist-x86-linux DEPLOY=1
+    - env: IMAGE=dist-powerpc64le-linux DEPLOY=1
+    - env: IMAGE=dist-s390x-linux DEPLOY=1
+    - env: IMAGE=dist-x86_64-freebsd DEPLOY=1
+    - env: IMAGE=dist-x86_64-linux DEPLOY=1
     - env: IMAGE=dist-x86_64-musl DEPLOY=1
+    - env: IMAGE=dist-x86_64-netbsd DEPLOY=1
     - env: IMAGE=emscripten
     - env: IMAGE=i686-gnu
     - env: IMAGE=i686-gnu-nopt
@@ -55,7 +63,7 @@ matrix:
       os: osx
       osx_image: xcode8.2
       install: &osx_install_sccache >
-        travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-apple-darwin &&
+        travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-apple-darwin &&
           chmod +x /usr/local/bin/sccache &&
         travis_retry curl -o /usr/local/bin/stamp https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin &&
           chmod +x /usr/local/bin/stamp
@@ -104,7 +112,7 @@ matrix:
     # turned on, they're deployed to a different location primarily for projects
     # which are stuck on nightly and don't want llvm assertions in the artifacts
     # that they use.
-    - env: IMAGE=dist-x86-linux DEPLOY_ALT=1
+    - env: IMAGE=dist-x86_64-linux DEPLOY_ALT=1
     - env: >
         RUST_CHECK_TARGET=dist
         RUST_CONFIGURE_ARGS="--enable-extended"
diff --git a/appveyor.yml b/appveyor.yml
index 68b2a239aff..83cfea0dd83 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -115,8 +115,8 @@ install:
   - set PATH=C:\Python27;%PATH%
 
   # Download and install sccache
-  - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-pc-windows-msvc
-  - mv 2017-03-24-sccache-x86_64-pc-windows-msvc sccache.exe
+  - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-pc-windows-msvc
+  - mv 2017-04-04-sccache-x86_64-pc-windows-msvc sccache.exe
   - set PATH=%PATH%;%CD%
 
   # Download and install ninja
diff --git a/cargo b/cargo
-Subproject 4e95c6b41eca3388f54dd5f7787366ad2df637b
+Subproject 4729175045b41b688ab903120860866ce7a22ba
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index d5bc6127a1e..526beb41aae 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -163,12 +163,13 @@ class RustBuild(object):
         if not os.path.exists(rustc_cache):
             os.makedirs(rustc_cache)
 
+        channel = self.stage0_rustc_channel()
+
         if self.rustc().startswith(self.bin_root()) and \
                 (not os.path.exists(self.rustc()) or self.rustc_out_of_date()):
             self.print_what_it_means_to_bootstrap()
             if os.path.exists(self.bin_root()):
                 shutil.rmtree(self.bin_root())
-            channel = self.stage0_rustc_channel()
             filename = "rust-std-{}-{}.tar.gz".format(channel, self.build)
             url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date()
             tarball = os.path.join(rustc_cache, filename)
@@ -189,6 +190,14 @@ class RustBuild(object):
             with open(self.rustc_stamp(), 'w') as f:
                 f.write(self.stage0_rustc_date())
 
+            if "pc-windows-gnu" in self.build:
+                filename = "rust-mingw-{}-{}.tar.gz".format(channel, self.build)
+                url = "https://static.rust-lang.org/dist/" + self.stage0_rustc_date()
+                tarball = os.path.join(rustc_cache, filename)
+                if not os.path.exists(tarball):
+                    get("{}/{}".format(url, filename), tarball, verbose=self.verbose)
+                unpack(tarball, self.bin_root(), match="rust-mingw", verbose=self.verbose)
+
         if self.cargo().startswith(self.bin_root()) and \
                 (not os.path.exists(self.cargo()) or self.cargo_out_of_date()):
             self.print_what_it_means_to_bootstrap()
@@ -591,16 +600,19 @@ def bootstrap():
 
 def main():
     start_time = time()
+    help_triggered = ('-h' in sys.argv) or ('--help' in sys.argv) or (len(sys.argv) == 1)
     try:
         bootstrap()
-        print("Build completed successfully in %s" % format_build_time(time() - start_time))
+        if not help_triggered:
+            print("Build completed successfully in %s" % format_build_time(time() - start_time))
     except (SystemExit, KeyboardInterrupt) as e:
         if hasattr(e, 'code') and isinstance(e.code, int):
             exit_code = e.code
         else:
             exit_code = 1
             print(e)
-        print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time))
+        if not help_triggered:
+            print("Build completed unsuccessfully in %s" % format_build_time(time() - start_time))
         sys.exit(exit_code)
 
 if __name__ == '__main__':
diff --git a/src/bootstrap/clean.rs b/src/bootstrap/clean.rs
index e9547ee42d0..308a0ab3076 100644
--- a/src/bootstrap/clean.rs
+++ b/src/bootstrap/clean.rs
@@ -44,26 +44,25 @@ pub fn clean(build: &Build) {
 }
 
 fn rm_rf(path: &Path) {
-    if !path.exists() {
-        return
-    }
-    if path.is_file() {
-        return do_op(path, "remove file", |p| fs::remove_file(p));
-    }
-
-    for file in t!(fs::read_dir(path)) {
-        let file = t!(file).path();
+    match path.symlink_metadata() {
+        Err(e) => {
+            if e.kind() == ErrorKind::NotFound {
+                return;
+            }
+            panic!("failed to get metadata for file {}: {}", path.display(), e);
+        },
+        Ok(metadata) => {
+            if metadata.file_type().is_file() || metadata.file_type().is_symlink() {
+                do_op(path, "remove file", |p| fs::remove_file(p));
+                return;
+            }
 
-        if file.is_dir() {
-            rm_rf(&file);
-        } else {
-            // On windows we can't remove a readonly file, and git will
-            // often clone files as readonly. As a result, we have some
-            // special logic to remove readonly files on windows.
-            do_op(&file, "remove file", |p| fs::remove_file(p));
-        }
-    }
-    do_op(path, "remove dir", |p| fs::remove_dir(p));
+            for file in t!(fs::read_dir(path)) {
+                rm_rf(&t!(file).path());
+            }
+            do_op(path, "remove dir", |p| fs::remove_dir(p));
+        },
+    };
 }
 
 fn do_op<F>(path: &Path, desc: &str, mut f: F)
@@ -71,9 +70,12 @@ fn do_op<F>(path: &Path, desc: &str, mut f: F)
 {
     match f(path) {
         Ok(()) => {}
+        // On windows we can't remove a readonly file, and git will often clone files as readonly.
+        // As a result, we have some special logic to remove readonly files on windows.
+        // This is also the reason that we can't use things like fs::remove_dir_all().
         Err(ref e) if cfg!(windows) &&
                       e.kind() == ErrorKind::PermissionDenied => {
-            let mut p = t!(path.metadata()).permissions();
+            let mut p = t!(path.symlink_metadata()).permissions();
             p.set_readonly(false);
             t!(fs::set_permissions(path, p));
             f(path).unwrap_or_else(|e| {
diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs
index b55f3d710ca..a1466d68a13 100644
--- a/src/bootstrap/flags.rs
+++ b/src/bootstrap/flags.rs
@@ -18,7 +18,7 @@ use std::fs;
 use std::path::PathBuf;
 use std::process;
 
-use getopts::{Matches, Options};
+use getopts::Options;
 
 use Build;
 use config::Config;
@@ -75,7 +75,22 @@ pub enum Subcommand {
 
 impl Flags {
     pub fn parse(args: &[String]) -> Flags {
+        let mut extra_help = String::new();
+        let mut subcommand_help = format!("\
+Usage: x.py <subcommand> [options] [<paths>...]
+
+Subcommands:
+    build       Compile either the compiler or libraries
+    test        Build and run some test suites
+    bench       Build and run some benchmarks
+    doc         Build documentation
+    clean       Clean out build directories
+    dist        Build and/or install distribution artifacts
+
+To learn more about a subcommand, run `./x.py <subcommand> -h`");
+
         let mut opts = Options::new();
+        // Options common to all subcommands
         opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
         opts.optflag("i", "incremental", "use incremental compilation");
         opts.optopt("", "config", "TOML configuration file for build", "FILE");
@@ -89,21 +104,83 @@ impl Flags {
         opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS");
         opts.optflag("h", "help", "print this help message");
 
-        let usage = |n, opts: &Options| -> ! {
-            let command = args.get(0).map(|s| &**s);
-            let brief = format!("Usage: x.py {} [options] [<args>...]",
-                                command.unwrap_or("<command>"));
+        // fn usage()
+        let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! {
+            println!("{}", opts.usage(subcommand_help));
+            if !extra_help.is_empty() {
+                println!("{}", extra_help);
+            }
+            process::exit(exit_code);
+        };
+
+        // We can't use getopt to parse the options until we have completed specifying which
+        // options are valid, but under the current implementation, some options are conditional on
+        // the subcommand. Therefore we must manually identify the subcommand first, so that we can
+        // complete the definition of the options.  Then we can use the getopt::Matches object from
+        // there on out.
+        let mut possible_subcommands = args.iter().collect::<Vec<_>>();
+        possible_subcommands.retain(|&s|
+                                           (s == "build")
+                                        || (s == "test")
+                                        || (s == "bench")
+                                        || (s == "doc")
+                                        || (s == "clean")
+                                        || (s == "dist"));
+        let subcommand = match possible_subcommands.first() {
+            Some(s) => s,
+            None => {
+                // No subcommand -- show the general usage and subcommand help
+                println!("{}\n", subcommand_help);
+                process::exit(0);
+            }
+        };
 
-            println!("{}", opts.usage(&brief));
-            match command {
-                Some("build") => {
-                    println!("\
+        // Some subcommands get extra options
+        match subcommand.as_str() {
+            "test"  => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
+            "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); },
+            "dist"  => { opts.optflag("", "install", "run installer as well"); },
+            _ => { },
+        };
+
+        // Done specifying what options are possible, so do the getopts parsing
+        let matches = opts.parse(&args[..]).unwrap_or_else(|e| {
+            // Invalid argument/option format
+            println!("\n{}\n", e);
+            usage(1, &opts, &subcommand_help, &extra_help);
+        });
+        // Extra sanity check to make sure we didn't hit this crazy corner case:
+        //
+        //     ./x.py --frobulate clean build
+        //            ^-- option  ^     ^- actual subcommand
+        //                        \_ arg to option could be mistaken as subcommand
+        let mut pass_sanity_check = true;
+        match matches.free.get(0) {
+            Some(check_subcommand) => {
+                if &check_subcommand != subcommand {
+                    pass_sanity_check = false;
+                }
+            },
+            None => {
+                pass_sanity_check = false;
+            }
+        }
+        if !pass_sanity_check {
+            println!("{}\n", subcommand_help);
+            println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\
+                      You may need to move some options to after the subcommand.\n");
+            process::exit(1);
+        }
+        // Extra help text for some commands
+        match subcommand.as_str() {
+            "build" => {
+                subcommand_help.push_str("\n
 Arguments:
-    This subcommand accepts a number of positional arguments of directories to
-    the crates and/or artifacts to compile. For example:
+    This subcommand accepts a number of paths to directories to the crates
+    and/or artifacts to compile. For example:
 
         ./x.py build src/libcore
-        ./x.py build src/libproc_macro
+        ./x.py build src/libcore src/libproc_macro
         ./x.py build src/libstd --stage 1
 
     If no arguments are passed then the complete artifacts for that stage are
@@ -114,15 +191,13 @@ Arguments:
 
     For a quick build with a usable compile, you can pass:
 
-        ./x.py build --stage 1 src/libtest
-");
-                }
-
-                Some("test") => {
-                    println!("\
+        ./x.py build --stage 1 src/libtest");
+            }
+            "test" => {
+                subcommand_help.push_str("\n
 Arguments:
-    This subcommand accepts a number of positional arguments of directories to
-    tests that should be compiled and run. For example:
+    This subcommand accepts a number of paths to directories to tests that
+    should be compiled and run. For example:
 
         ./x.py test src/test/run-pass
         ./x.py test src/libstd --test-args hash_map
@@ -132,139 +207,90 @@ Arguments:
     compiled and tested.
 
         ./x.py test
-        ./x.py test --stage 1
-");
-                }
-
-                Some("doc") => {
-                    println!("\
+        ./x.py test --stage 1");
+            }
+            "doc" => {
+                subcommand_help.push_str("\n
 Arguments:
-    This subcommand accepts a number of positional arguments of directories of
-    documentation to build. For example:
+    This subcommand accepts a number of paths to directories of documentation
+    to build. For example:
 
         ./x.py doc src/doc/book
         ./x.py doc src/doc/nomicon
-        ./x.py doc src/libstd
+        ./x.py doc src/doc/book src/libstd
 
     If no arguments are passed then everything is documented:
 
         ./x.py doc
-        ./x.py doc --stage 1
-");
-                }
-
-                _ => {}
+        ./x.py doc --stage 1");
             }
-
-            if let Some(command) = command {
-                if command == "build" ||
-                   command == "dist" ||
-                   command == "doc" ||
-                   command == "test" ||
-                   command == "bench" ||
-                   command == "clean"  {
-                    println!("Available invocations:");
-                    if args.iter().any(|a| a == "-v") {
-                        let flags = Flags::parse(&["build".to_string()]);
-                        let mut config = Config::default();
-                        config.build = flags.build.clone();
-                        let mut build = Build::new(flags, config);
-                        metadata::build(&mut build);
-                        step::build_rules(&build).print_help(command);
-                    } else {
-                        println!("    ... elided, run `./x.py {} -h -v` to see",
-                                 command);
-                    }
-
-                    println!("");
-                }
-            }
-
-println!("\
-Subcommands:
-    build       Compile either the compiler or libraries
-    test        Build and run some test suites
-    bench       Build and run some benchmarks
-    doc         Build documentation
-    clean       Clean out build directories
-    dist        Build and/or install distribution artifacts
-
-To learn more about a subcommand, run `./x.py <command> -h`
-");
-
-            process::exit(n);
+            _ => { }
         };
-        if args.len() == 0 {
-            println!("a command must be passed");
-            usage(1, &opts);
-        }
-        let parse = |opts: &Options| {
-            let m = opts.parse(&args[1..]).unwrap_or_else(|e| {
-                println!("failed to parse options: {}", e);
-                usage(1, opts);
-            });
-            if m.opt_present("h") {
-                usage(0, opts);
+        // Get any optional paths which occur after the subcommand
+        let cwd = t!(env::current_dir());
+        let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::<Vec<_>>();
+
+
+        // All subcommands can have an optional "Available paths" section
+        if matches.opt_present("verbose") {
+            let flags = Flags::parse(&["build".to_string()]);
+            let mut config = Config::default();
+            config.build = flags.build.clone();
+            let mut build = Build::new(flags, config);
+            metadata::build(&mut build);
+            let maybe_rules_help = step::build_rules(&build).get_help(subcommand);
+            if maybe_rules_help.is_some() {
+                extra_help.push_str(maybe_rules_help.unwrap().as_str());
             }
-            return m
-        };
+        } else {
+            extra_help.push_str(format!("Run `./x.py {} -h -v` to see a list of available paths.",
+                     subcommand).as_str());
+        }
 
-        let cwd = t!(env::current_dir());
-        let remaining_as_path = |m: &Matches| {
-            m.free.iter().map(|p| cwd.join(p)).collect::<Vec<_>>()
-        };
+        // User passed in -h/--help?
+        if matches.opt_present("help") {
+            usage(0, &opts, &subcommand_help, &extra_help);
+        }
 
-        let m: Matches;
-        let cmd = match &args[0][..] {
+        let cmd = match subcommand.as_str() {
             "build" => {
-                m = parse(&opts);
-                Subcommand::Build { paths: remaining_as_path(&m) }
-            }
-            "doc" => {
-                m = parse(&opts);
-                Subcommand::Doc { paths: remaining_as_path(&m) }
+                Subcommand::Build { paths: paths }
             }
             "test" => {
-                opts.optmulti("", "test-args", "extra arguments", "ARGS");
-                m = parse(&opts);
                 Subcommand::Test {
-                    paths: remaining_as_path(&m),
-                    test_args: m.opt_strs("test-args"),
+                    paths: paths,
+                    test_args: matches.opt_strs("test-args"),
                 }
             }
             "bench" => {
-                opts.optmulti("", "test-args", "extra arguments", "ARGS");
-                m = parse(&opts);
                 Subcommand::Bench {
-                    paths: remaining_as_path(&m),
-                    test_args: m.opt_strs("test-args"),
+                    paths: paths,
+                    test_args: matches.opt_strs("test-args"),
                 }
             }
+            "doc" => {
+                Subcommand::Doc { paths: paths }
+            }
             "clean" => {
-                m = parse(&opts);
-                if m.free.len() > 0 {
-                    println!("clean takes no arguments");
-                    usage(1, &opts);
+                if paths.len() > 0 {
+                    println!("\nclean takes no arguments\n");
+                    usage(1, &opts, &subcommand_help, &extra_help);
                 }
                 Subcommand::Clean
             }
             "dist" => {
-                opts.optflag("", "install", "run installer as well");
-                m = parse(&opts);
                 Subcommand::Dist {
-                    paths: remaining_as_path(&m),
-                    install: m.opt_present("install"),
+                    paths: paths,
+                    install: matches.opt_present("install"),
                 }
             }
-            "--help" => usage(0, &opts),
-            cmd => {
-                println!("unknown command: {}", cmd);
-                usage(1, &opts);
+            _ => {
+                usage(1, &opts, &subcommand_help, &extra_help);
             }
         };
 
 
-        let cfg_file = m.opt_str("config").map(PathBuf::from).or_else(|| {
+        let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| {
             if fs::metadata("config.toml").is_ok() {
                 Some(PathBuf::from("config.toml"))
             } else {
@@ -272,31 +298,29 @@ To learn more about a subcommand, run `./x.py <command> -h`
             }
         });
 
-        let mut stage = m.opt_str("stage").map(|j| j.parse().unwrap());
-
-        let incremental = m.opt_present("i");
+        let mut stage = matches.opt_str("stage").map(|j| j.parse().unwrap());
 
-        if incremental {
+        if matches.opt_present("incremental") {
             if stage.is_none() {
                 stage = Some(1);
             }
         }
 
         Flags {
-            verbose: m.opt_count("v"),
+            verbose: matches.opt_count("verbose"),
             stage: stage,
-            on_fail: m.opt_str("on-fail"),
-            keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
-            build: m.opt_str("build").unwrap_or_else(|| {
+            on_fail: matches.opt_str("on-fail"),
+            keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()),
+            build: matches.opt_str("build").unwrap_or_else(|| {
                 env::var("BUILD").unwrap()
             }),
-            host: split(m.opt_strs("host")),
-            target: split(m.opt_strs("target")),
+            host: split(matches.opt_strs("host")),
+            target: split(matches.opt_strs("target")),
             config: cfg_file,
-            src: m.opt_str("src").map(PathBuf::from),
-            jobs: m.opt_str("jobs").map(|j| j.parse().unwrap()),
+            src: matches.opt_str("src").map(PathBuf::from),
+            jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()),
             cmd: cmd,
-            incremental: incremental,
+            incremental: matches.opt_present("incremental"),
         }
     }
 }
diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs
index 249f241a151..25082e3a9d0 100644
--- a/src/bootstrap/install.rs
+++ b/src/bootstrap/install.rs
@@ -49,12 +49,17 @@ pub fn install(build: &Build, stage: u32, host: &str) {
         install_sh(&build, "docs", "rust-docs", stage, host, &prefix,
                    &docdir, &libdir, &mandir, &empty_dir);
     }
+
+    for target in build.config.target.iter() {
+        install_sh(&build, "std", "rust-std", stage, target, &prefix,
+                   &docdir, &libdir, &mandir, &empty_dir);
+    }
+
     if build.config.rust_save_analysis {
         install_sh(&build, "analysis", "rust-analysis", stage, host, &prefix,
                    &docdir, &libdir, &mandir, &empty_dir);
     }
-    install_sh(&build, "std", "rust-std", stage, host, &prefix,
-               &docdir, &libdir, &mandir, &empty_dir);
+
     install_sh(&build, "rustc", "rustc", stage, host, &prefix,
                &docdir, &libdir, &mandir, &empty_dir);
     t!(fs::remove_dir_all(&empty_dir));
diff --git a/src/bootstrap/step.rs b/src/bootstrap/step.rs
index 6eb12fed5ab..5560b5b0333 100644
--- a/src/bootstrap/step.rs
+++ b/src/bootstrap/step.rs
@@ -978,26 +978,25 @@ invalid rule dependency graph detected, was a rule added and maybe typo'd?
         }
     }
 
-    pub fn print_help(&self, command: &str) {
+    pub fn get_help(&self, command: &str) -> Option<String> {
         let kind = match command {
             "build" => Kind::Build,
             "doc" => Kind::Doc,
             "test" => Kind::Test,
             "bench" => Kind::Bench,
             "dist" => Kind::Dist,
-            _ => return,
+            _ => return None,
         };
         let rules = self.rules.values().filter(|r| r.kind == kind);
         let rules = rules.filter(|r| !r.path.contains("nowhere"));
         let mut rules = rules.collect::<Vec<_>>();
         rules.sort_by_key(|r| r.path);
 
-        println!("Available paths:\n");
+        let mut help_string = String::from("Available paths:\n");
         for rule in rules {
-            print!("    ./x.py {} {}", command, rule.path);
-
-            println!("");
+            help_string.push_str(format!("    ./x.py {} {}\n", command, rule.path).as_str());
         }
+        Some(help_string)
     }
 
     /// Construct the top-level build steps that we're going to be executing,
diff --git a/src/ci/docker/armhf-gnu/Dockerfile b/src/ci/docker/armhf-gnu/Dockerfile
index 933562c79e5..d42b35d488c 100644
--- a/src/ci/docker/armhf-gnu/Dockerfile
+++ b/src/ci/docker/armhf-gnu/Dockerfile
@@ -74,7 +74,7 @@ RUN arm-linux-gnueabihf-gcc addentropy.c -o rootfs/addentropy -static
 RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/ci/docker/cross/Dockerfile b/src/ci/docker/cross/Dockerfile
index 8dc02ab522c..7c198441007 100644
--- a/src/ci/docker/cross/Dockerfile
+++ b/src/ci/docker/cross/Dockerfile
@@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   pkg-config
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile b/src/ci/docker/dist-aarch64-linux/Dockerfile
index 369e5a7dffe..d9a5429d2b8 100644
--- a/src/ci/docker/dist-armv7-aarch64-linux/Dockerfile
+++ b/src/ci/docker/dist-aarch64-linux/Dockerfile
@@ -56,28 +56,22 @@ RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools
 USER rustbuild
 WORKDIR /tmp
 
-COPY armv7-linux-gnueabihf.config /tmp/
-COPY armv7-linux-gnueabihf.config aarch64-linux-gnu.config build-toolchains.sh /tmp/
+COPY aarch64-linux-gnu.config build-toolchains.sh /tmp/
 RUN ./build-toolchains.sh
 
 USER root
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 ENV PATH=$PATH:/x-tools/aarch64-unknown-linux-gnueabi/bin
-ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin
 
 ENV CC_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-gcc \
     AR_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-ar \
-    CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++ \
-    CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \
-    AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar \
-    CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++
+    CXX_aarch64_unknown_linux_gnu=aarch64-unknown-linux-gnueabi-g++
 
-ENV HOSTS=armv7-unknown-linux-gnueabihf
-ENV HOSTS=$HOSTS,aarch64-unknown-linux-gnu
+ENV HOSTS=aarch64-unknown-linux-gnu
 
 ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config b/src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config
index 3d30ee49022..3d30ee49022 100644
--- a/src/ci/docker/dist-armv7-aarch64-linux/aarch64-linux-gnu.config
+++ b/src/ci/docker/dist-aarch64-linux/aarch64-linux-gnu.config
diff --git a/src/ci/docker/dist-aarch64-linux/build-toolchains.sh b/src/ci/docker/dist-aarch64-linux/build-toolchains.sh
new file mode 100755
index 00000000000..94f785c96f8
--- /dev/null
+++ b/src/ci/docker/dist-aarch64-linux/build-toolchains.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  $@ &> /tmp/build.log
+  rm /tmp/build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  set -x
+}
+
+mkdir build
+cd build
+cp ../aarch64-linux-gnu.config .config
+ct-ng oldconfig
+hide_output ct-ng build
+cd ..
+rm -rf build
diff --git a/src/ci/docker/dist-android/Dockerfile b/src/ci/docker/dist-android/Dockerfile
index 44d6863bf0b..31f4b8b777b 100644
--- a/src/ci/docker/dist-android/Dockerfile
+++ b/src/ci/docker/dist-android/Dockerfile
@@ -32,7 +32,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 ENV TARGETS=arm-linux-androideabi
diff --git a/src/ci/docker/dist-arm-linux/Dockerfile b/src/ci/docker/dist-arm-linux/Dockerfile
index 7facc52390f..7162aa0efc0 100644
--- a/src/ci/docker/dist-arm-linux/Dockerfile
+++ b/src/ci/docker/dist-arm-linux/Dockerfile
@@ -56,27 +56,22 @@ RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools
 USER rustbuild
 WORKDIR /tmp
 
-COPY arm-linux-gnueabihf.config arm-linux-gnueabi.config build-toolchains.sh /tmp/
+COPY arm-linux-gnueabi.config build-toolchains.sh /tmp/
 RUN ./build-toolchains.sh
 
 USER root
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabi/bin
-ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin
 
 ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \
     AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \
-    CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ \
-    CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \
-    AR_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-ar \
-    CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++
+    CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++
 
 ENV HOSTS=arm-unknown-linux-gnueabi
-ENV HOSTS=$HOSTS,arm-unknown-linux-gnueabihf
 
 ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-arm-linux/build-toolchains.sh b/src/ci/docker/dist-arm-linux/build-toolchains.sh
index ed1406bd7cf..f78ecf9381a 100755
--- a/src/ci/docker/dist-arm-linux/build-toolchains.sh
+++ b/src/ci/docker/dist-arm-linux/build-toolchains.sh
@@ -35,11 +35,3 @@ ct-ng oldconfig
 hide_output ct-ng build
 cd ..
 rm -rf build
-
-mkdir build
-cd build
-cp ../arm-linux-gnueabihf.config .config
-ct-ng oldconfig
-hide_output ct-ng build
-cd ..
-rm -rf build
diff --git a/src/ci/docker/dist-armhf-linux/Dockerfile b/src/ci/docker/dist-armhf-linux/Dockerfile
new file mode 100644
index 00000000000..8fa1cbe492f
--- /dev/null
+++ b/src/ci/docker/dist-armhf-linux/Dockerfile
@@ -0,0 +1,77 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  automake \
+  bison \
+  bzip2 \
+  ca-certificates \
+  cmake \
+  curl \
+  file \
+  flex \
+  g++ \
+  gawk \
+  gdb \
+  git \
+  gperf \
+  help2man \
+  libncurses-dev \
+  libtool-bin \
+  make \
+  patch \
+  python2.7 \
+  sudo \
+  texinfo \
+  wget \
+  xz-utils \
+  libssl-dev \
+  pkg-config
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+# Ubuntu 16.04 (this contianer) ships with make 4, but something in the
+# toolchains we build below chokes on that, so go back to make 3
+RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \
+      cd make-3.81 && \
+      ./configure --prefix=/usr && \
+      make && \
+      make install && \
+      cd .. && \
+      rm -rf make-3.81
+
+RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \
+      tar xjf - && \
+      cd crosstool-ng && \
+      ./configure --prefix=/usr/local && \
+      make -j$(nproc) && \
+      make install && \
+      cd .. && \
+      rm -rf crosstool-ng
+
+RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild
+RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools
+USER rustbuild
+WORKDIR /tmp
+
+COPY arm-linux-gnueabihf.config build-toolchains.sh /tmp/
+RUN ./build-toolchains.sh
+
+USER root
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENV PATH=$PATH:/x-tools/arm-unknown-linux-gnueabihf/bin
+
+ENV CC_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-gcc \
+    AR_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-ar \
+    CXX_arm_unknown_linux_gnueabihf=arm-unknown-linux-gnueabihf-g++
+
+ENV HOSTS=arm-unknown-linux-gnueabihf
+
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config b/src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config
index 1feeef15557..1feeef15557 100644
--- a/src/ci/docker/dist-arm-linux/arm-linux-gnueabihf.config
+++ b/src/ci/docker/dist-armhf-linux/arm-linux-gnueabihf.config
diff --git a/src/ci/docker/dist-armhf-linux/build-toolchains.sh b/src/ci/docker/dist-armhf-linux/build-toolchains.sh
new file mode 100755
index 00000000000..df1134d5483
--- /dev/null
+++ b/src/ci/docker/dist-armhf-linux/build-toolchains.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  $@ &> /tmp/build.log
+  rm /tmp/build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  set -x
+}
+
+mkdir build
+cd build
+cp ../arm-linux-gnueabihf.config .config
+ct-ng oldconfig
+hide_output ct-ng build
+cd ..
+rm -rf build
diff --git a/src/ci/docker/dist-armv7-linux/Dockerfile b/src/ci/docker/dist-armv7-linux/Dockerfile
new file mode 100644
index 00000000000..9fcd827fc99
--- /dev/null
+++ b/src/ci/docker/dist-armv7-linux/Dockerfile
@@ -0,0 +1,77 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  automake \
+  bison \
+  bzip2 \
+  ca-certificates \
+  cmake \
+  curl \
+  file \
+  flex \
+  g++ \
+  gawk \
+  gdb \
+  git \
+  gperf \
+  help2man \
+  libncurses-dev \
+  libtool-bin \
+  make \
+  patch \
+  python2.7 \
+  sudo \
+  texinfo \
+  wget \
+  xz-utils \
+  libssl-dev \
+  pkg-config
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+# Ubuntu 16.04 (this contianer) ships with make 4, but something in the
+# toolchains we build below chokes on that, so go back to make 3
+RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \
+      cd make-3.81 && \
+      ./configure --prefix=/usr && \
+      make && \
+      make install && \
+      cd .. && \
+      rm -rf make-3.81
+
+RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \
+      tar xjf - && \
+      cd crosstool-ng && \
+      ./configure --prefix=/usr/local && \
+      make -j$(nproc) && \
+      make install && \
+      cd .. && \
+      rm -rf crosstool-ng
+
+RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild
+RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools
+USER rustbuild
+WORKDIR /tmp
+
+COPY build-toolchains.sh armv7-linux-gnueabihf.config /tmp/
+RUN ./build-toolchains.sh
+
+USER root
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENV PATH=$PATH:/x-tools/armv7-unknown-linux-gnueabihf/bin
+
+ENV CC_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-gcc \
+    AR_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-ar \
+    CXX_armv7_unknown_linux_gnueabihf=armv7-unknown-linux-gnueabihf-g++
+
+ENV HOSTS=armv7-unknown-linux-gnueabihf
+
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config
index 79d6c77c411..79d6c77c411 100644
--- a/src/ci/docker/dist-armv7-aarch64-linux/armv7-linux-gnueabihf.config
+++ b/src/ci/docker/dist-armv7-linux/armv7-linux-gnueabihf.config
diff --git a/src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh b/src/ci/docker/dist-armv7-linux/build-toolchains.sh
index ebd5ef4cfc4..2d395fee792 100755
--- a/src/ci/docker/dist-armv7-aarch64-linux/build-toolchains.sh
+++ b/src/ci/docker/dist-armv7-linux/build-toolchains.sh
@@ -35,11 +35,3 @@ ct-ng oldconfig
 hide_output ct-ng build
 cd ..
 rm -rf build
-
-mkdir build
-cd build
-cp ../aarch64-linux-gnu.config .config
-ct-ng oldconfig
-hide_output ct-ng build
-cd ..
-rm -rf build
diff --git a/src/ci/docker/dist-fuchsia/Dockerfile b/src/ci/docker/dist-fuchsia/Dockerfile
index ed37a9e842e..bfffd9637fc 100644
--- a/src/ci/docker/dist-fuchsia/Dockerfile
+++ b/src/ci/docker/dist-fuchsia/Dockerfile
@@ -29,7 +29,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 ENV \
diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile
index d88ec7aab34..d2727cbdb35 100644
--- a/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile
+++ b/src/ci/docker/dist-i586-gnu-i686-musl/Dockerfile
@@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 ENV RUST_CONFIGURE_ARGS \
diff --git a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh
index a50a25c7913..ad285a57a84 100644
--- a/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh
+++ b/src/ci/docker/dist-i586-gnu-i686-musl/build-musl.sh
@@ -15,11 +15,14 @@ set -ex
 export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
 export CXXFLAGS="-Wa,-mrelax-relocations=no"
 
-MUSL=musl-1.1.14
+MUSL=musl-1.1.16
 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
 cd $MUSL
-CFLAGS="$CFLAGS -m32" ./configure --prefix=/musl-i686 --disable-shared --target=i686
-make -j10
+CC=gcc \
+  CFLAGS="$CFLAGS -m32" \
+  ./configure --prefix=/musl-i686 --disable-shared \
+    --target=i686
+make AR=ar RANLIB=ranlib -j10
 make install
 cd ..
 
diff --git a/src/ci/docker/dist-freebsd/Dockerfile b/src/ci/docker/dist-i686-freebsd/Dockerfile
index 633f58ea474..3b81216c643 100644
--- a/src/ci/docker/dist-freebsd/Dockerfile
+++ b/src/ci/docker/dist-i686-freebsd/Dockerfile
@@ -17,7 +17,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   pkg-config
 
 COPY build-toolchain.sh /tmp/
-RUN /tmp/build-toolchain.sh x86_64
 RUN /tmp/build-toolchain.sh i686
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
@@ -26,19 +25,15 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 ENV \
-    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \
-    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \
-    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++ \
     AR_i686_unknown_freebsd=i686-unknown-freebsd10-ar \
     CC_i686_unknown_freebsd=i686-unknown-freebsd10-gcc \
     CXX_i686_unknown_freebsd=i686-unknown-freebsd10-g++
 
-ENV HOSTS=x86_64-unknown-freebsd
-ENV HOSTS=$HOSTS,i686-unknown-freebsd
+ENV HOSTS=i686-unknown-freebsd
 
 ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-freebsd/build-toolchain.sh b/src/ci/docker/dist-i686-freebsd/build-toolchain.sh
index 5642e6fc937..5642e6fc937 100755
--- a/src/ci/docker/dist-freebsd/build-toolchain.sh
+++ b/src/ci/docker/dist-i686-freebsd/build-toolchain.sh
diff --git a/src/ci/docker/dist-x86-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile
index 18c7a4d2b3e..b322f56f0d0 100644
--- a/src/ci/docker/dist-x86-linux/Dockerfile
+++ b/src/ci/docker/dist-i686-linux/Dockerfile
@@ -2,6 +2,12 @@ FROM centos:5
 
 WORKDIR /build
 
+# Centos 5 is EOL and is no longer available from the usual mirrors, so switch
+# to http://vault.centos.org/
+RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf
+RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo
+RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo
+
 RUN yum upgrade -y && yum install -y \
       curl \
       bzip2 \
@@ -76,11 +82,10 @@ RUN curl -Lo /rustroot/dumb-init \
 ENTRYPOINT ["/rustroot/dumb-init", "--"]
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 ENV HOSTS=i686-unknown-linux-gnu
-ENV HOSTS=$HOSTS,x86_64-unknown-linux-gnu
 
 ENV RUST_CONFIGURE_ARGS \
       --host=$HOSTS \
diff --git a/src/ci/docker/dist-x86-linux/build-binutils.sh b/src/ci/docker/dist-i686-linux/build-binutils.sh
index 80aa1f2a016..80aa1f2a016 100755
--- a/src/ci/docker/dist-x86-linux/build-binutils.sh
+++ b/src/ci/docker/dist-i686-linux/build-binutils.sh
diff --git a/src/ci/docker/dist-x86-linux/build-cmake.sh b/src/ci/docker/dist-i686-linux/build-cmake.sh
index 82e46455cb0..82e46455cb0 100755
--- a/src/ci/docker/dist-x86-linux/build-cmake.sh
+++ b/src/ci/docker/dist-i686-linux/build-cmake.sh
diff --git a/src/ci/docker/dist-x86-linux/build-curl.sh b/src/ci/docker/dist-i686-linux/build-curl.sh
index b7d22755a57..b7d22755a57 100755
--- a/src/ci/docker/dist-x86-linux/build-curl.sh
+++ b/src/ci/docker/dist-i686-linux/build-curl.sh
diff --git a/src/ci/docker/dist-x86-linux/build-gcc.sh b/src/ci/docker/dist-i686-linux/build-gcc.sh
index ab2562538d6..ab2562538d6 100755
--- a/src/ci/docker/dist-x86-linux/build-gcc.sh
+++ b/src/ci/docker/dist-i686-linux/build-gcc.sh
diff --git a/src/ci/docker/dist-x86-linux/build-git.sh b/src/ci/docker/dist-i686-linux/build-git.sh
index 92fa66b496d..92fa66b496d 100755
--- a/src/ci/docker/dist-x86-linux/build-git.sh
+++ b/src/ci/docker/dist-i686-linux/build-git.sh
diff --git a/src/ci/docker/dist-x86-linux/build-headers.sh b/src/ci/docker/dist-i686-linux/build-headers.sh
index 4ce38fd9205..4ce38fd9205 100755
--- a/src/ci/docker/dist-x86-linux/build-headers.sh
+++ b/src/ci/docker/dist-i686-linux/build-headers.sh
diff --git a/src/ci/docker/dist-x86-linux/build-openssl.sh b/src/ci/docker/dist-i686-linux/build-openssl.sh
index 64b1abf82a8..64b1abf82a8 100755
--- a/src/ci/docker/dist-x86-linux/build-openssl.sh
+++ b/src/ci/docker/dist-i686-linux/build-openssl.sh
diff --git a/src/ci/docker/dist-x86-linux/build-python.sh b/src/ci/docker/dist-i686-linux/build-python.sh
index a7a450f3c8d..a7a450f3c8d 100755
--- a/src/ci/docker/dist-x86-linux/build-python.sh
+++ b/src/ci/docker/dist-i686-linux/build-python.sh
diff --git a/src/ci/docker/dist-x86-linux/shared.sh b/src/ci/docker/dist-i686-linux/shared.sh
index 97e6d2908cf..97e6d2908cf 100644
--- a/src/ci/docker/dist-x86-linux/shared.sh
+++ b/src/ci/docker/dist-i686-linux/shared.sh
diff --git a/src/ci/docker/dist-mips-linux/Dockerfile b/src/ci/docker/dist-mips-linux/Dockerfile
index 938c53ae488..33cca061103 100644
--- a/src/ci/docker/dist-mips-linux/Dockerfile
+++ b/src/ci/docker/dist-mips-linux/Dockerfile
@@ -13,12 +13,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils \
   g++-mips-linux-gnu \
-  g++-mipsel-linux-gnu \
   libssl-dev \
   pkg-config
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
@@ -27,7 +26,6 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
 ENV HOSTS=mips-unknown-linux-gnu
-ENV HOSTS=$HOSTS,mipsel-unknown-linux-gnu
 
 ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-mips64-linux/Dockerfile b/src/ci/docker/dist-mips64-linux/Dockerfile
index 45de8100b4f..157de83abb7 100644
--- a/src/ci/docker/dist-mips64-linux/Dockerfile
+++ b/src/ci/docker/dist-mips64-linux/Dockerfile
@@ -13,12 +13,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   gdb \
   xz-utils \
   g++-mips64-linux-gnuabi64 \
-  g++-mips64el-linux-gnuabi64 \
   libssl-dev \
   pkg-config
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
@@ -27,7 +26,6 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
 ENV HOSTS=mips64-unknown-linux-gnuabi64
-ENV HOSTS=$HOSTS,mips64el-unknown-linux-gnuabi64
 
 ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-mips64el-linux/Dockerfile b/src/ci/docker/dist-mips64el-linux/Dockerfile
new file mode 100644
index 00000000000..739d5ff6ac4
--- /dev/null
+++ b/src/ci/docker/dist-mips64el-linux/Dockerfile
@@ -0,0 +1,31 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  xz-utils \
+  g++-mips64el-linux-gnuabi64 \
+  libssl-dev \
+  pkg-config
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+ENV HOSTS=mips64el-unknown-linux-gnuabi64
+
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-mipsel-linux/Dockerfile b/src/ci/docker/dist-mipsel-linux/Dockerfile
new file mode 100644
index 00000000000..9339063bc19
--- /dev/null
+++ b/src/ci/docker/dist-mipsel-linux/Dockerfile
@@ -0,0 +1,31 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  sudo \
+  gdb \
+  xz-utils \
+  g++-mipsel-linux-gnu \
+  libssl-dev \
+  pkg-config
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+ENV HOSTS=mipsel-unknown-linux-gnu
+
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-powerpc-linux/Dockerfile b/src/ci/docker/dist-powerpc-linux/Dockerfile
index c1e5e863ae0..92342caed2a 100644
--- a/src/ci/docker/dist-powerpc-linux/Dockerfile
+++ b/src/ci/docker/dist-powerpc-linux/Dockerfile
@@ -63,7 +63,7 @@ RUN ./build-powerpc-toolchain.sh
 USER root
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 ENV PATH=$PATH:/x-tools/powerpc-unknown-linux-gnu/bin
diff --git a/src/ci/docker/dist-powerpc64-linux/Dockerfile b/src/ci/docker/dist-powerpc64-linux/Dockerfile
index 7413c327323..182dfd93cc7 100644
--- a/src/ci/docker/dist-powerpc64-linux/Dockerfile
+++ b/src/ci/docker/dist-powerpc64-linux/Dockerfile
@@ -62,12 +62,8 @@ RUN ./build-powerpc64-toolchain.sh
 
 USER root
 
-RUN apt-get install -y --no-install-recommends rpm2cpio cpio
-COPY build-powerpc64le-toolchain.sh /tmp/
-RUN ./build-powerpc64le-toolchain.sh
-
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin
@@ -75,13 +71,9 @@ ENV PATH=$PATH:/x-tools/powerpc64-unknown-linux-gnu/bin
 ENV \
     AR_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-ar \
     CC_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-gcc \
-    CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++ \
-    AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \
-    CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \
-    CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++
+    CXX_powerpc64_unknown_linux_gnu=powerpc64-unknown-linux-gnu-g++
 
 ENV HOSTS=powerpc64-unknown-linux-gnu
-ENV HOSTS=$HOSTS,powerpc64le-unknown-linux-gnu
 
 ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-powerpc64le-linux/Dockerfile b/src/ci/docker/dist-powerpc64le-linux/Dockerfile
new file mode 100644
index 00000000000..6b9f964d5a3
--- /dev/null
+++ b/src/ci/docker/dist-powerpc64le-linux/Dockerfile
@@ -0,0 +1,77 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  automake \
+  bison \
+  bzip2 \
+  ca-certificates \
+  cmake \
+  curl \
+  file \
+  flex \
+  g++ \
+  gawk \
+  gdb \
+  git \
+  gperf \
+  help2man \
+  libncurses-dev \
+  libtool-bin \
+  make \
+  patch \
+  python2.7 \
+  sudo \
+  texinfo \
+  wget \
+  xz-utils \
+  libssl-dev \
+ pkg-config
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+# Ubuntu 16.04 (this contianer) ships with make 4, but something in the
+# toolchains we build below chokes on that, so go back to make 3
+RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \
+      cd make-3.81 && \
+      ./configure --prefix=/usr && \
+      make && \
+      make install && \
+      cd .. && \
+      rm -rf make-3.81
+
+RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \
+      tar xjf - && \
+      cd crosstool-ng && \
+      ./configure --prefix=/usr/local && \
+      make -j$(nproc) && \
+      make install && \
+      cd .. && \
+      rm -rf crosstool-ng
+
+RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild
+RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools
+USER rustbuild
+WORKDIR /tmp
+
+USER root
+
+RUN apt-get install -y --no-install-recommends rpm2cpio cpio
+COPY shared.sh build-powerpc64le-toolchain.sh /tmp/
+RUN ./build-powerpc64le-toolchain.sh
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENV \
+    AR_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-ar \
+    CC_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-gcc \
+    CXX_powerpc64le_unknown_linux_gnu=powerpc64le-linux-gnu-g++
+
+ENV HOSTS=powerpc64le-unknown-linux-gnu
+
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh
index 4d3e638916d..4d3e638916d 100755
--- a/src/ci/docker/dist-powerpc64-linux/build-powerpc64le-toolchain.sh
+++ b/src/ci/docker/dist-powerpc64le-linux/build-powerpc64le-toolchain.sh
diff --git a/src/ci/docker/dist-powerpc64le-linux/shared.sh b/src/ci/docker/dist-powerpc64le-linux/shared.sh
new file mode 100644
index 00000000000..97e6d2908cf
--- /dev/null
+++ b/src/ci/docker/dist-powerpc64le-linux/shared.sh
@@ -0,0 +1,25 @@
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  $@ &> /tmp/build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  set -x
+}
diff --git a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile b/src/ci/docker/dist-s390x-linux/Dockerfile
index 4180006690f..7c94f713e18 100644
--- a/src/ci/docker/dist-s390x-linux-netbsd/Dockerfile
+++ b/src/ci/docker/dist-s390x-linux/Dockerfile
@@ -60,27 +60,20 @@ COPY patches/ /tmp/patches/
 COPY s390x-linux-gnu.config build-s390x-toolchain.sh /tmp/
 RUN ./build-s390x-toolchain.sh
 
-COPY build-netbsd-toolchain.sh /tmp/
-RUN ./build-netbsd-toolchain.sh
-
 USER root
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
-ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin:/x-tools/x86_64-unknown-netbsd/bin
+ENV PATH=$PATH:/x-tools/s390x-ibm-linux-gnu/bin
 
 ENV \
-    AR_x86_64_unknown_netbsd=x86_64--netbsd-ar \
-    CC_x86_64_unknown_netbsd=x86_64--netbsd-gcc-sysroot \
-    CXX_x86_64_unknown_netbsd=x86_64--netbsd-g++-sysroot \
     CC_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-gcc \
     AR_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-ar \
     CXX_s390x_unknown_linux_gnu=s390x-ibm-linux-gnu-g++
 
-ENV HOSTS=x86_64-unknown-netbsd
-ENV HOSTS=$HOSTS,s390x-unknown-linux-gnu
+ENV HOSTS=s390x-unknown-linux-gnu
 
 ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
 ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh b/src/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh
index b4995e20dc6..b4995e20dc6 100755
--- a/src/ci/docker/dist-s390x-linux-netbsd/build-s390x-toolchain.sh
+++ b/src/ci/docker/dist-s390x-linux/build-s390x-toolchain.sh
diff --git a/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch b/src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch
index cba416ed2f7..cba416ed2f7 100644
--- a/src/ci/docker/dist-s390x-linux-netbsd/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch
+++ b/src/ci/docker/dist-s390x-linux/patches/glibc/2.12.2/001-Use-.machine-to-prevent-AS-from-complaining-about-z9.patch
diff --git a/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config b/src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config
index fa5e4510987..fa5e4510987 100644
--- a/src/ci/docker/dist-s390x-linux-netbsd/s390x-linux-gnu.config
+++ b/src/ci/docker/dist-s390x-linux/s390x-linux-gnu.config
diff --git a/src/ci/docker/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/dist-x86_64-freebsd/Dockerfile
new file mode 100644
index 00000000000..a2939c8c485
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-freebsd/Dockerfile
@@ -0,0 +1,39 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  g++ \
+  make \
+  file \
+  curl \
+  ca-certificates \
+  python2.7 \
+  git \
+  cmake \
+  sudo \
+  bzip2 \
+  xz-utils \
+  wget \
+  libssl-dev \
+  pkg-config
+
+COPY build-toolchain.sh /tmp/
+RUN /tmp/build-toolchain.sh x86_64
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENV \
+    AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \
+    CC_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-gcc \
+    CXX_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-g++
+
+ENV HOSTS=x86_64-unknown-freebsd
+
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh b/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh
new file mode 100755
index 00000000000..5642e6fc937
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-freebsd/build-toolchain.sh
@@ -0,0 +1,112 @@
+#!/bin/bash
+# Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+
+ARCH=$1
+BINUTILS=2.25.1
+GCC=5.3.0
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  $@ &> /tmp/build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  set -x
+}
+
+mkdir binutils
+cd binutils
+
+# First up, build binutils
+curl https://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS.tar.bz2 | tar xjf -
+mkdir binutils-build
+cd binutils-build
+hide_output ../binutils-$BINUTILS/configure \
+  --target=$ARCH-unknown-freebsd10
+hide_output make -j10
+hide_output make install
+cd ../..
+rm -rf binutils
+
+# Next, download the FreeBSD libc and relevant header files
+
+mkdir freebsd
+case "$ARCH" in
+    x86_64)
+        URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/amd64/10.2-RELEASE/base.txz
+        ;;
+    i686)
+        URL=ftp://ftp.freebsd.org/pub/FreeBSD/releases/i386/10.2-RELEASE/base.txz
+        ;;
+esac
+curl $URL | tar xJf - -C freebsd ./usr/include ./usr/lib ./lib
+
+dst=/usr/local/$ARCH-unknown-freebsd10
+
+cp -r freebsd/usr/include $dst/
+cp freebsd/usr/lib/crt1.o $dst/lib
+cp freebsd/usr/lib/Scrt1.o $dst/lib
+cp freebsd/usr/lib/crti.o $dst/lib
+cp freebsd/usr/lib/crtn.o $dst/lib
+cp freebsd/usr/lib/libc.a $dst/lib
+cp freebsd/usr/lib/libutil.a $dst/lib
+cp freebsd/usr/lib/libutil_p.a $dst/lib
+cp freebsd/usr/lib/libm.a $dst/lib
+cp freebsd/usr/lib/librt.so.1 $dst/lib
+cp freebsd/usr/lib/libexecinfo.so.1 $dst/lib
+cp freebsd/lib/libc.so.7 $dst/lib
+cp freebsd/lib/libm.so.5 $dst/lib
+cp freebsd/lib/libutil.so.9 $dst/lib
+cp freebsd/lib/libthr.so.3 $dst/lib/libpthread.so
+
+ln -s libc.so.7 $dst/lib/libc.so
+ln -s libm.so.5 $dst/lib/libm.so
+ln -s librt.so.1 $dst/lib/librt.so
+ln -s libutil.so.9 $dst/lib/libutil.so
+ln -s libexecinfo.so.1 $dst/lib/libexecinfo.so
+rm -rf freebsd
+
+# Finally, download and build gcc to target FreeBSD
+mkdir gcc
+cd gcc
+curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
+cd gcc-$GCC
+./contrib/download_prerequisites
+
+mkdir ../gcc-build
+cd ../gcc-build
+hide_output ../gcc-$GCC/configure                \
+  --enable-languages=c,c++                       \
+  --target=$ARCH-unknown-freebsd10               \
+  --disable-multilib                             \
+  --disable-nls                                  \
+  --disable-libgomp                              \
+  --disable-libquadmath                          \
+  --disable-libssp                               \
+  --disable-libvtv                               \
+  --disable-libcilkrts                           \
+  --disable-libada                               \
+  --disable-libsanitizer                         \
+  --disable-libquadmath-support                  \
+  --disable-lto
+hide_output make -j10
+hide_output make install
+cd ../..
+rm -rf gcc
diff --git a/src/ci/docker/dist-x86_64-linux/Dockerfile b/src/ci/docker/dist-x86_64-linux/Dockerfile
new file mode 100644
index 00000000000..cbe5f5936a5
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-linux/Dockerfile
@@ -0,0 +1,101 @@
+FROM centos:5
+
+WORKDIR /build
+
+# Centos 5 is EOL and is no longer available from the usual mirrors, so switch
+# to http://vault.centos.org/
+RUN sed -i 's/enabled=1/enabled=0/' /etc/yum/pluginconf.d/fastestmirror.conf
+RUN sed -i 's/mirrorlist/#mirrorlist/' /etc/yum.repos.d/*.repo
+RUN sed -i 's/#\(baseurl.*\)mirror.centos.org/\1107.158.252.35/' /etc/yum.repos.d/*.repo
+
+RUN yum upgrade -y && yum install -y \
+      curl \
+      bzip2 \
+      gcc \
+      gcc-c++ \
+      make \
+      glibc-devel \
+      perl \
+      zlib-devel \
+      file \
+      xz \
+      which \
+      pkgconfig \
+      wget \
+      autoconf \
+      gettext
+
+ENV PATH=/rustroot/bin:$PATH
+ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib
+ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig
+WORKDIR /tmp
+COPY shared.sh build-binutils.sh /tmp/
+
+# We need a build of openssl which supports SNI to download artifacts from
+# static.rust-lang.org. This'll be used to link into libcurl below (and used
+# later as well), so build a copy of OpenSSL with dynamic libraries into our
+# generic root.
+COPY build-openssl.sh /tmp/
+RUN ./build-openssl.sh
+
+# The `curl` binary on CentOS doesn't support SNI which is needed for fetching
+# some https urls we have, so install a new version of libcurl + curl which is
+# using the openssl we just built previously.
+#
+# Note that we also disable a bunch of optional features of curl that we don't
+# really need.
+COPY build-curl.sh /tmp/
+RUN ./build-curl.sh
+
+# binutils < 2.22 has a bug where the 32-bit executables it generates
+# immediately segfault in Rust, so we need to install our own binutils.
+#
+# See https://github.com/rust-lang/rust/issues/20440 for more info
+RUN ./build-binutils.sh
+
+# Need a newer version of gcc than centos has to compile LLVM nowadays
+COPY build-gcc.sh /tmp/
+RUN ./build-gcc.sh
+
+# CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+
+COPY build-python.sh /tmp/
+RUN ./build-python.sh
+
+# Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for
+# cloning, so download and build it here.
+COPY build-git.sh /tmp/
+RUN ./build-git.sh
+
+# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS
+# only has 2.6.4, so build our own
+COPY build-cmake.sh /tmp/
+RUN ./build-cmake.sh
+
+# for sanitizers, we need kernel headers files newer than the ones CentOS ships
+# with so we install newer ones here
+COPY build-headers.sh /tmp/
+RUN ./build-headers.sh
+
+RUN curl -Lo /rustroot/dumb-init \
+      https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64 && \
+      chmod +x /rustroot/dumb-init
+ENTRYPOINT ["/rustroot/dumb-init", "--"]
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENV HOSTS=x86_64-unknown-linux-gnu
+
+ENV RUST_CONFIGURE_ARGS \
+      --host=$HOSTS \
+      --enable-extended \
+      --enable-sanitizers
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
+
+# This is the only builder which will create source tarballs
+ENV DIST_SRC 1
+
+# When we build cargo in this container, we don't want it to use the system
+# libcurl, instead it should compile its own.
+ENV LIBCURL_NO_PKG_CONFIG 1
diff --git a/src/ci/docker/dist-x86_64-linux/build-binutils.sh b/src/ci/docker/dist-x86_64-linux/build-binutils.sh
new file mode 100755
index 00000000000..80aa1f2a016
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-linux/build-binutils.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+
+source shared.sh
+
+curl https://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2 | tar xfj -
+
+mkdir binutils-build
+cd binutils-build
+hide_output ../binutils-2.25.1/configure --prefix=/rustroot
+hide_output make -j10
+hide_output make install
+
+cd ..
+rm -rf binutils-build
+rm -rf binutils-2.25.1
diff --git a/src/ci/docker/dist-x86_64-linux/build-cmake.sh b/src/ci/docker/dist-x86_64-linux/build-cmake.sh
new file mode 100755
index 00000000000..82e46455cb0
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-linux/build-cmake.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+source shared.sh
+
+curl https://cmake.org/files/v3.6/cmake-3.6.3.tar.gz | tar xzf -
+
+mkdir cmake-build
+cd cmake-build
+hide_output ../cmake-3.6.3/configure --prefix=/rustroot
+hide_output make -j10
+hide_output make install
+
+cd ..
+rm -rf cmake-build
+rm -rf cmake-3.6.3
diff --git a/src/ci/docker/dist-x86_64-linux/build-curl.sh b/src/ci/docker/dist-x86_64-linux/build-curl.sh
new file mode 100755
index 00000000000..b7d22755a57
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-linux/build-curl.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+source shared.sh
+
+VERSION=7.51.0
+
+curl http://cool.haxx.se/download/curl-$VERSION.tar.bz2 | tar xjf -
+
+mkdir curl-build
+cd curl-build
+hide_output ../curl-$VERSION/configure \
+      --prefix=/rustroot \
+      --with-ssl=/rustroot \
+      --disable-sspi \
+      --disable-gopher \
+      --disable-smtp \
+      --disable-smb \
+      --disable-imap \
+      --disable-pop3 \
+      --disable-tftp \
+      --disable-telnet \
+      --disable-manual \
+      --disable-dict \
+      --disable-rtsp \
+      --disable-ldaps \
+      --disable-ldap
+hide_output make -j10
+hide_output make install
+
+cd ..
+rm -rf curl-build
+rm -rf curl-$VERSION
+yum erase -y curl
diff --git a/src/ci/docker/dist-x86_64-linux/build-gcc.sh b/src/ci/docker/dist-x86_64-linux/build-gcc.sh
new file mode 100755
index 00000000000..ab2562538d6
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-linux/build-gcc.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+
+source shared.sh
+
+GCC=4.8.5
+
+curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf -
+cd gcc-$GCC
+./contrib/download_prerequisites
+mkdir ../gcc-build
+cd ../gcc-build
+hide_output ../gcc-$GCC/configure \
+    --prefix=/rustroot \
+    --enable-languages=c,c++
+hide_output make -j10
+hide_output make install
+ln -nsf gcc /rustroot/bin/cc
+
+cd ..
+rm -rf gcc-build
+rm -rf gcc-$GCC
+yum erase -y gcc gcc-c++ binutils
diff --git a/src/ci/docker/dist-x86_64-linux/build-git.sh b/src/ci/docker/dist-x86_64-linux/build-git.sh
new file mode 100755
index 00000000000..92fa66b496d
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-linux/build-git.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+source shared.sh
+
+curl https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf -
+
+cd git-2.10.0
+make configure
+hide_output ./configure --prefix=/rustroot
+hide_output make -j10
+hide_output make install
+
+cd ..
+rm -rf git-2.10.0
diff --git a/src/ci/docker/dist-x86_64-linux/build-headers.sh b/src/ci/docker/dist-x86_64-linux/build-headers.sh
new file mode 100755
index 00000000000..4ce38fd9205
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-linux/build-headers.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+source shared.sh
+
+curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x
+
+cd linux-3.2.84
+hide_output make mrproper
+hide_output make INSTALL_HDR_PATH=dest headers_install
+
+find dest/include \( -name .install -o -name ..install.cmd \) -delete
+yes | cp -fr dest/include/* /usr/include
+
+cd ..
+rm -rf linux-3.2.84
diff --git a/src/ci/docker/dist-x86_64-linux/build-openssl.sh b/src/ci/docker/dist-x86_64-linux/build-openssl.sh
new file mode 100755
index 00000000000..64b1abf82a8
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-linux/build-openssl.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+source shared.sh
+
+VERSION=1.0.2j
+
+curl https://www.openssl.org/source/openssl-$VERSION.tar.gz | tar xzf -
+
+cd openssl-$VERSION
+hide_output ./config --prefix=/rustroot shared -fPIC
+hide_output make -j10
+hide_output make install
+cd ..
+rm -rf openssl-$VERSION
+
+# Make the system cert collection available to the new install.
+ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/
diff --git a/src/ci/docker/dist-x86_64-linux/build-python.sh b/src/ci/docker/dist-x86_64-linux/build-python.sh
new file mode 100755
index 00000000000..a7a450f3c8d
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-linux/build-python.sh
@@ -0,0 +1,30 @@
+#!/bin/bash
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+set -ex
+source shared.sh
+
+curl https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz | \
+  tar xzf -
+
+mkdir python-build
+cd python-build
+
+# Gotta do some hackery to tell python about our custom OpenSSL build, but other
+# than that fairly normal.
+CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \
+    hide_output ../Python-2.7.12/configure --prefix=/rustroot
+hide_output make -j10
+hide_output make install
+
+cd ..
+rm -rf python-build
+rm -rf Python-2.7.12
diff --git a/src/ci/docker/dist-x86_64-linux/shared.sh b/src/ci/docker/dist-x86_64-linux/shared.sh
new file mode 100644
index 00000000000..97e6d2908cf
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-linux/shared.sh
@@ -0,0 +1,25 @@
+# Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+# file at the top-level directory of this distribution and at
+# http://rust-lang.org/COPYRIGHT.
+#
+# Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+# option. This file may not be copied, modified, or distributed
+# except according to those terms.
+
+hide_output() {
+  set +x
+  on_err="
+echo ERROR: An error was encountered with the build.
+cat /tmp/build.log
+exit 1
+"
+  trap "$on_err" ERR
+  bash -c "while true; do sleep 30; echo \$(date) - building ...; done" &
+  PING_LOOP_PID=$!
+  $@ &> /tmp/build.log
+  trap - ERR
+  kill $PING_LOOP_PID
+  set -x
+}
diff --git a/src/ci/docker/dist-x86_64-musl/Dockerfile b/src/ci/docker/dist-x86_64-musl/Dockerfile
index 085aa351659..a41c0cca3b5 100644
--- a/src/ci/docker/dist-x86_64-musl/Dockerfile
+++ b/src/ci/docker/dist-x86_64-musl/Dockerfile
@@ -26,7 +26,7 @@ RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-ini
 ENTRYPOINT ["/usr/bin/dumb-init", "--"]
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 ENV RUST_CONFIGURE_ARGS \
diff --git a/src/ci/docker/dist-x86_64-musl/build-musl.sh b/src/ci/docker/dist-x86_64-musl/build-musl.sh
index 86bb259c854..776da009397 100644
--- a/src/ci/docker/dist-x86_64-musl/build-musl.sh
+++ b/src/ci/docker/dist-x86_64-musl/build-musl.sh
@@ -15,7 +15,7 @@ set -ex
 export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
 export CXXFLAGS="-Wa,-mrelax-relocations=no"
 
-MUSL=musl-1.1.14
+MUSL=musl-1.1.16
 curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
 cd $MUSL
 ./configure --prefix=/musl-x86_64 --disable-shared
diff --git a/src/ci/docker/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/dist-x86_64-netbsd/Dockerfile
new file mode 100644
index 00000000000..a1dd9a3724a
--- /dev/null
+++ b/src/ci/docker/dist-x86_64-netbsd/Dockerfile
@@ -0,0 +1,78 @@
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+  automake \
+  bison \
+  bzip2 \
+  ca-certificates \
+  cmake \
+  curl \
+  file \
+  flex \
+  g++ \
+  gawk \
+  gdb \
+  git \
+  gperf \
+  help2man \
+  libncurses-dev \
+  libtool-bin \
+  make \
+  patch \
+  python2.7 \
+  sudo \
+  texinfo \
+  wget \
+  xz-utils \
+  libssl-dev \
+  pkg-config
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+    dpkg -i dumb-init_*.deb && \
+    rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+# Ubuntu 16.04 (this contianer) ships with make 4, but something in the
+# toolchains we build below chokes on that, so go back to make 3
+RUN curl https://ftp.gnu.org/gnu/make/make-3.81.tar.gz | tar xzf - && \
+      cd make-3.81 && \
+      ./configure --prefix=/usr && \
+      make && \
+      make install && \
+      cd .. && \
+      rm -rf make-3.81
+
+RUN curl http://crosstool-ng.org/download/crosstool-ng/crosstool-ng-1.22.0.tar.bz2 | \
+      tar xjf - && \
+      cd crosstool-ng && \
+      ./configure --prefix=/usr/local && \
+      make -j$(nproc) && \
+      make install && \
+      cd .. && \
+      rm -rf crosstool-ng
+
+RUN groupadd -r rustbuild && useradd -m -r -g rustbuild rustbuild
+RUN mkdir /x-tools && chown rustbuild:rustbuild /x-tools
+USER rustbuild
+WORKDIR /tmp
+
+COPY build-netbsd-toolchain.sh /tmp/
+RUN ./build-netbsd-toolchain.sh
+
+USER root
+
+RUN curl -o /usr/local/bin/sccache \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
+      chmod +x /usr/local/bin/sccache
+
+ENV PATH=$PATH:/x-tools/x86_64-unknown-netbsd/bin
+
+ENV \
+    AR_x86_64_unknown_netbsd=x86_64--netbsd-ar \
+    CC_x86_64_unknown_netbsd=x86_64--netbsd-gcc-sysroot \
+    CXX_x86_64_unknown_netbsd=x86_64--netbsd-g++-sysroot
+
+ENV HOSTS=x86_64-unknown-netbsd
+
+ENV RUST_CONFIGURE_ARGS --host=$HOSTS --enable-extended
+ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh
index ea335a24973..ea335a24973 100755
--- a/src/ci/docker/dist-s390x-linux-netbsd/build-netbsd-toolchain.sh
+++ b/src/ci/docker/dist-x86_64-netbsd/build-netbsd-toolchain.sh
diff --git a/src/ci/docker/emscripten/Dockerfile b/src/ci/docker/emscripten/Dockerfile
index 77cf54a19a7..ffdb1d18a94 100644
--- a/src/ci/docker/emscripten/Dockerfile
+++ b/src/ci/docker/emscripten/Dockerfile
@@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   lib32stdc++6
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/ci/docker/i686-gnu-nopt/Dockerfile b/src/ci/docker/i686-gnu-nopt/Dockerfile
index c84cf56e4e8..34d0567a440 100644
--- a/src/ci/docker/i686-gnu-nopt/Dockerfile
+++ b/src/ci/docker/i686-gnu-nopt/Dockerfile
@@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/ci/docker/i686-gnu/Dockerfile b/src/ci/docker/i686-gnu/Dockerfile
index f4bb9083b85..960a0fa7a38 100644
--- a/src/ci/docker/i686-gnu/Dockerfile
+++ b/src/ci/docker/i686-gnu/Dockerfile
@@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/ci/docker/x86_64-gnu-aux/Dockerfile b/src/ci/docker/x86_64-gnu-aux/Dockerfile
index 68184c65cf1..9871df90e00 100644
--- a/src/ci/docker/x86_64-gnu-aux/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-aux/Dockerfile
@@ -15,7 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   pkg-config
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/ci/docker/x86_64-gnu-debug/Dockerfile b/src/ci/docker/x86_64-gnu-debug/Dockerfile
index 6320a806fc3..197b0ec9b9b 100644
--- a/src/ci/docker/x86_64-gnu-debug/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-debug/Dockerfile
@@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile
index 180f53ec33f..60af302791a 100644
--- a/src/ci/docker/x86_64-gnu-distcheck/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-distcheck/Dockerfile
@@ -16,7 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   pkg-config
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile
index 4500fc0f642..4ec0b5c1525 100644
--- a/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-full-bootstrap/Dockerfile
@@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/ci/docker/x86_64-gnu-incremental/Dockerfile b/src/ci/docker/x86_64-gnu-incremental/Dockerfile
index ad1227fa581..6448f88950f 100644
--- a/src/ci/docker/x86_64-gnu-incremental/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-incremental/Dockerfile
@@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile
index f1240201805..c00667fe1dd 100644
--- a/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-llvm-3.7/Dockerfile
@@ -17,7 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/ci/docker/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/x86_64-gnu-nopt/Dockerfile
index fa9707d1a73..7284d231b84 100644
--- a/src/ci/docker/x86_64-gnu-nopt/Dockerfile
+++ b/src/ci/docker/x86_64-gnu-nopt/Dockerfile
@@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/ci/docker/x86_64-gnu/Dockerfile b/src/ci/docker/x86_64-gnu/Dockerfile
index e5d89034dbe..1dce84bc5fd 100644
--- a/src/ci/docker/x86_64-gnu/Dockerfile
+++ b/src/ci/docker/x86_64-gnu/Dockerfile
@@ -14,7 +14,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
   xz-utils
 
 RUN curl -o /usr/local/bin/sccache \
-      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-03-24-sccache-x86_64-unknown-linux-musl && \
+      https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-04-04-sccache-x86_64-unknown-linux-musl && \
       chmod +x /usr/local/bin/sccache
 
 RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md
index 292f5a1ec81..20812de524a 100644
--- a/src/doc/unstable-book/src/SUMMARY.md
+++ b/src/doc/unstable-book/src/SUMMARY.md
@@ -123,6 +123,7 @@
 - [no_debug](no-debug.md)
 - [non_ascii_idents](non-ascii-idents.md)
 - [nonzero](nonzero.md)
+- [offset_to](offset-to.md)
 - [omit_gdb_pretty_printer_section](omit-gdb-pretty-printer-section.md)
 - [on_unimplemented](on-unimplemented.md)
 - [once_poison](once-poison.md)
@@ -171,6 +172,7 @@
 - [slice_concat_ext](slice-concat-ext.md)
 - [slice_get_slice](slice-get-slice.md)
 - [slice_patterns](slice-patterns.md)
+- [slice_rsplit](slice-rsplit.md)
 - [sort_internals](sort-internals.md)
 - [sort_unstable](sort-unstable.md)
 - [specialization](specialization.md)
@@ -203,11 +205,11 @@
 - [unwind_attributes](unwind-attributes.md)
 - [update_panic_count](update-panic-count.md)
 - [use_extern_macros](use-extern-macros.md)
+- [used](used.md)
 - [utf8_error_error_len](utf8-error-error-len.md)
 - [vec_remove_item](vec-remove-item.md)
 - [windows_c](windows-c.md)
 - [windows_handle](windows-handle.md)
 - [windows_net](windows-net.md)
 - [windows_stdio](windows-stdio.md)
-- [windows_subsystem](windows-subsystem.md)
 - [zero_one](zero-one.md)
diff --git a/src/doc/unstable-book/src/offset-to.md b/src/doc/unstable-book/src/offset-to.md
new file mode 100644
index 00000000000..03d990eb4ae
--- /dev/null
+++ b/src/doc/unstable-book/src/offset-to.md
@@ -0,0 +1,7 @@
+# `offset_to`
+
+The tracking issue for this feature is: [#41079]
+
+[#41079]: https://github.com/rust-lang/rust/issues/41079
+
+------------------------
diff --git a/src/doc/unstable-book/src/slice-rsplit.md b/src/doc/unstable-book/src/slice-rsplit.md
new file mode 100644
index 00000000000..8c2954f7294
--- /dev/null
+++ b/src/doc/unstable-book/src/slice-rsplit.md
@@ -0,0 +1,10 @@
+# `slice_rsplit`
+
+The tracking issue for this feature is: [#41020]
+
+[#41020]: https://github.com/rust-lang/rust/issues/41020
+
+------------------------
+
+The `slice_rsplit` feature enables two methods on slices:
+`slice.rsplit(predicate)` and `slice.rsplit_mut(predicate)`.
diff --git a/src/doc/unstable-book/src/used.md b/src/doc/unstable-book/src/used.md
new file mode 100644
index 00000000000..75a8b2774f4
--- /dev/null
+++ b/src/doc/unstable-book/src/used.md
@@ -0,0 +1,153 @@
+# `used`
+
+The tracking issue for this feature
+is: [40289](https://github.com/rust-lang/rust/issues/40289).
+
+------------------------
+
+The `#[used]` attribute can be applied to `static` variables to prevent the Rust
+compiler from optimizing them away even if they appear to be unused by the crate
+(appear to be "dead code").
+
+``` rust
+#![feature(used)]
+
+#[used]
+static FOO: i32 = 1;
+
+static BAR: i32 = 2;
+
+fn main() {}
+```
+
+If you compile this program into an object file, you'll see that `FOO` makes it
+to the object file but `BAR` doesn't. Neither static variable is used by the
+program.
+
+``` text
+$ rustc -C opt-level=3 --emit=obj used.rs
+
+$ nm -C used.o
+0000000000000000 T main
+                 U std::rt::lang_start
+0000000000000000 r used::FOO
+0000000000000000 t used::main
+```
+
+Note that the *linker* knows nothing about the `#[used]` attribute and will
+remove `#[used]` symbols if they are not referenced by other parts of the
+program:
+
+``` text
+$ rustc -C opt-level=3 used.rs
+
+$ nm -C used | grep FOO
+```
+
+"This doesn't sound too useful then!" you may think but keep reading.
+
+To preserve the symbols all the way to the final binary, you'll need the
+cooperation of the linker. Here's one example:
+
+The ELF standard defines two special sections, `.init_array` and
+`.pre_init_array`, that may contain function pointers which will be executed
+*before* the `main` function is invoked. The linker will preserve symbols placed
+in these sections (at least when linking programs that target the `*-*-linux-*`
+targets).
+
+``` rust,ignore
+#![feature(used)]
+
+extern "C" fn before_main() {
+    println!("Hello, world!");
+}
+
+#[link_section = ".init_array"]
+#[used]
+static INIT_ARRAY: [extern "C" fn(); 1] = [before_main];
+
+fn main() {}
+```
+
+So, `#[used]` and `#[link_section]` can be combined to obtain "life before
+main".
+
+``` text
+$ rustc -C opt-level=3 before-main.rs
+
+$ ./before-main
+Hello, world!
+```
+
+Another example: ARM Cortex-M microcontrollers need their reset handler, a
+pointer to the function that will executed right after the microcontroller is
+turned on, to be placed near the start of their FLASH memory to boot properly.
+
+This condition can be met using `#[used]` and `#[link_section]` plus a linker
+script.
+
+``` rust,ignore
+#![feature(lang_items)]
+#![feature(used)]
+#![no_main]
+#![no_std]
+
+extern "C" fn reset_handler() -> ! {
+    loop {}
+}
+
+#[link_section = ".reset_handler"]
+#[used]
+static RESET_HANDLER: extern "C" fn() -> ! = reset_handler;
+
+#[lang = "panic_fmt"]
+fn panic_fmt() {}
+```
+
+``` text
+MEMORY
+{
+  FLASH : ORIGIN = 0x08000000, LENGTH = 128K
+  RAM : ORIGIN = 0x20000000, LENGTH = 20K
+}
+
+SECTIONS
+{
+  .text ORIGIN(FLASH) :
+  {
+    /* Vector table */
+    LONG(ORIGIN(RAM) + LENGTH(RAM)); /* initial SP value */
+    KEEP(*(.reset_handler));
+
+    /* Omitted: The rest of the vector table */
+
+    *(.text.*);
+  } > FLASH
+
+  /DISCARD/ :
+  {
+    /* Unused unwinding stuff */
+    *(.ARM.exidx.*)
+  }
+}
+```
+
+``` text
+$ xargo rustc --target thumbv7m-none-eabi --release -- \
+    -C link-arg=-Tlink.x -C link-arg=-nostartfiles
+
+$ arm-none-eabi-objdump -Cd target/thumbv7m-none-eabi/release/app
+./target/thumbv7m-none-eabi/release/app:     file format elf32-littlearm
+
+
+Disassembly of section .text:
+
+08000000 <app::RESET_HANDLER-0x4>:
+ 8000000:       20005000        .word   0x20005000
+
+08000004 <app::RESET_HANDLER>:
+ 8000004:       08000009                                ....
+
+08000008 <app::reset_handler>:
+ 8000008:       e7fe            b.n     8000008 <app::reset_handler>
+```
diff --git a/src/doc/unstable-book/src/windows-subsystem.md b/src/doc/unstable-book/src/windows-subsystem.md
deleted file mode 100644
index 80583352fbf..00000000000
--- a/src/doc/unstable-book/src/windows-subsystem.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# `windows_subsystem`
-
-The tracking issue for this feature is: [#37499]
-
-[#37499]: https://github.com/rust-lang/rust/issues/37499
-
-------------------------
-
-
-
diff --git a/src/etc/char_private.py b/src/etc/char_private.py
index 9d15f98e067..75ab3f1a17b 100644
--- a/src/etc/char_private.py
+++ b/src/etc/char_private.py
@@ -76,6 +76,66 @@ def get_codepoints(f):
     for c in range(prev_codepoint + 1, NUM_CODEPOINTS):
         yield Codepoint(c, None)
 
+def compress_singletons(singletons):
+    uppers = [] # (upper, # items in lowers)
+    lowers = []
+
+    for i in singletons:
+        upper = i >> 8
+        lower = i & 0xff
+        if len(uppers) == 0 or uppers[-1][0] != upper:
+            uppers.append((upper, 1))
+        else:
+            upper, count = uppers[-1]
+            uppers[-1] = upper, count + 1
+        lowers.append(lower)
+
+    return uppers, lowers
+
+def compress_normal(normal):
+    # lengths 0x00..0x7f are encoded as 00, 01, ..., 7e, 7f
+    # lengths 0x80..0x7fff are encoded as 80 80, 80 81, ..., ff fe, ff ff
+    compressed = [] # [truelen, (truelenaux), falselen, (falselenaux)]
+
+    prev_start = 0
+    for start, count in normal:
+        truelen = start - prev_start
+        falselen = count
+        prev_start = start + count
+
+        assert truelen < 0x8000 and falselen < 0x8000
+        entry = []
+        if truelen > 0x7f:
+            entry.append(0x80 | (truelen >> 8))
+            entry.append(truelen & 0xff)
+        else:
+            entry.append(truelen & 0x7f)
+        if falselen > 0x7f:
+            entry.append(0x80 | (falselen >> 8))
+            entry.append(falselen & 0xff)
+        else:
+            entry.append(falselen & 0x7f)
+
+        compressed.append(entry)
+
+    return compressed
+
+def print_singletons(uppers, lowers, uppersname, lowersname):
+    print("const {}: &'static [(u8, u8)] = &[".format(uppersname))
+    for u, c in uppers:
+        print("    ({:#04x}, {}),".format(u, c))
+    print("];")
+    print("const {}: &'static [u8] = &[".format(lowersname))
+    for i in range(0, len(lowers), 8):
+        print("    {}".format(" ".join("{:#04x},".format(l) for l in lowers[i:i+8])))
+    print("];")
+
+def print_normal(normal, normalname):
+    print("const {}: &'static [u8] = &[".format(normalname))
+    for v in normal:
+        print("    {}".format(" ".join("{:#04x},".format(i) for i in v)))
+    print("];")
+
 def main():
     file = get_file("http://www.unicode.org/Public/UNIDATA/UnicodeData.txt")
 
@@ -111,6 +171,11 @@ def main():
             else:
                 normal0.append((a, b - a))
 
+    singletons0u, singletons0l = compress_singletons(singletons0)
+    singletons1u, singletons1l = compress_singletons(singletons1)
+    normal0 = compress_normal(normal0)
+    normal1 = compress_normal(normal1)
+
     print("""\
 // Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
@@ -125,38 +190,49 @@ def main():
 // NOTE: The following code was generated by "src/etc/char_private.py",
 //       do not edit directly!
 
-use slice::SliceExt;
-
-fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool {
-    for &s in singletons {
-        if x == s {
-            return false;
-        } else if x < s {
+fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8],
+         normal: &[u8]) -> bool {
+    let xupper = (x >> 8) as u8;
+    let mut lowerstart = 0;
+    for &(upper, lowercount) in singletonuppers {
+        let lowerend = lowerstart + lowercount as usize;
+        if xupper == upper {
+            for &lower in &singletonlowers[lowerstart..lowerend] {
+                if lower == x as u8 {
+                    return false;
+                }
+            }
+        } else if xupper < upper {
             break;
         }
+        lowerstart = lowerend;
     }
-    for w in normal.chunks(2) {
-        let start = w[0];
-        let len = w[1];
-        let difference = (x as i32) - (start as i32);
-        if 0 <= difference {
-            if difference < len as i32 {
-                return false;
-            }
+
+    let mut x = x as i32;
+    let mut normal = normal.iter().cloned();
+    let mut current = true;
+    while let Some(v) = normal.next() {
+        let len = if v & 0x80 != 0 {
+            ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32
         } else {
+            v as i32
+        };
+        x -= len;
+        if x < 0 {
             break;
         }
+        current = !current;
     }
-    true
+    current
 }
 
 pub fn is_printable(x: char) -> bool {
     let x = x as u32;
     let lower = x as u16;
     if x < 0x10000 {
-        check(lower, SINGLETONS0, NORMAL0)
+        check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0)
     } else if x < 0x20000 {
-        check(lower, SINGLETONS1, NORMAL1)
+        check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1)
     } else {\
 """)
     for a, b in extra:
@@ -169,22 +245,10 @@ pub fn is_printable(x: char) -> bool {
 }\
 """)
     print()
-    print("const SINGLETONS0: &'static [u16] = &[")
-    for s in singletons0:
-        print("    0x{:x},".format(s))
-    print("];")
-    print("const SINGLETONS1: &'static [u16] = &[")
-    for s in singletons1:
-        print("    0x{:x},".format(s))
-    print("];")
-    print("const NORMAL0: &'static [u16] = &[")
-    for a, b in normal0:
-        print("    0x{:x}, 0x{:x},".format(a, b))
-    print("];")
-    print("const NORMAL1: &'static [u16] = &[")
-    for a, b in normal1:
-        print("    0x{:x}, 0x{:x},".format(a, b))
-    print("];")
+    print_singletons(singletons0u, singletons0l, 'SINGLETONS0U', 'SINGLETONS0L')
+    print_singletons(singletons1u, singletons1l, 'SINGLETONS1U', 'SINGLETONS1L')
+    print_normal(normal0, 'NORMAL0')
+    print_normal(normal1, 'NORMAL1')
 
 if __name__ == '__main__':
     main()
diff --git a/src/etc/make-win-dist.py b/src/etc/make-win-dist.py
index eda5f854085..394ff97d845 100644
--- a/src/etc/make-win-dist.py
+++ b/src/etc/make-win-dist.py
@@ -51,7 +51,7 @@ def make_win_dist(rust_root, plat_root, target_triple):
 
     target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe"]
 
-    rustc_dlls = ["libstdc++-6.dll"]
+    rustc_dlls = ["libstdc++-6.dll", "libwinpthread-1.dll"]
     if target_triple.startswith("i686-"):
         rustc_dlls.append("libgcc_s_dw2-1.dll")
     else:
@@ -67,6 +67,7 @@ def make_win_dist(rust_root, plat_root, target_triple):
                     "libstdc++.a",
                     "libiconv.a",
                     "libmoldname.a",
+                    "libpthread.a",
                     # Windows import libs
                     "libadvapi32.a",
                     "libbcrypt.a",
diff --git a/src/libcollections/Cargo.toml b/src/libcollections/Cargo.toml
index 02b2171a224..7e92404bc0d 100644
--- a/src/libcollections/Cargo.toml
+++ b/src/libcollections/Cargo.toml
@@ -13,8 +13,8 @@ core = { path = "../libcore" }
 std_unicode = { path = "../libstd_unicode" }
 
 [[test]]
-name = "collectionstest"
-path = "../libcollectionstest/lib.rs"
+name = "collectionstests"
+path = "../libcollections/tests/lib.rs"
 
 [[bench]]
 name = "collectionsbenches"
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index 00448b6abb2..248c15e96f8 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -52,6 +52,7 @@
 #![feature(shared)]
 #![feature(slice_get_slice)]
 #![feature(slice_patterns)]
+#![feature(slice_rsplit)]
 #![cfg_attr(not(test), feature(sort_unstable))]
 #![feature(specialization)]
 #![feature(staged_api)]
@@ -62,6 +63,7 @@
 #![feature(untagged_unions)]
 #![cfg_attr(not(test), feature(str_checked_slicing))]
 #![cfg_attr(test, feature(rand, test))]
+#![feature(offset_to)]
 
 #![no_std]
 
diff --git a/src/libcollections/linked_list.rs b/src/libcollections/linked_list.rs
index 8f0488f6936..1b3eeb837d9 100644
--- a/src/libcollections/linked_list.rs
+++ b/src/libcollections/linked_list.rs
@@ -697,8 +697,8 @@ impl<T> LinkedList<T> {
 
     /// Returns a place for insertion at the front of the list.
     ///
-    /// Using this method with placement syntax is equivalent to [`push_front`]
-    /// (#method.push_front), but may be more efficient.
+    /// Using this method with placement syntax is equivalent to
+    /// [`push_front`](#method.push_front), but may be more efficient.
     ///
     /// # Examples
     ///
diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs
index 6f8843c2374..6cff315a6cc 100644
--- a/src/libcollections/slice.rs
+++ b/src/libcollections/slice.rs
@@ -115,6 +115,8 @@ pub use core::slice::{Iter, IterMut};
 pub use core::slice::{SplitMut, ChunksMut, Split};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut};
+#[unstable(feature = "slice_rsplit", issue = "41020")]
+pub use core::slice::{RSplit, RSplitMut};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::slice::{from_raw_parts, from_raw_parts_mut};
 #[unstable(feature = "slice_get_slice", issue = "35729")]
@@ -780,6 +782,72 @@ impl<T> [T] {
     }
 
     /// Returns an iterator over subslices separated by elements that match
+    /// `pred`, starting at the end of the slice and working backwards.
+    /// The matched element is not contained in the subslices.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_rsplit)]
+    ///
+    /// let slice = [11, 22, 33, 0, 44, 55];
+    /// let mut iter = slice.rsplit(|num| *num == 0);
+    ///
+    /// assert_eq!(iter.next().unwrap(), &[44, 55]);
+    /// assert_eq!(iter.next().unwrap(), &[11, 22, 33]);
+    /// assert_eq!(iter.next(), None);
+    /// ```
+    ///
+    /// As with `split()`, if the first or last element is matched, an empty
+    /// slice will be the first (or last) item returned by the iterator.
+    ///
+    /// ```
+    /// #![feature(slice_rsplit)]
+    ///
+    /// let v = &[0, 1, 1, 2, 3, 5, 8];
+    /// let mut it = v.rsplit(|n| *n % 2 == 0);
+    /// assert_eq!(it.next().unwrap(), &[]);
+    /// assert_eq!(it.next().unwrap(), &[3, 5]);
+    /// assert_eq!(it.next().unwrap(), &[1, 1]);
+    /// assert_eq!(it.next().unwrap(), &[]);
+    /// assert_eq!(it.next(), None);
+    /// ```
+    #[unstable(feature = "slice_rsplit", issue = "41020")]
+    #[inline]
+    pub fn rsplit<F>(&self, pred: F) -> RSplit<T, F>
+        where F: FnMut(&T) -> bool
+    {
+        core_slice::SliceExt::rsplit(self, pred)
+    }
+
+    /// Returns an iterator over mutable subslices separated by elements that
+    /// match `pred`, starting at the end of the slice and working
+    /// backwards. The matched element is not contained in the subslices.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(slice_rsplit)]
+    ///
+    /// let mut v = [100, 400, 300, 200, 600, 500];
+    ///
+    /// let mut count = 0;
+    /// for group in v.rsplit_mut(|num| *num % 3 == 0) {
+    ///     count += 1;
+    ///     group[0] = count;
+    /// }
+    /// assert_eq!(v, [3, 400, 300, 2, 600, 1]);
+    /// ```
+    ///
+    #[unstable(feature = "slice_rsplit", issue = "41020")]
+    #[inline]
+    pub fn rsplit_mut<F>(&mut self, pred: F) -> RSplitMut<T, F>
+        where F: FnMut(&T) -> bool
+    {
+        core_slice::SliceExt::rsplit_mut(self, pred)
+    }
+
+    /// Returns an iterator over subslices separated by elements that match
     /// `pred`, limited to returning at most `n` items. The matched element is
     /// not contained in the subslices.
     ///
diff --git a/src/libcollectionstest/binary_heap.rs b/src/libcollections/tests/binary_heap.rs
index d284937a9e6..d284937a9e6 100644
--- a/src/libcollectionstest/binary_heap.rs
+++ b/src/libcollections/tests/binary_heap.rs
diff --git a/src/libcollectionstest/btree/map.rs b/src/libcollections/tests/btree/map.rs
index 2c899d96940..2c899d96940 100644
--- a/src/libcollectionstest/btree/map.rs
+++ b/src/libcollections/tests/btree/map.rs
diff --git a/src/libcollectionstest/btree/mod.rs b/src/libcollections/tests/btree/mod.rs
index ae8b18d0c9f..ae8b18d0c9f 100644
--- a/src/libcollectionstest/btree/mod.rs
+++ b/src/libcollections/tests/btree/mod.rs
diff --git a/src/libcollectionstest/btree/set.rs b/src/libcollections/tests/btree/set.rs
index 6171b8ba624..6171b8ba624 100644
--- a/src/libcollectionstest/btree/set.rs
+++ b/src/libcollections/tests/btree/set.rs
diff --git a/src/libcollectionstest/cow_str.rs b/src/libcollections/tests/cow_str.rs
index b29245121da..b29245121da 100644
--- a/src/libcollectionstest/cow_str.rs
+++ b/src/libcollections/tests/cow_str.rs
diff --git a/src/libcollectionstest/fmt.rs b/src/libcollections/tests/fmt.rs
index 70e21c65a18..70e21c65a18 100644
--- a/src/libcollectionstest/fmt.rs
+++ b/src/libcollections/tests/fmt.rs
diff --git a/src/libcollectionstest/lib.rs b/src/libcollections/tests/lib.rs
index 618eb386c0f..618eb386c0f 100644
--- a/src/libcollectionstest/lib.rs
+++ b/src/libcollections/tests/lib.rs
diff --git a/src/libcollectionstest/linked_list.rs b/src/libcollections/tests/linked_list.rs
index a59724a017b..a59724a017b 100644
--- a/src/libcollectionstest/linked_list.rs
+++ b/src/libcollections/tests/linked_list.rs
diff --git a/src/libcollectionstest/slice.rs b/src/libcollections/tests/slice.rs
index c3e5304fb2b..c3e5304fb2b 100644
--- a/src/libcollectionstest/slice.rs
+++ b/src/libcollections/tests/slice.rs
diff --git a/src/libcollectionstest/str.rs b/src/libcollections/tests/str.rs
index c9b7104fec4..c9b7104fec4 100644
--- a/src/libcollectionstest/str.rs
+++ b/src/libcollections/tests/str.rs
diff --git a/src/libcollectionstest/string.rs b/src/libcollections/tests/string.rs
index 2f021b9935d..2f021b9935d 100644
--- a/src/libcollectionstest/string.rs
+++ b/src/libcollections/tests/string.rs
diff --git a/src/libcollectionstest/vec.rs b/src/libcollections/tests/vec.rs
index 63df0eb7305..63df0eb7305 100644
--- a/src/libcollectionstest/vec.rs
+++ b/src/libcollections/tests/vec.rs
diff --git a/src/libcollectionstest/vec_deque.rs b/src/libcollections/tests/vec_deque.rs
index f2935c05d4f..f2935c05d4f 100644
--- a/src/libcollectionstest/vec_deque.rs
+++ b/src/libcollections/tests/vec_deque.rs
diff --git a/src/libcollections/vec.rs b/src/libcollections/vec.rs
index 56b60a3e003..35ecf411db4 100644
--- a/src/libcollections/vec.rs
+++ b/src/libcollections/vec.rs
@@ -678,8 +678,9 @@ impl<T> Vec<T> {
         self.len = len;
     }
 
-    /// Removes an element from anywhere in the vector and return it, replacing
-    /// it with the last element.
+    /// Removes an element from the vector and returns it.
+    ///
+    /// The removed element is replaced by the last element of the vector.
     ///
     /// This does not preserve ordering, but is O(1).
     ///
@@ -972,6 +973,29 @@ impl<T> Vec<T> {
         }
     }
 
+    /// Returns a place for insertion at the back of the `Vec`.
+    ///
+    /// Using this method with placement syntax is equivalent to [`push`](#method.push),
+    /// but may be more efficient.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(collection_placement)]
+    /// #![feature(placement_in_syntax)]
+    ///
+    /// let mut vec = vec![1, 2];
+    /// vec.place_back() <- 3;
+    /// vec.place_back() <- 4;
+    /// assert_eq!(&vec, &[1, 2, 3, 4]);
+    /// ```
+    #[unstable(feature = "collection_placement",
+               reason = "placement protocol is subject to change",
+               issue = "30172")]
+    pub fn place_back(&mut self) -> PlaceBack<T> {
+        PlaceBack { vec: self }
+    }
+
     /// Removes the last element from a vector and returns it, or [`None`] if it
     /// is empty.
     ///
@@ -1266,29 +1290,6 @@ impl<T: Clone> Vec<T> {
     pub fn extend_from_slice(&mut self, other: &[T]) {
         self.spec_extend(other.iter())
     }
-
-    /// Returns a place for insertion at the back of the `Vec`.
-    ///
-    /// Using this method with placement syntax is equivalent to [`push`](#method.push),
-    /// but may be more efficient.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(collection_placement)]
-    /// #![feature(placement_in_syntax)]
-    ///
-    /// let mut vec = vec![1, 2];
-    /// vec.place_back() <- 3;
-    /// vec.place_back() <- 4;
-    /// assert_eq!(&vec, &[1, 2, 3, 4]);
-    /// ```
-    #[unstable(feature = "collection_placement",
-               reason = "placement protocol is subject to change",
-               issue = "30172")]
-    pub fn place_back(&mut self) -> PlaceBack<T> {
-        PlaceBack { vec: self }
-    }
 }
 
 // Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
@@ -1345,7 +1346,7 @@ impl<T: PartialEq> Vec<T> {
     /// # Examples
     ///
     /// ```
-    ///# #![feature(vec_remove_item)]
+    /// # #![feature(vec_remove_item)]
     /// let mut vec = vec![1, 2, 3, 1];
     ///
     /// vec.remove_item(&1);
@@ -2073,14 +2074,10 @@ impl<T> Iterator for IntoIter<T> {
 
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
-        let diff = (self.end as usize) - (self.ptr as usize);
-        let size = mem::size_of::<T>();
-        let exact = diff /
-                    (if size == 0 {
-                         1
-                     } else {
-                         size
-                     });
+        let exact = match self.ptr.offset_to(self.end) {
+            Some(x) => x as usize,
+            None => (self.end as usize).wrapping_sub(self.ptr as usize),
+        };
         (exact, Some(exact))
     }
 
diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs
index cb92236ec73..22f2ff1a346 100644
--- a/src/libcollections/vec_deque.rs
+++ b/src/libcollections/vec_deque.rs
@@ -635,7 +635,7 @@ impl<T> VecDeque<T> {
         }
     }
 
-    /// Shortens a `VecDeque`, dropping excess elements from the back.
+    /// Shortens the `VecDeque`, dropping excess elements from the back.
     ///
     /// If `len` is greater than the `VecDeque`'s current length, this has no
     /// effect.
@@ -941,7 +941,7 @@ impl<T> VecDeque<T> {
         a.contains(x) || b.contains(x)
     }
 
-    /// Provides a reference to the front element, or `None` if the sequence is
+    /// Provides a reference to the front element, or `None` if the `VecDeque` is
     /// empty.
     ///
     /// # Examples
@@ -966,7 +966,7 @@ impl<T> VecDeque<T> {
     }
 
     /// Provides a mutable reference to the front element, or `None` if the
-    /// sequence is empty.
+    /// `VecDeque` is empty.
     ///
     /// # Examples
     ///
@@ -993,7 +993,7 @@ impl<T> VecDeque<T> {
         }
     }
 
-    /// Provides a reference to the back element, or `None` if the sequence is
+    /// Provides a reference to the back element, or `None` if the `VecDeque` is
     /// empty.
     ///
     /// # Examples
@@ -1018,7 +1018,7 @@ impl<T> VecDeque<T> {
     }
 
     /// Provides a mutable reference to the back element, or `None` if the
-    /// sequence is empty.
+    /// `VecDeque` is empty.
     ///
     /// # Examples
     ///
@@ -1046,7 +1046,7 @@ impl<T> VecDeque<T> {
         }
     }
 
-    /// Removes the first element and returns it, or `None` if the sequence is
+    /// Removes the first element and returns it, or `None` if the `VecDeque` is
     /// empty.
     ///
     /// # Examples
@@ -1073,7 +1073,7 @@ impl<T> VecDeque<T> {
         }
     }
 
-    /// Inserts an element first in the sequence.
+    /// Prepends an element to the `VecDeque`.
     ///
     /// # Examples
     ///
@@ -1096,7 +1096,7 @@ impl<T> VecDeque<T> {
         }
     }
 
-    /// Appends an element to the back of a buffer
+    /// Appends an element to the back of the `VecDeque`.
     ///
     /// # Examples
     ///
@@ -1117,7 +1117,7 @@ impl<T> VecDeque<T> {
         unsafe { self.buffer_write(head, value) }
     }
 
-    /// Removes the last element from a buffer and returns it, or `None` if
+    /// Removes the last element from the `VecDeque` and returns it, or `None` if
     /// it is empty.
     ///
     /// # Examples
diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml
index e847c7fa3a0..5af63aa970f 100644
--- a/src/libcore/Cargo.toml
+++ b/src/libcore/Cargo.toml
@@ -10,8 +10,8 @@ test = false
 bench = false
 
 [[test]]
-name = "coretest"
-path = "../libcoretest/lib.rs"
+name = "coretests"
+path = "../libcore/tests/lib.rs"
 
 [[bench]]
 name = "corebenches"
diff --git a/src/libcore/char_private.rs b/src/libcore/char_private.rs
index ddc473592a2..2c0f449b276 100644
--- a/src/libcore/char_private.rs
+++ b/src/libcore/char_private.rs
@@ -11,38 +11,49 @@
 // NOTE: The following code was generated by "src/etc/char_private.py",
 //       do not edit directly!
 
-use slice::SliceExt;
-
-fn check(x: u16, singletons: &[u16], normal: &[u16]) -> bool {
-    for &s in singletons {
-        if x == s {
-            return false;
-        } else if x < s {
+fn check(x: u16, singletonuppers: &[(u8, u8)], singletonlowers: &[u8],
+         normal: &[u8]) -> bool {
+    let xupper = (x >> 8) as u8;
+    let mut lowerstart = 0;
+    for &(upper, lowercount) in singletonuppers {
+        let lowerend = lowerstart + lowercount as usize;
+        if xupper == upper {
+            for &lower in &singletonlowers[lowerstart..lowerend] {
+                if lower == x as u8 {
+                    return false;
+                }
+            }
+        } else if xupper < upper {
             break;
         }
+        lowerstart = lowerend;
     }
-    for w in normal.chunks(2) {
-        let start = w[0];
-        let len = w[1];
-        let difference = (x as i32) - (start as i32);
-        if 0 <= difference {
-            if difference < len as i32 {
-                return false;
-            }
+
+    let mut x = x as i32;
+    let mut normal = normal.iter().cloned();
+    let mut current = true;
+    while let Some(v) = normal.next() {
+        let len = if v & 0x80 != 0 {
+            ((v & 0x7f) as i32) << 8 | normal.next().unwrap() as i32
         } else {
+            v as i32
+        };
+        x -= len;
+        if x < 0 {
             break;
         }
+        current = !current;
     }
-    true
+    current
 }
 
 pub fn is_printable(x: char) -> bool {
     let x = x as u32;
     let lower = x as u16;
     if x < 0x10000 {
-        check(lower, SINGLETONS0, NORMAL0)
+        check(lower, SINGLETONS0U, SINGLETONS0L, NORMAL0)
     } else if x < 0x20000 {
-        check(lower, SINGLETONS1, NORMAL1)
+        check(lower, SINGLETONS1U, SINGLETONS1L, NORMAL1)
     } else {
         if 0x2a6d7 <= x && x < 0x2a700 {
             return false;
@@ -66,761 +77,446 @@ pub fn is_printable(x: char) -> bool {
     }
 }
 
-const SINGLETONS0: &'static [u16] = &[
-    0xad,
-    0x378,
-    0x379,
-    0x38b,
-    0x38d,
-    0x3a2,
-    0x530,
-    0x557,
-    0x558,
-    0x560,
-    0x588,
-    0x58b,
-    0x58c,
-    0x590,
-    0x61c,
-    0x61d,
-    0x6dd,
-    0x70e,
-    0x70f,
-    0x74b,
-    0x74c,
-    0x82e,
-    0x82f,
-    0x83f,
-    0x85c,
-    0x85d,
-    0x8b5,
-    0x8e2,
-    0x984,
-    0x98d,
-    0x98e,
-    0x991,
-    0x992,
-    0x9a9,
-    0x9b1,
-    0x9ba,
-    0x9bb,
-    0x9c5,
-    0x9c6,
-    0x9c9,
-    0x9ca,
-    0x9de,
-    0x9e4,
-    0x9e5,
-    0xa04,
-    0xa11,
-    0xa12,
-    0xa29,
-    0xa31,
-    0xa34,
-    0xa37,
-    0xa3a,
-    0xa3b,
-    0xa3d,
-    0xa49,
-    0xa4a,
-    0xa5d,
-    0xa84,
-    0xa8e,
-    0xa92,
-    0xaa9,
-    0xab1,
-    0xab4,
-    0xaba,
-    0xabb,
-    0xac6,
-    0xaca,
-    0xace,
-    0xacf,
-    0xae4,
-    0xae5,
-    0xb04,
-    0xb0d,
-    0xb0e,
-    0xb11,
-    0xb12,
-    0xb29,
-    0xb31,
-    0xb34,
-    0xb3a,
-    0xb3b,
-    0xb45,
-    0xb46,
-    0xb49,
-    0xb4a,
-    0xb5e,
-    0xb64,
-    0xb65,
-    0xb84,
-    0xb91,
-    0xb9b,
-    0xb9d,
-    0xbc9,
-    0xbce,
-    0xbcf,
-    0xc04,
-    0xc0d,
-    0xc11,
-    0xc29,
-    0xc45,
-    0xc49,
-    0xc57,
-    0xc64,
-    0xc65,
-    0xc84,
-    0xc8d,
-    0xc91,
-    0xca9,
-    0xcb4,
-    0xcba,
-    0xcbb,
-    0xcc5,
-    0xcc9,
-    0xcdf,
-    0xce4,
-    0xce5,
-    0xcf0,
-    0xd04,
-    0xd0d,
-    0xd11,
-    0xd3b,
-    0xd3c,
-    0xd45,
-    0xd49,
-    0xd64,
-    0xd65,
-    0xd80,
-    0xd81,
-    0xd84,
-    0xdb2,
-    0xdbc,
-    0xdbe,
-    0xdbf,
-    0xdd5,
-    0xdd7,
-    0xdf0,
-    0xdf1,
-    0xe83,
-    0xe85,
-    0xe86,
-    0xe89,
-    0xe8b,
-    0xe8c,
-    0xe98,
-    0xea0,
-    0xea4,
-    0xea6,
-    0xea8,
-    0xea9,
-    0xeac,
-    0xeba,
-    0xebe,
-    0xebf,
-    0xec5,
-    0xec7,
-    0xece,
-    0xecf,
-    0xeda,
-    0xedb,
-    0xf48,
-    0xf98,
-    0xfbd,
-    0xfcd,
-    0x10c6,
-    0x10ce,
-    0x10cf,
-    0x1249,
-    0x124e,
-    0x124f,
-    0x1257,
-    0x1259,
-    0x125e,
-    0x125f,
-    0x1289,
-    0x128e,
-    0x128f,
-    0x12b1,
-    0x12b6,
-    0x12b7,
-    0x12bf,
-    0x12c1,
-    0x12c6,
-    0x12c7,
-    0x12d7,
-    0x1311,
-    0x1316,
-    0x1317,
-    0x135b,
-    0x135c,
-    0x13f6,
-    0x13f7,
-    0x13fe,
-    0x13ff,
-    0x1680,
-    0x170d,
-    0x176d,
-    0x1771,
-    0x17de,
-    0x17df,
-    0x180e,
-    0x180f,
-    0x191f,
-    0x196e,
-    0x196f,
-    0x1a1c,
-    0x1a1d,
-    0x1a5f,
-    0x1a7d,
-    0x1a7e,
-    0x1aae,
-    0x1aaf,
-    0x1cf7,
-    0x1f16,
-    0x1f17,
-    0x1f1e,
-    0x1f1f,
-    0x1f46,
-    0x1f47,
-    0x1f4e,
-    0x1f4f,
-    0x1f58,
-    0x1f5a,
-    0x1f5c,
-    0x1f5e,
-    0x1f7e,
-    0x1f7f,
-    0x1fb5,
-    0x1fc5,
-    0x1fd4,
-    0x1fd5,
-    0x1fdc,
-    0x1ff0,
-    0x1ff1,
-    0x1ff5,
-    0x2072,
-    0x2073,
-    0x208f,
-    0x23ff,
-    0x2b74,
-    0x2b75,
-    0x2b96,
-    0x2b97,
-    0x2bc9,
-    0x2c2f,
-    0x2c5f,
-    0x2d26,
-    0x2d2e,
-    0x2d2f,
-    0x2da7,
-    0x2daf,
-    0x2db7,
-    0x2dbf,
-    0x2dc7,
-    0x2dcf,
-    0x2dd7,
-    0x2ddf,
-    0x2e9a,
-    0x3040,
-    0x3097,
-    0x3098,
-    0x318f,
-    0x321f,
-    0x32ff,
-    0xa7af,
-    0xa8fe,
-    0xa8ff,
-    0xa9ce,
-    0xa9ff,
-    0xaa4e,
-    0xaa4f,
-    0xaa5a,
-    0xaa5b,
-    0xab07,
-    0xab08,
-    0xab0f,
-    0xab10,
-    0xab27,
-    0xab2f,
-    0xabee,
-    0xabef,
-    0xfa6e,
-    0xfa6f,
-    0xfb37,
-    0xfb3d,
-    0xfb3f,
-    0xfb42,
-    0xfb45,
-    0xfd90,
-    0xfd91,
-    0xfdfe,
-    0xfdff,
-    0xfe53,
-    0xfe67,
-    0xfe75,
-    0xffc8,
-    0xffc9,
-    0xffd0,
-    0xffd1,
-    0xffd8,
-    0xffd9,
-    0xffe7,
-    0xfffe,
-    0xffff,
+const SINGLETONS0U: &'static [(u8, u8)] = &[
+    (0x00, 1),
+    (0x03, 5),
+    (0x05, 8),
+    (0x06, 3),
+    (0x07, 4),
+    (0x08, 7),
+    (0x09, 16),
+    (0x0a, 27),
+    (0x0b, 24),
+    (0x0c, 22),
+    (0x0d, 20),
+    (0x0e, 22),
+    (0x0f, 4),
+    (0x10, 3),
+    (0x12, 18),
+    (0x13, 9),
+    (0x16, 1),
+    (0x17, 5),
+    (0x18, 2),
+    (0x19, 3),
+    (0x1a, 7),
+    (0x1c, 1),
+    (0x1f, 22),
+    (0x20, 3),
+    (0x23, 1),
+    (0x2b, 5),
+    (0x2c, 2),
+    (0x2d, 11),
+    (0x2e, 1),
+    (0x30, 3),
+    (0x31, 1),
+    (0x32, 2),
+    (0xa7, 1),
+    (0xa8, 2),
+    (0xa9, 2),
+    (0xaa, 4),
+    (0xab, 8),
+    (0xfa, 2),
+    (0xfb, 5),
+    (0xfd, 4),
+    (0xfe, 3),
+    (0xff, 9),
 ];
-const SINGLETONS1: &'static [u16] = &[
-    0xc,
-    0x27,
-    0x3b,
-    0x3e,
-    0x4e,
-    0x4f,
-    0x18f,
-    0x39e,
-    0x49e,
-    0x49f,
-    0x806,
-    0x807,
-    0x809,
-    0x836,
-    0x83d,
-    0x83e,
-    0x856,
-    0x8f3,
-    0x9d0,
-    0x9d1,
-    0xa04,
-    0xa14,
-    0xa18,
-    0xb56,
-    0xb57,
-    0x10bd,
-    0x1135,
-    0x11ce,
-    0x11cf,
-    0x11e0,
-    0x1212,
-    0x1287,
-    0x1289,
-    0x128e,
-    0x129e,
-    0x1304,
-    0x130d,
-    0x130e,
-    0x1311,
-    0x1312,
-    0x1329,
-    0x1331,
-    0x1334,
-    0x133a,
-    0x133b,
-    0x1345,
-    0x1346,
-    0x1349,
-    0x134a,
-    0x134e,
-    0x134f,
-    0x1364,
-    0x1365,
-    0x145a,
-    0x145c,
-    0x15b6,
-    0x15b7,
-    0x1c09,
-    0x1c37,
-    0x1c90,
-    0x1c91,
-    0x1ca8,
-    0x246f,
-    0x6a5f,
-    0x6aee,
-    0x6aef,
-    0x6b5a,
-    0x6b62,
-    0xbc9a,
-    0xbc9b,
-    0xd127,
-    0xd128,
-    0xd455,
-    0xd49d,
-    0xd4a0,
-    0xd4a1,
-    0xd4a3,
-    0xd4a4,
-    0xd4a7,
-    0xd4a8,
-    0xd4ad,
-    0xd4ba,
-    0xd4bc,
-    0xd4c4,
-    0xd506,
-    0xd50b,
-    0xd50c,
-    0xd515,
-    0xd51d,
-    0xd53a,
-    0xd53f,
-    0xd545,
-    0xd551,
-    0xd6a6,
-    0xd6a7,
-    0xd7cc,
-    0xd7cd,
-    0xdaa0,
-    0xe007,
-    0xe019,
-    0xe01a,
-    0xe022,
-    0xe025,
-    0xe8c5,
-    0xe8c6,
-    0xee04,
-    0xee20,
-    0xee23,
-    0xee25,
-    0xee26,
-    0xee28,
-    0xee33,
-    0xee38,
-    0xee3a,
-    0xee48,
-    0xee4a,
-    0xee4c,
-    0xee50,
-    0xee53,
-    0xee55,
-    0xee56,
-    0xee58,
-    0xee5a,
-    0xee5c,
-    0xee5e,
-    0xee60,
-    0xee63,
-    0xee65,
-    0xee66,
-    0xee6b,
-    0xee73,
-    0xee78,
-    0xee7d,
-    0xee7f,
-    0xee8a,
-    0xeea4,
-    0xeeaa,
-    0xf0af,
-    0xf0b0,
-    0xf0c0,
-    0xf0d0,
-    0xf12f,
-    0xf91f,
-    0xf931,
-    0xf932,
-    0xf93f,
+const SINGLETONS0L: &'static [u8] = &[
+    0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57,
+    0x58, 0x60, 0x88, 0x8b, 0x8c, 0x90, 0x1c, 0x1d,
+    0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0x2e, 0x2f, 0x3f,
+    0x5c, 0x5d, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91,
+    0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, 0xc9,
+    0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, 0x29,
+    0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a,
+    0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba,
+    0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, 0x04,
+    0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a,
+    0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65,
+    0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, 0xcf, 0x04,
+    0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65,
+    0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5,
+    0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, 0x0d, 0x11,
+    0x3b, 0x3c, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81,
+    0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0,
+    0xf1, 0x83, 0x85, 0x86, 0x89, 0x8b, 0x8c, 0x98,
+    0xa0, 0xa4, 0xa6, 0xa8, 0xa9, 0xac, 0xba, 0xbe,
+    0xbf, 0xc5, 0xc7, 0xce, 0xcf, 0xda, 0xdb, 0x48,
+    0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, 0x4e,
+    0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f,
+    0xb1, 0xb6, 0xb7, 0xbf, 0xc1, 0xc6, 0xc7, 0xd7,
+    0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe,
+    0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e,
+    0x0f, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d,
+    0x7e, 0xae, 0xaf, 0xf7, 0x16, 0x17, 0x1e, 0x1f,
+    0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e,
+    0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0,
+    0xf1, 0xf5, 0x72, 0x73, 0x8f, 0xff, 0x74, 0x75,
+    0x96, 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f,
+    0xa7, 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf,
+    0x9a, 0x40, 0x97, 0x98, 0x8f, 0x1f, 0xff, 0xaf,
+    0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b,
+    0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, 0xef,
+    0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90,
+    0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9,
+    0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff,
 ];
-const NORMAL0: &'static [u16] = &[
-    0x0, 0x20,
-    0x7f, 0x22,
-    0x380, 0x4,
-    0x5c8, 0x8,
-    0x5eb, 0x5,
-    0x5f5, 0x11,
-    0x7b2, 0xe,
-    0x7fb, 0x5,
-    0x85f, 0x41,
-    0x8be, 0x16,
-    0x9b3, 0x3,
-    0x9cf, 0x8,
-    0x9d8, 0x4,
-    0x9fc, 0x5,
-    0xa0b, 0x4,
-    0xa43, 0x4,
-    0xa4e, 0x3,
-    0xa52, 0x7,
-    0xa5f, 0x7,
-    0xa76, 0xb,
-    0xad1, 0xf,
-    0xaf2, 0x7,
-    0xafa, 0x7,
-    0xb4e, 0x8,
-    0xb58, 0x4,
-    0xb78, 0xa,
-    0xb8b, 0x3,
-    0xb96, 0x3,
-    0xba0, 0x3,
-    0xba5, 0x3,
-    0xbab, 0x3,
-    0xbba, 0x4,
-    0xbc3, 0x3,
-    0xbd1, 0x6,
-    0xbd8, 0xe,
-    0xbfb, 0x5,
-    0xc3a, 0x3,
-    0xc4e, 0x7,
-    0xc5b, 0x5,
-    0xc70, 0x8,
-    0xcce, 0x7,
-    0xcd7, 0x7,
-    0xcf3, 0xe,
-    0xd50, 0x4,
-    0xd97, 0x3,
-    0xdc7, 0x3,
-    0xdcb, 0x4,
-    0xde0, 0x6,
-    0xdf5, 0xc,
-    0xe3b, 0x4,
-    0xe5c, 0x25,
-    0xe8e, 0x6,
-    0xee0, 0x20,
-    0xf6d, 0x4,
-    0xfdb, 0x25,
-    0x10c8, 0x5,
-    0x137d, 0x3,
-    0x139a, 0x6,
-    0x169d, 0x3,
-    0x16f9, 0x7,
-    0x1715, 0xb,
-    0x1737, 0x9,
-    0x1754, 0xc,
-    0x1774, 0xc,
-    0x17ea, 0x6,
-    0x17fa, 0x6,
-    0x181a, 0x6,
-    0x1878, 0x8,
-    0x18ab, 0x5,
-    0x18f6, 0xa,
-    0x192c, 0x4,
-    0x193c, 0x4,
-    0x1941, 0x3,
-    0x1975, 0xb,
-    0x19ac, 0x4,
-    0x19ca, 0x6,
-    0x19db, 0x3,
-    0x1a8a, 0x6,
-    0x1a9a, 0x6,
-    0x1abf, 0x41,
-    0x1b4c, 0x4,
-    0x1b7d, 0x3,
-    0x1bf4, 0x8,
-    0x1c38, 0x3,
-    0x1c4a, 0x3,
-    0x1c89, 0x37,
-    0x1cc8, 0x8,
-    0x1cfa, 0x6,
-    0x1df6, 0x5,
-    0x1fff, 0x11,
-    0x2028, 0x8,
-    0x205f, 0x11,
-    0x209d, 0x3,
-    0x20bf, 0x11,
-    0x20f1, 0xf,
-    0x218c, 0x4,
-    0x2427, 0x19,
-    0x244b, 0x15,
-    0x2bba, 0x3,
-    0x2bd2, 0x1a,
-    0x2bf0, 0x10,
-    0x2cf4, 0x5,
-    0x2d28, 0x5,
-    0x2d68, 0x7,
-    0x2d71, 0xe,
-    0x2d97, 0x9,
-    0x2e45, 0x3b,
-    0x2ef4, 0xc,
-    0x2fd6, 0x1a,
-    0x2ffc, 0x5,
-    0x3100, 0x5,
-    0x312e, 0x3,
-    0x31bb, 0x5,
-    0x31e4, 0xc,
-    0x4db6, 0xa,
-    0x9fd6, 0x2a,
-    0xa48d, 0x3,
-    0xa4c7, 0x9,
-    0xa62c, 0x14,
-    0xa6f8, 0x8,
-    0xa7b8, 0x3f,
-    0xa82c, 0x4,
-    0xa83a, 0x6,
-    0xa878, 0x8,
-    0xa8c6, 0x8,
-    0xa8da, 0x6,
-    0xa954, 0xb,
-    0xa97d, 0x3,
-    0xa9da, 0x4,
-    0xaa37, 0x9,
-    0xaac3, 0x18,
-    0xaaf7, 0xa,
-    0xab17, 0x9,
-    0xab66, 0xa,
-    0xabfa, 0x6,
-    0xd7a4, 0xc,
-    0xd7c7, 0x4,
-    0xd7fc, 0x2104,
-    0xfada, 0x26,
-    0xfb07, 0xc,
-    0xfb18, 0x5,
-    0xfbc2, 0x11,
-    0xfd40, 0x10,
-    0xfdc8, 0x28,
-    0xfe1a, 0x6,
-    0xfe6c, 0x4,
-    0xfefd, 0x4,
-    0xffbf, 0x3,
-    0xffdd, 0x3,
-    0xffef, 0xd,
+const SINGLETONS1U: &'static [(u8, u8)] = &[
+    (0x00, 6),
+    (0x01, 1),
+    (0x03, 1),
+    (0x04, 2),
+    (0x08, 8),
+    (0x09, 2),
+    (0x0a, 3),
+    (0x0b, 2),
+    (0x10, 1),
+    (0x11, 4),
+    (0x12, 5),
+    (0x13, 18),
+    (0x14, 2),
+    (0x15, 2),
+    (0x1c, 5),
+    (0x24, 1),
+    (0x6a, 3),
+    (0x6b, 2),
+    (0xbc, 2),
+    (0xd1, 2),
+    (0xd4, 12),
+    (0xd5, 9),
+    (0xd6, 2),
+    (0xd7, 2),
+    (0xda, 1),
+    (0xe0, 5),
+    (0xe8, 2),
+    (0xee, 32),
+    (0xf0, 4),
+    (0xf1, 1),
+    (0xf9, 4),
 ];
-const NORMAL1: &'static [u16] = &[
+const SINGLETONS1L: &'static [u8] = &[
+    0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e,
+    0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e,
+    0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x56,
+    0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, 0x12, 0x87,
+    0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12,
+    0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49,
+    0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, 0xb6,
+    0xb7, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x6f, 0x5f,
+    0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28,
+    0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8,
+    0xad, 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15,
+    0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc,
+    0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5,
+    0xc6, 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33,
+    0x38, 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55,
+    0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65,
+    0x66, 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4,
+    0xaa, 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x1f, 0x31,
+    0x32, 0x3f,
+];
+const NORMAL0: &'static [u8] = &[
+    0x00, 0x20,
+    0x5f, 0x22,
+    0x82, 0xdf, 0x04,
+    0x82, 0x44, 0x08,
+    0x1b, 0x05,
+    0x05, 0x11,
+    0x81, 0xac, 0x0e,
+    0x3b, 0x05,
+    0x5f, 0x41,
+    0x1e, 0x16,
+    0x80, 0xdf, 0x03,
+    0x19, 0x08,
+    0x01, 0x04,
+    0x20, 0x05,
+    0x0a, 0x04,
+    0x34, 0x04,
+    0x07, 0x03,
+    0x01, 0x07,
+    0x06, 0x07,
+    0x10, 0x0b,
+    0x50, 0x0f,
+    0x12, 0x07,
+    0x01, 0x07,
+    0x4d, 0x08,
+    0x02, 0x04,
+    0x1c, 0x0a,
+    0x09, 0x03,
+    0x08, 0x03,
+    0x07, 0x03,
+    0x02, 0x03,
+    0x03, 0x03,
+    0x0c, 0x04,
+    0x05, 0x03,
+    0x0b, 0x06,
+    0x01, 0x0e,
+    0x15, 0x05,
+    0x3a, 0x03,
+    0x11, 0x07,
+    0x06, 0x05,
+    0x10, 0x08,
+    0x56, 0x07,
+    0x02, 0x07,
+    0x15, 0x0e,
+    0x4f, 0x04,
+    0x43, 0x03,
+    0x2d, 0x03,
+    0x01, 0x04,
+    0x11, 0x06,
+    0x0f, 0x0c,
+    0x3a, 0x04,
+    0x1d, 0x25,
+    0x0d, 0x06,
+    0x4c, 0x20,
+    0x6d, 0x04,
+    0x6a, 0x25,
+    0x80, 0xc8, 0x05,
+    0x82, 0xb0, 0x03,
+    0x1a, 0x06,
+    0x82, 0xfd, 0x03,
+    0x59, 0x07,
+    0x15, 0x0b,
+    0x17, 0x09,
+    0x14, 0x0c,
+    0x14, 0x0c,
+    0x6a, 0x06,
+    0x0a, 0x06,
+    0x1a, 0x06,
+    0x58, 0x08,
+    0x2b, 0x05,
+    0x46, 0x0a,
+    0x2c, 0x04,
+    0x0c, 0x04,
+    0x01, 0x03,
+    0x31, 0x0b,
+    0x2c, 0x04,
+    0x1a, 0x06,
+    0x0b, 0x03,
+    0x80, 0xac, 0x06,
+    0x0a, 0x06,
+    0x1f, 0x41,
+    0x4c, 0x04,
+    0x2d, 0x03,
+    0x74, 0x08,
+    0x3c, 0x03,
+    0x0f, 0x03,
+    0x3c, 0x37,
+    0x08, 0x08,
+    0x2a, 0x06,
+    0x80, 0xf6, 0x05,
+    0x82, 0x04, 0x11,
+    0x18, 0x08,
+    0x2f, 0x11,
+    0x2d, 0x03,
+    0x1f, 0x11,
+    0x21, 0x0f,
+    0x80, 0x8c, 0x04,
+    0x82, 0x97, 0x19,
+    0x0b, 0x15,
+    0x87, 0x5a, 0x03,
+    0x15, 0x1a,
+    0x04, 0x10,
+    0x80, 0xf4, 0x05,
+    0x2f, 0x05,
+    0x3b, 0x07,
+    0x02, 0x0e,
+    0x18, 0x09,
+    0x80, 0xa5, 0x3b,
+    0x74, 0x0c,
+    0x80, 0xd6, 0x1a,
+    0x0c, 0x05,
+    0x80, 0xff, 0x05,
+    0x29, 0x03,
+    0x80, 0x8a, 0x05,
+    0x24, 0x0c,
+    0x9b, 0xc6, 0x0a,
+    0xd2, 0x16, 0x2a,
+    0x84, 0x8d, 0x03,
+    0x37, 0x09,
+    0x81, 0x5c, 0x14,
+    0x80, 0xb8, 0x08,
+    0x80, 0xb8, 0x3f,
+    0x35, 0x04,
+    0x0a, 0x06,
+    0x38, 0x08,
+    0x46, 0x08,
+    0x0c, 0x06,
+    0x74, 0x0b,
+    0x1e, 0x03,
+    0x5a, 0x04,
+    0x59, 0x09,
+    0x80, 0x83, 0x18,
+    0x1c, 0x0a,
+    0x16, 0x09,
+    0x46, 0x0a,
+    0x80, 0x8a, 0x06,
+    0xab, 0xa4, 0x0c,
+    0x17, 0x04,
+    0x31, 0xa1, 0x04,
+    0x81, 0xda, 0x26,
+    0x07, 0x0c,
+    0x05, 0x05,
+    0x80, 0xa5, 0x11,
+    0x81, 0x6d, 0x10,
+    0x78, 0x28,
+    0x2a, 0x06,
+    0x4c, 0x04,
+    0x80, 0x8d, 0x04,
+    0x80, 0xbe, 0x03,
+    0x1b, 0x03,
+    0x0f, 0x0d,
+];
+const NORMAL1: &'static [u8] = &[
+    0x5e, 0x22,
+    0x7b, 0x05,
+    0x03, 0x04,
+    0x2d, 0x03,
+    0x65, 0x04,
+    0x01, 0x2f,
+    0x2e, 0x80, 0x82,
+    0x1d, 0x03,
+    0x31, 0x0f,
+    0x1c, 0x04,
+    0x24, 0x0c,
+    0x1b, 0x05,
+    0x2b, 0x05,
+    0x44, 0x04,
+    0x0e, 0x2a,
+    0x80, 0xaa, 0x06,
+    0x24, 0x04,
+    0x24, 0x04,
+    0x28, 0x08,
+    0x34, 0x0b,
+    0x01, 0x80, 0x90,
+    0x81, 0x37, 0x09,
+    0x16, 0x0a,
+    0x08, 0x80, 0x98,
+    0x39, 0x03,
+    0x63, 0x08,
+    0x09, 0x30,
+    0x16, 0x05,
+    0x21, 0x03,
+    0x1b, 0x05,
+    0x01, 0x40,
+    0x38, 0x04,
+    0x4b, 0x05,
+    0x28, 0x04,
+    0x03, 0x04,
+    0x09, 0x08,
+    0x09, 0x07,
+    0x40, 0x20,
+    0x27, 0x04,
+    0x0c, 0x09,
+    0x36, 0x03,
+    0x3a, 0x05,
+    0x1a, 0x07,
+    0x04, 0x0c,
+    0x07, 0x50,
+    0x49, 0x37,
+    0x33, 0x0d,
+    0x33, 0x07,
+    0x06, 0x81, 0x60,
+    0x1f, 0x81, 0x81,
+    0x4e, 0x04,
+    0x1e, 0x0f,
+    0x43, 0x0e,
+    0x19, 0x07,
+    0x0a, 0x06,
+    0x44, 0x0c,
+    0x27, 0x09,
+    0x75, 0x0b,
+    0x3f, 0x41,
+    0x2a, 0x06,
+    0x3b, 0x05,
+    0x0a, 0x06,
+    0x51, 0x06,
+    0x01, 0x05,
+    0x10, 0x03,
+    0x05, 0x80, 0x8b,
+    0x5e, 0x22,
+    0x48, 0x08,
+    0x0a, 0x80, 0xa6,
     0x5e, 0x22,
-    0xfb, 0x5,
-    0x103, 0x4,
-    0x134, 0x3,
-    0x19c, 0x4,
-    0x1a1, 0x2f,
-    0x1fe, 0x82,
-    0x29d, 0x3,
-    0x2d1, 0xf,
-    0x2fc, 0x4,
-    0x324, 0xc,
-    0x34b, 0x5,
-    0x37b, 0x5,
-    0x3c4, 0x4,
-    0x3d6, 0x2a,
-    0x4aa, 0x6,
-    0x4d4, 0x4,
-    0x4fc, 0x4,
-    0x528, 0x8,
-    0x564, 0xb,
-    0x570, 0x90,
-    0x737, 0x9,
-    0x756, 0xa,
-    0x768, 0x98,
-    0x839, 0x3,
-    0x89f, 0x8,
-    0x8b0, 0x30,
-    0x8f6, 0x5,
-    0x91c, 0x3,
-    0x93a, 0x5,
-    0x940, 0x40,
-    0x9b8, 0x4,
-    0xa07, 0x5,
-    0xa34, 0x4,
-    0xa3b, 0x4,
-    0xa48, 0x8,
-    0xa59, 0x7,
-    0xaa0, 0x20,
-    0xae7, 0x4,
-    0xaf7, 0x9,
-    0xb36, 0x3,
-    0xb73, 0x5,
-    0xb92, 0x7,
-    0xb9d, 0xc,
-    0xbb0, 0x50,
-    0xc49, 0x37,
-    0xcb3, 0xd,
-    0xcf3, 0x7,
-    0xd00, 0x160,
-    0xe7f, 0x181,
-    0x104e, 0x4,
-    0x1070, 0xf,
-    0x10c2, 0xe,
-    0x10e9, 0x7,
-    0x10fa, 0x6,
-    0x1144, 0xc,
-    0x1177, 0x9,
-    0x11f5, 0xb,
-    0x123f, 0x41,
-    0x12aa, 0x6,
-    0x12eb, 0x5,
-    0x12fa, 0x6,
-    0x1351, 0x6,
-    0x1358, 0x5,
-    0x136d, 0x3,
-    0x1375, 0x8b,
-    0x145e, 0x22,
-    0x14c8, 0x8,
-    0x14da, 0xa6,
-    0x15de, 0x22,
-    0x1645, 0xb,
-    0x165a, 0x6,
-    0x166d, 0x13,
-    0x16b8, 0x8,
-    0x16ca, 0x36,
-    0x171a, 0x3,
-    0x172c, 0x4,
-    0x1740, 0x160,
-    0x18f3, 0xc,
-    0x1900, 0x1c0,
-    0x1af9, 0x107,
-    0x1c46, 0xa,
-    0x1c6d, 0x3,
-    0x1cb7, 0x349,
-    0x239a, 0x66,
-    0x2475, 0xb,
-    0x2544, 0xabc,
-    0x342f, 0xfd1,
-    0x4647, 0x21b9,
-    0x6a39, 0x7,
-    0x6a6a, 0x4,
-    0x6a70, 0x60,
-    0x6af6, 0xa,
-    0x6b46, 0xa,
-    0x6b78, 0x5,
-    0x6b90, 0x370,
-    0x6f45, 0xb,
-    0x6f7f, 0x10,
-    0x6fa0, 0x40,
-    0x6fe1, 0x1f,
-    0x87ed, 0x13,
-    0x8af3, 0x250d,
-    0xb002, 0xbfe,
-    0xbc6b, 0x5,
-    0xbc7d, 0x3,
-    0xbc89, 0x7,
-    0xbca0, 0x1360,
-    0xd0f6, 0xa,
-    0xd173, 0x8,
-    0xd1e9, 0x17,
-    0xd246, 0xba,
-    0xd357, 0x9,
-    0xd372, 0x8e,
-    0xd547, 0x3,
-    0xda8c, 0xf,
-    0xdab0, 0x550,
-    0xe02b, 0x7d5,
-    0xe8d7, 0x29,
-    0xe94b, 0x5,
-    0xe95a, 0x4,
-    0xe960, 0x4a0,
-    0xee3c, 0x6,
-    0xee43, 0x4,
-    0xee9c, 0x5,
-    0xeebc, 0x34,
-    0xeef2, 0x10e,
-    0xf02c, 0x4,
-    0xf094, 0xc,
-    0xf0f6, 0xa,
-    0xf10d, 0x3,
-    0xf16c, 0x4,
-    0xf1ad, 0x39,
-    0xf203, 0xd,
-    0xf23c, 0x4,
-    0xf249, 0x7,
-    0xf252, 0xae,
-    0xf6d3, 0xd,
-    0xf6ed, 0x3,
-    0xf6f7, 0x9,
-    0xf774, 0xc,
-    0xf7d5, 0x2b,
-    0xf80c, 0x4,
-    0xf848, 0x8,
-    0xf85a, 0x6,
-    0xf888, 0x8,
-    0xf8ae, 0x62,
-    0xf928, 0x8,
-    0xf94c, 0x4,
-    0xf95f, 0x21,
-    0xf992, 0x2e,
-    0xf9c1, 0x63f,
+    0x45, 0x0b,
+    0x0a, 0x06,
+    0x0d, 0x13,
+    0x38, 0x08,
+    0x0a, 0x36,
+    0x1a, 0x03,
+    0x0f, 0x04,
+    0x10, 0x81, 0x60,
+    0x53, 0x0c,
+    0x01, 0x81, 0xc0,
+    0x39, 0x81, 0x07,
+    0x46, 0x0a,
+    0x1d, 0x03,
+    0x47, 0x83, 0x49,
+    0x83, 0x9a, 0x66,
+    0x75, 0x0b,
+    0x80, 0xc4, 0x8a, 0xbc,
+    0x84, 0x2f, 0x8f, 0xd1,
+    0x82, 0x47, 0xa1, 0xb9,
+    0x82, 0x39, 0x07,
+    0x2a, 0x04,
+    0x02, 0x60,
+    0x26, 0x0a,
+    0x46, 0x0a,
+    0x28, 0x05,
+    0x13, 0x83, 0x70,
+    0x45, 0x0b,
+    0x2f, 0x10,
+    0x11, 0x40,
+    0x01, 0x1f,
+    0x97, 0xed, 0x13,
+    0x82, 0xf3, 0xa5, 0x0d,
+    0x02, 0x8b, 0xfe,
+    0x6b, 0x05,
+    0x0d, 0x03,
+    0x09, 0x07,
+    0x10, 0x93, 0x60,
+    0x80, 0xf6, 0x0a,
+    0x73, 0x08,
+    0x6e, 0x17,
+    0x46, 0x80, 0xba,
+    0x57, 0x09,
+    0x12, 0x80, 0x8e,
+    0x81, 0x47, 0x03,
+    0x85, 0x42, 0x0f,
+    0x15, 0x85, 0x50,
+    0x2b, 0x87, 0xd5,
+    0x80, 0xd7, 0x29,
+    0x4b, 0x05,
+    0x0a, 0x04,
+    0x02, 0x84, 0xa0,
+    0x3c, 0x06,
+    0x01, 0x04,
+    0x55, 0x05,
+    0x1b, 0x34,
+    0x02, 0x81, 0x0e,
+    0x2c, 0x04,
+    0x64, 0x0c,
+    0x56, 0x0a,
+    0x0d, 0x03,
+    0x5c, 0x04,
+    0x3d, 0x39,
+    0x1d, 0x0d,
+    0x2c, 0x04,
+    0x09, 0x07,
+    0x02, 0x80, 0xae,
+    0x83, 0xd3, 0x0d,
+    0x0d, 0x03,
+    0x07, 0x09,
+    0x74, 0x0c,
+    0x55, 0x2b,
+    0x0c, 0x04,
+    0x38, 0x08,
+    0x0a, 0x06,
+    0x28, 0x08,
+    0x1e, 0x62,
+    0x18, 0x08,
+    0x1c, 0x04,
+    0x0f, 0x21,
+    0x12, 0x2e,
+    0x01, 0x86, 0x3f,
 ];
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 1ae8b6bb451..e0a4707ff66 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -61,16 +61,18 @@ extern "rust-intrinsic" {
     /// `std::sync::atomic` types via the `compare_exchange` method by passing
     /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html)
     /// as both the `success` and `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange).
+    /// [`AtomicBool::compare_exchange`][compare_exchange].
+    ///
+    /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange
     pub fn atomic_cxchg<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
     /// `std::sync::atomic` types via the `compare_exchange` method by passing
     /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html)
     /// as both the `success` and `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange).
+    /// [`AtomicBool::compare_exchange`][compare_exchange].
+    ///
+    /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange
     pub fn atomic_cxchg_acq<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
@@ -79,8 +81,9 @@ extern "rust-intrinsic" {
     /// as the `success` and
     /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html)
     /// as the `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange).
+    /// [`AtomicBool::compare_exchange`][compare_exchange].
+    ///
+    /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange
     pub fn atomic_cxchg_rel<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
@@ -89,16 +92,18 @@ extern "rust-intrinsic" {
     /// as the `success` and
     /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html)
     /// as the `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange).
+    /// [`AtomicBool::compare_exchange`][compare_exchange].
+    ///
+    /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange
     pub fn atomic_cxchg_acqrel<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
     /// `std::sync::atomic` types via the `compare_exchange` method by passing
     /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html)
     /// as both the `success` and `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange).
+    /// [`AtomicBool::compare_exchange`][compare_exchange].
+    ///
+    /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange
     pub fn atomic_cxchg_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
@@ -107,8 +112,9 @@ extern "rust-intrinsic" {
     /// as the `success` and
     /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html)
     /// as the `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange).
+    /// [`AtomicBool::compare_exchange`][compare_exchange].
+    ///
+    /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange
     pub fn atomic_cxchg_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
@@ -117,8 +123,9 @@ extern "rust-intrinsic" {
     /// as the `success` and
     /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html)
     /// as the `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange).
+    /// [`AtomicBool::compare_exchange`][compare_exchange].
+    ///
+    /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange
     pub fn atomic_cxchg_failacq<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
@@ -127,8 +134,9 @@ extern "rust-intrinsic" {
     /// as the `success` and
     /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html)
     /// as the `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange).
+    /// [`AtomicBool::compare_exchange`][compare_exchange].
+    ///
+    /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange
     pub fn atomic_cxchg_acq_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
@@ -137,8 +145,9 @@ extern "rust-intrinsic" {
     /// as the `success` and
     /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html)
     /// as the `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange).
+    /// [`AtomicBool::compare_exchange`][compare_exchange].
+    ///
+    /// [compare_exchange]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange
     pub fn atomic_cxchg_acqrel_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
 
     /// Stores a value if the current value is the same as the `old` value.
@@ -146,16 +155,18 @@ extern "rust-intrinsic" {
     /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing
     /// [`Ordering::SeqCst`](../../std/sync/atomic/enum.Ordering.html)
     /// as both the `success` and `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange_weak`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak).
+    /// [`AtomicBool::compare_exchange_weak`][cew].
+    ///
+    /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak
     pub fn atomic_cxchgweak<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
     /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing
     /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html)
     /// as both the `success` and `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange_weak`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak).
+    /// [`AtomicBool::compare_exchange_weak`][cew].
+    ///
+    /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak
     pub fn atomic_cxchgweak_acq<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
@@ -164,8 +175,9 @@ extern "rust-intrinsic" {
     /// as the `success` and
     /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html)
     /// as the `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange_weak`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak).
+    /// [`AtomicBool::compare_exchange_weak`][cew].
+    ///
+    /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak
     pub fn atomic_cxchgweak_rel<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
@@ -174,16 +186,18 @@ extern "rust-intrinsic" {
     /// as the `success` and
     /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html)
     /// as the `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange_weak`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak).
+    /// [`AtomicBool::compare_exchange_weak`][cew].
+    ///
+    /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak
     pub fn atomic_cxchgweak_acqrel<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
     /// `std::sync::atomic` types via the `compare_exchange_weak` method by passing
     /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html)
     /// as both the `success` and `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange_weak`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak).
+    /// [`AtomicBool::compare_exchange_weak`][cew].
+    ///
+    /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak
     pub fn atomic_cxchgweak_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
@@ -192,8 +206,9 @@ extern "rust-intrinsic" {
     /// as the `success` and
     /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html)
     /// as the `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange_weak`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak).
+    /// [`AtomicBool::compare_exchange_weak`][cew].
+    ///
+    /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak
     pub fn atomic_cxchgweak_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
@@ -202,8 +217,9 @@ extern "rust-intrinsic" {
     /// as the `success` and
     /// [`Ordering::Acquire`](../../std/sync/atomic/enum.Ordering.html)
     /// as the `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange_weak`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak).
+    /// [`AtomicBool::compare_exchange_weak`][cew].
+    ///
+    /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak
     pub fn atomic_cxchgweak_failacq<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
@@ -212,8 +228,9 @@ extern "rust-intrinsic" {
     /// as the `success` and
     /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html)
     /// as the `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange_weak`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak).
+    /// [`AtomicBool::compare_exchange_weak`][cew].
+    ///
+    /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak
     pub fn atomic_cxchgweak_acq_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
     /// Stores a value if the current value is the same as the `old` value.
     /// The stabilized version of this intrinsic is available on the
@@ -222,8 +239,9 @@ extern "rust-intrinsic" {
     /// as the `success` and
     /// [`Ordering::Relaxed`](../../std/sync/atomic/enum.Ordering.html)
     /// as the `failure` parameters. For example,
-    /// [`AtomicBool::compare_exchange_weak`]
-    /// (../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak).
+    /// [`AtomicBool::compare_exchange_weak`][cew].
+    ///
+    /// [cew]: ../../std/sync/atomic/struct.AtomicBool.html#method.compare_exchange_weak
     pub fn atomic_cxchgweak_acqrel_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
 
     /// Loads the current value of the pointer.
@@ -1253,17 +1271,17 @@ extern "rust-intrinsic" {
     #[cfg(not(stage0))]
     pub fn unchecked_shr<T>(x: T, y: T) -> T;
 
-    /// Returns (a + b) mod 2^N, where N is the width of T in bits.
+    /// Returns (a + b) mod 2<sup>N</sup>, where N is the width of T in bits.
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `wrapping_add` method. For example,
     /// [`std::u32::wrapping_add`](../../std/primitive.u32.html#method.wrapping_add)
     pub fn overflowing_add<T>(a: T, b: T) -> T;
-    /// Returns (a - b) mod 2^N, where N is the width of T in bits.
+    /// Returns (a - b) mod 2<sup>N</sup>, where N is the width of T in bits.
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `wrapping_sub` method. For example,
     /// [`std::u32::wrapping_sub`](../../std/primitive.u32.html#method.wrapping_sub)
     pub fn overflowing_sub<T>(a: T, b: T) -> T;
-    /// Returns (a * b) mod 2^N, where N is the width of T in bits.
+    /// Returns (a * b) mod 2<sup>N</sup>, where N is the width of T in bits.
     /// The stabilized versions of this intrinsic are available on the integer
     /// primitives via the `wrapping_mul` method. For example,
     /// [`std::u32::wrapping_mul`](../../std/primitive.u32.html#method.wrapping_mul)
diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs
index 04394e0a3a8..273f9d0e6f6 100644
--- a/src/libcore/iter/mod.rs
+++ b/src/libcore/iter/mod.rs
@@ -358,12 +358,24 @@ impl<I> Iterator for Rev<I> where I: DoubleEndedIterator {
     fn next(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next_back() }
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+
+    fn find<P>(&mut self, predicate: P) -> Option<Self::Item>
+        where P: FnMut(&Self::Item) -> bool
+    {
+        self.iter.rfind(predicate)
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<I> DoubleEndedIterator for Rev<I> where I: DoubleEndedIterator {
     #[inline]
     fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
+
+    fn rfind<P>(&mut self, predicate: P) -> Option<Self::Item>
+        where P: FnMut(&Self::Item) -> bool
+    {
+        self.iter.find(predicate)
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs
index 34f14ef53f8..798dda19928 100644
--- a/src/libcore/iter/traits.rs
+++ b/src/libcore/iter/traits.rs
@@ -467,7 +467,7 @@ pub trait DoubleEndedIterator: Iterator {
         Self: Sized,
         P: FnMut(&Self::Item) -> bool
     {
-        for x in self.by_ref().rev() {
+        while let Some(x) = self.next_back() {
             if predicate(&x) { return Some(x) }
         }
         None
diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs
index 8904322ca48..b5553fb2947 100644
--- a/src/libcore/num/bignum.rs
+++ b/src/libcore/num/bignum.rs
@@ -19,7 +19,7 @@
 //! inputs, but we don't do so to avoid the code bloat. Each bignum is still
 //! tracked for the actual usages, so it normally doesn't matter.
 
-// This module is only for dec2flt and flt2dec, and only public because of libcoretest.
+// This module is only for dec2flt and flt2dec, and only public because of coretests.
 // It is not intended to ever be stabilized.
 #![doc(hidden)]
 #![unstable(feature = "core_private_bignum",
diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs
index e3b58b6cc7c..45fa721a5a3 100644
--- a/src/libcore/num/dec2flt/rawfp.rs
+++ b/src/libcore/num/dec2flt/rawfp.rs
@@ -10,12 +10,12 @@
 
 //! Bit fiddling on positive IEEE 754 floats. Negative numbers aren't and needn't be handled.
 //! Normal floating point numbers have a canonical representation as (frac, exp) such that the
-//! value is 2^exp * (1 + sum(frac[N-i] / 2^i)) where N is the number of bits. Subnormals are
-//! slightly different and weird, but the same principle applies.
+//! value is 2<sup>exp</sup> * (1 + sum(frac[N-i] / 2<sup>i</sup>)) where N is the number of bits.
+//! Subnormals are slightly different and weird, but the same principle applies.
 //!
-//! Here, however, we represent them as (sig, k) with f positive, such that the value is f * 2^e.
-//! Besides making the "hidden bit" explicit, this changes the exponent by the so-called
-//! mantissa shift.
+//! Here, however, we represent them as (sig, k) with f positive, such that the value is f *
+//! 2<sup>e</sup>. Besides making the "hidden bit" explicit, this changes the exponent by the
+//! so-called mantissa shift.
 //!
 //! Put another way, normally floats are written as (1) but here they are written as (2):
 //!
@@ -94,7 +94,8 @@ pub trait RawFloat : Float + Copy + Debug + LowerExp
     /// represented, the other code in this module makes sure to never let that happen.
     fn from_int(x: u64) -> Self;
 
-    /// Get the value 10^e from a pre-computed table. Panics for e >= ceil_log5_of_max_sig().
+    /// Get the value 10<sup>e</sup> from a pre-computed table. Panics for e >=
+    /// ceil_log5_of_max_sig().
     fn short_fast_pow10(e: usize) -> Self;
 
     // FIXME Everything that follows should be associated constants, but taking the value of an
diff --git a/src/libcore/num/diy_float.rs b/src/libcore/num/diy_float.rs
index 11eea753f93..6635d95155f 100644
--- a/src/libcore/num/diy_float.rs
+++ b/src/libcore/num/diy_float.rs
@@ -10,7 +10,7 @@
 
 //! Extended precision "soft float", for internal use only.
 
-// This module is only for dec2flt and flt2dec, and only public because of libcoretest.
+// This module is only for dec2flt and flt2dec, and only public because of coretests.
 // It is not intended to ever be stabilized.
 #![doc(hidden)]
 #![unstable(feature = "core_private_diy_float",
diff --git a/src/libcore/num/flt2dec/mod.rs b/src/libcore/num/flt2dec/mod.rs
index f6c03a59f81..5123e42df61 100644
--- a/src/libcore/num/flt2dec/mod.rs
+++ b/src/libcore/num/flt2dec/mod.rs
@@ -118,7 +118,7 @@ provide a large enough buffer and `Part` array, and to assemble the final
 string from resulting `Part`s itself.
 
 All algorithms and formatting functions are accompanied by extensive tests
-in `coretest::num::flt2dec` module. It also shows how to use individual
+in `coretests::num::flt2dec` module. It also shows how to use individual
 functions.
 
 */
diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs
index df343c9d45f..f665cfdee77 100644
--- a/src/libcore/num/mod.rs
+++ b/src/libcore/num/mod.rs
@@ -90,7 +90,7 @@ impl<T: fmt::UpperHex> fmt::UpperHex for Wrapping<T> {
 
 mod wrapping;
 
-// All these modules are technically private and only exposed for libcoretest:
+// All these modules are technically private and only exposed for coretests:
 pub mod flt2dec;
 pub mod dec2flt;
 pub mod bignum;
diff --git a/src/libcore/option.rs b/src/libcore/option.rs
index d997f3592fd..1a48f277625 100644
--- a/src/libcore/option.rs
+++ b/src/libcore/option.rs
@@ -894,9 +894,15 @@ impl<A> ExactSizeIterator for Item<A> {}
 impl<A> FusedIterator for Item<A> {}
 unsafe impl<A> TrustedLen for Item<A> {}
 
-/// An iterator over a reference of the contained item in an [`Option`].
+/// An iterator over a reference to the [`Some`] variant of an [`Option`].
+///
+/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none.
+///
+/// This `struct` is created by the [`Option::iter`] function.
 ///
 /// [`Option`]: enum.Option.html
+/// [`Some`]: enum.Option.html#variant.Some
+/// [`Option::iter`]: enum.Option.html#method.iter
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug)]
 pub struct Iter<'a, A: 'a> { inner: Item<&'a A> }
@@ -933,9 +939,15 @@ impl<'a, A> Clone for Iter<'a, A> {
     }
 }
 
-/// An iterator over a mutable reference of the contained item in an [`Option`].
+/// An iterator over a mutable reference to the [`Some`] variant of an [`Option`].
+///
+/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none.
+///
+/// This `struct` is created by the [`Option::iter_mut`] function.
 ///
 /// [`Option`]: enum.Option.html
+/// [`Some`]: enum.Option.html#variant.Some
+/// [`Option::iter_mut`]: enum.Option.html#method.iter_mut
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug)]
 pub struct IterMut<'a, A: 'a> { inner: Item<&'a mut A> }
@@ -964,9 +976,15 @@ impl<'a, A> FusedIterator for IterMut<'a, A> {}
 #[unstable(feature = "trusted_len", issue = "37572")]
 unsafe impl<'a, A> TrustedLen for IterMut<'a, A> {}
 
-/// An iterator over the item contained inside an [`Option`].
+/// An iterator over the value in [`Some`] variant of an [`Option`].
+///
+/// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none.
+///
+/// This `struct` is created by the [`Option::into_iter`] function.
 ///
 /// [`Option`]: enum.Option.html
+/// [`Some`]: enum.Option.html#variant.Some
+/// [`Option::into_iter`]: enum.Option.html#method.into_iter
 #[derive(Clone, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<A> { inner: Item<A> }
diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs
index d2830a6d00c..04480fc5d31 100644
--- a/src/libcore/ptr.rs
+++ b/src/libcore/ptr.rs
@@ -500,6 +500,44 @@ impl<T: ?Sized> *const T {
             intrinsics::arith_offset(self, count)
         }
     }
+
+    /// Calculates the distance between two pointers. The returned value is in
+    /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
+    ///
+    /// If the address different between the two pointers ia not a multiple of
+    /// `mem::size_of::<T>()` then the result of the division is rounded towards
+    /// zero.
+    ///
+    /// This function returns `None` if `T` is a zero-sized typed.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(offset_to)]
+    ///
+    /// fn main() {
+    ///     let a = [0; 5];
+    ///     let ptr1: *const i32 = &a[1];
+    ///     let ptr2: *const i32 = &a[3];
+    ///     assert_eq!(ptr1.offset_to(ptr2), Some(2));
+    ///     assert_eq!(ptr2.offset_to(ptr1), Some(-2));
+    ///     assert_eq!(unsafe { ptr1.offset(2) }, ptr2);
+    ///     assert_eq!(unsafe { ptr2.offset(-2) }, ptr1);
+    /// }
+    /// ```
+    #[unstable(feature = "offset_to", issue = "41079")]
+    #[inline]
+    pub fn offset_to(self, other: *const T) -> Option<isize> where T: Sized {
+        let size = mem::size_of::<T>();
+        if size == 0 {
+            None
+        } else {
+            let diff = (other as isize).wrapping_sub(self as isize);
+            Some(diff / size as isize)
+        }
+    }
 }
 
 #[lang = "mut_ptr"]
@@ -653,6 +691,44 @@ impl<T: ?Sized> *mut T {
             Some(&mut *self)
         }
     }
+
+    /// Calculates the distance between two pointers. The returned value is in
+    /// units of T: the distance in bytes is divided by `mem::size_of::<T>()`.
+    ///
+    /// If the address different between the two pointers ia not a multiple of
+    /// `mem::size_of::<T>()` then the result of the division is rounded towards
+    /// zero.
+    ///
+    /// This function returns `None` if `T` is a zero-sized typed.
+    ///
+    /// # Examples
+    ///
+    /// Basic usage:
+    ///
+    /// ```
+    /// #![feature(offset_to)]
+    ///
+    /// fn main() {
+    ///     let mut a = [0; 5];
+    ///     let ptr1: *mut i32 = &mut a[1];
+    ///     let ptr2: *mut i32 = &mut a[3];
+    ///     assert_eq!(ptr1.offset_to(ptr2), Some(2));
+    ///     assert_eq!(ptr2.offset_to(ptr1), Some(-2));
+    ///     assert_eq!(unsafe { ptr1.offset(2) }, ptr2);
+    ///     assert_eq!(unsafe { ptr2.offset(-2) }, ptr1);
+    /// }
+    /// ```
+    #[unstable(feature = "offset_to", issue = "41079")]
+    #[inline]
+    pub fn offset_to(self, other: *const T) -> Option<isize> where T: Sized {
+        let size = mem::size_of::<T>();
+        if size == 0 {
+            None
+        } else {
+            let diff = (other as isize).wrapping_sub(self as isize);
+            Some(diff / size as isize)
+        }
+    }
 }
 
 // Equality for pointers
diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs
index 45667bb4299..6d598677c9b 100644
--- a/src/libcore/slice/mod.rs
+++ b/src/libcore/slice/mod.rs
@@ -81,6 +81,10 @@ pub trait SliceExt {
     fn split<P>(&self, pred: P) -> Split<Self::Item, P>
         where P: FnMut(&Self::Item) -> bool;
 
+    #[unstable(feature = "slice_rsplit", issue = "41020")]
+    fn rsplit<P>(&self, pred: P) -> RSplit<Self::Item, P>
+        where P: FnMut(&Self::Item) -> bool;
+
     #[stable(feature = "core", since = "1.6.0")]
     fn splitn<P>(&self, n: usize, pred: P) -> SplitN<Self::Item, P>
         where P: FnMut(&Self::Item) -> bool;
@@ -159,6 +163,10 @@ pub trait SliceExt {
     fn split_mut<P>(&mut self, pred: P) -> SplitMut<Self::Item, P>
         where P: FnMut(&Self::Item) -> bool;
 
+    #[unstable(feature = "slice_rsplit", issue = "41020")]
+    fn rsplit_mut<P>(&mut self, pred: P) -> RSplitMut<Self::Item, P>
+        where P: FnMut(&Self::Item) -> bool;
+
     #[stable(feature = "core", since = "1.6.0")]
     fn splitn_mut<P>(&mut self, n: usize, pred: P) -> SplitNMut<Self::Item, P>
         where P: FnMut(&Self::Item) -> bool;
@@ -294,14 +302,20 @@ impl<T> SliceExt for [T] {
     }
 
     #[inline]
+    fn rsplit<P>(&self, pred: P) -> RSplit<T, P>
+        where P: FnMut(&T) -> bool
+    {
+        RSplit { inner: self.split(pred) }
+    }
+
+    #[inline]
     fn splitn<P>(&self, n: usize, pred: P) -> SplitN<T, P>
         where P: FnMut(&T) -> bool
     {
         SplitN {
             inner: GenericSplitN {
                 iter: self.split(pred),
-                count: n,
-                invert: false
+                count: n
             }
         }
     }
@@ -312,9 +326,8 @@ impl<T> SliceExt for [T] {
     {
         RSplitN {
             inner: GenericSplitN {
-                iter: self.split(pred),
-                count: n,
-                invert: true
+                iter: self.rsplit(pred),
+                count: n
             }
         }
     }
@@ -476,14 +489,20 @@ impl<T> SliceExt for [T] {
     }
 
     #[inline]
+    fn rsplit_mut<P>(&mut self, pred: P) -> RSplitMut<T, P>
+        where P: FnMut(&T) -> bool
+    {
+        RSplitMut { inner: self.split_mut(pred) }
+    }
+
+    #[inline]
     fn splitn_mut<P>(&mut self, n: usize, pred: P) -> SplitNMut<T, P>
         where P: FnMut(&T) -> bool
     {
         SplitNMut {
             inner: GenericSplitN {
                 iter: self.split_mut(pred),
-                count: n,
-                invert: false
+                count: n
             }
         }
     }
@@ -494,9 +513,8 @@ impl<T> SliceExt for [T] {
     {
         RSplitNMut {
             inner: GenericSplitN {
-                iter: self.split_mut(pred),
-                count: n,
-                invert: true
+                iter: self.rsplit_mut(pred),
+                count: n
             }
         }
     }
@@ -1498,9 +1516,10 @@ unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {}
 // Return the arithmetic difference if `T` is zero size.
 #[inline(always)]
 fn ptrdistance<T>(start: *const T, end: *const T) -> usize {
-    let diff = (end as usize).wrapping_sub(start as usize);
-    let size = mem::size_of::<T>();
-    diff / (if size == 0 { 1 } else { size })
+    match start.offset_to(end) {
+        Some(x) => x as usize,
+        None => (end as usize).wrapping_sub(start as usize),
+    }
 }
 
 // Extension methods for raw pointers, used by the iterators
@@ -1735,6 +1754,123 @@ impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> where
 #[unstable(feature = "fused", issue = "35602")]
 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
+/// function, starting from the end of the slice.
+///
+/// This struct is created by the [`rsplit`] method on [slices].
+///
+/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit
+/// [slices]: ../../std/primitive.slice.html
+#[unstable(feature = "slice_rsplit", issue = "41020")]
+#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`?
+pub struct RSplit<'a, T:'a, P> where P: FnMut(&T) -> bool {
+    inner: Split<'a, T, P>
+}
+
+#[unstable(feature = "slice_rsplit", issue = "41020")]
+impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("RSplit")
+            .field("v", &self.inner.v)
+            .field("finished", &self.inner.finished)
+            .finish()
+    }
+}
+
+#[unstable(feature = "slice_rsplit", issue = "41020")]
+impl<'a, T, P> Iterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
+    type Item = &'a [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a [T]> {
+        self.inner.next_back()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+}
+
+#[unstable(feature = "slice_rsplit", issue = "41020")]
+impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a [T]> {
+        self.inner.next()
+    }
+}
+
+#[unstable(feature = "slice_rsplit", issue = "41020")]
+impl<'a, T, P> SplitIter for RSplit<'a, T, P> where P: FnMut(&T) -> bool {
+    #[inline]
+    fn finish(&mut self) -> Option<&'a [T]> {
+        self.inner.finish()
+    }
+}
+
+//#[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 {}
+
+/// An iterator over the subslices of the vector which are separated
+/// by elements that match `pred`, starting from the end of the slice.
+///
+/// This struct is created by the [`rsplit_mut`] method on [slices].
+///
+/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut
+/// [slices]: ../../std/primitive.slice.html
+#[unstable(feature = "slice_rsplit", issue = "41020")]
+pub struct RSplitMut<'a, T:'a, P> where P: FnMut(&T) -> bool {
+    inner: SplitMut<'a, T, P>
+}
+
+#[unstable(feature = "slice_rsplit", issue = "41020")]
+impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        f.debug_struct("RSplitMut")
+            .field("v", &self.inner.v)
+            .field("finished", &self.inner.finished)
+            .finish()
+    }
+}
+
+#[unstable(feature = "slice_rsplit", issue = "41020")]
+impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {
+    #[inline]
+    fn finish(&mut self) -> Option<&'a mut [T]> {
+        self.inner.finish()
+    }
+}
+
+#[unstable(feature = "slice_rsplit", issue = "41020")]
+impl<'a, T, P> Iterator for RSplitMut<'a, T, P> where P: FnMut(&T) -> bool {
+    type Item = &'a mut [T];
+
+    #[inline]
+    fn next(&mut self) -> Option<&'a mut [T]> {
+        self.inner.next_back()
+    }
+
+    #[inline]
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.inner.size_hint()
+    }
+}
+
+#[unstable(feature = "slice_rsplit", issue = "41020")]
+impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> where
+    P: FnMut(&T) -> bool,
+{
+    #[inline]
+    fn next_back(&mut self) -> Option<&'a mut [T]> {
+        self.inner.next()
+    }
+}
+
+//#[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 {}
+
 /// An private iterator over subslices separated by elements that
 /// match a predicate function, splitting at most a fixed number of
 /// times.
@@ -1742,7 +1878,6 @@ impl<'a, T, P> FusedIterator for SplitMut<'a, T, P> where P: FnMut(&T) -> bool {
 struct GenericSplitN<I> {
     iter: I,
     count: usize,
-    invert: bool
 }
 
 impl<T, I: SplitIter<Item=T>> Iterator for GenericSplitN<I> {
@@ -1753,10 +1888,7 @@ impl<T, I: SplitIter<Item=T>> Iterator for GenericSplitN<I> {
         match self.count {
             0 => None,
             1 => { self.count -= 1; self.iter.finish() }
-            _ => {
-                self.count -= 1;
-                if self.invert {self.iter.next_back()} else {self.iter.next()}
-            }
+            _ => { self.count -= 1; self.iter.next() }
         }
     }
 
@@ -1798,7 +1930,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for SplitN<'a, T, P> where P: FnMut(&
 /// [slices]: ../../std/primitive.slice.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RSplitN<'a, T: 'a, P> where P: FnMut(&T) -> bool {
-    inner: GenericSplitN<Split<'a, T, P>>
+    inner: GenericSplitN<RSplit<'a, T, P>>
 }
 
 #[stable(feature = "core_impl_debug", since = "1.9.0")]
@@ -1841,7 +1973,7 @@ impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for SplitNMut<'a, T, P> where P: FnMu
 /// [slices]: ../../std/primitive.slice.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RSplitNMut<'a, T: 'a, P> where P: FnMut(&T) -> bool {
-    inner: GenericSplitN<SplitMut<'a, T, P>>
+    inner: GenericSplitN<RSplitMut<'a, T, P>>
 }
 
 #[stable(feature = "core_impl_debug", since = "1.9.0")]
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index f75a1f7ab6e..352cc926994 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -152,11 +152,16 @@ impl fmt::Display for ParseBoolError {
 Section: Creating a string
 */
 
-/// Errors which can occur when attempting to interpret a sequence of `u8`
+/// Errors which can occur when attempting to interpret a sequence of [`u8`]
 /// as a string.
 ///
-/// As such, the `from_utf8` family of functions and methods for both `String`s
-/// and `&str`s make use of this error, for example.
+/// [`u8`]: ../../std/primitive.u8.html
+///
+/// As such, the `from_utf8` family of functions and methods for both [`String`]s
+/// and [`&str`]s make use of this error, for example.
+///
+/// [`String`]: ../../std/string/struct.String.html#method.from_utf8
+/// [`&str`]: ../../std/str/fn.from_utf8.html
 #[derive(Copy, Eq, PartialEq, Clone, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Utf8Error {
@@ -210,11 +215,15 @@ impl Utf8Error {
 
 /// Converts a slice of bytes to a string slice.
 ///
-/// A string slice (`&str`) is made of bytes (`u8`), and a byte slice (`&[u8]`)
-/// is made of bytes, so this function converts between the two. Not all byte
-/// slices are valid string slices, however: `&str` requires that it is valid
-/// UTF-8. `from_utf8()` checks to ensure that the bytes are valid UTF-8, and
-/// then does the conversion.
+/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice
+/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between
+/// the two. Not all byte slices are valid string slices, however: [`&str`] requires
+/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid
+/// UTF-8, and then does the conversion.
+///
+/// [`&str`]: ../../std/primitive.str.html
+/// [`u8`]: ../../std/primitive.u8.html
+/// [byteslice]: ../../std/primitive.slice.html
 ///
 /// If you are sure that the byte slice is valid UTF-8, and you don't want to
 /// incur the overhead of the validity check, there is an unsafe version of
@@ -228,9 +237,12 @@ impl Utf8Error {
 ///
 /// [string]: ../../std/string/struct.String.html#method.from_utf8
 ///
-/// Because you can stack-allocate a `[u8; N]`, and you can take a `&[u8]` of
-/// it, this function is one way to have a stack-allocated string. There is
-/// an example of this in the examples section below.
+/// Because you can stack-allocate a `[u8; N]`, and you can take a
+/// [`&[u8]`][byteslice] of it, this function is one way to have a
+/// stack-allocated string. There is an example of this in the
+/// examples section below.
+///
+/// [byteslice]: ../../std/primitive.slice.html
 ///
 /// # Errors
 ///
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index ae47e6fdfa9..2e1058bfc34 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -153,8 +153,9 @@ unsafe impl<T> Sync for AtomicPtr<T> {}
 /// Rust's memory orderings are [the same as
 /// LLVM's](http://llvm.org/docs/LangRef.html#memory-model-for-concurrent-operations).
 ///
-/// For more information see the [nomicon][1].
-/// [1]: ../../../nomicon/atomics.html
+/// For more information see the [nomicon].
+///
+/// [nomicon]: ../../../nomicon/atomics.html
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Copy, Clone, Debug)]
 pub enum Ordering {
@@ -321,7 +322,7 @@ impl AtomicBool {
         }
     }
 
-    /// Stores a value into the bool, returning the old value.
+    /// Stores a value into the bool, returning the previous value.
     ///
     /// `swap` takes an [`Ordering`] argument which describes the memory ordering
     /// of this operation.
@@ -732,7 +733,7 @@ impl<T> AtomicPtr<T> {
         }
     }
 
-    /// Stores a value into the pointer, returning the old value.
+    /// Stores a value into the pointer, returning the previous value.
     ///
     /// `swap` takes an [`Ordering`] argument which describes the memory ordering
     /// of this operation.
@@ -1047,7 +1048,7 @@ macro_rules! atomic_int {
                 unsafe { atomic_store(self.v.get(), val, order); }
             }
 
-            /// Stores a value into the atomic integer, returning the old value.
+            /// Stores a value into the atomic integer, returning the previous value.
             ///
             /// `swap` takes an [`Ordering`] argument which describes the memory ordering of this
             /// operation.
@@ -1201,7 +1202,9 @@ macro_rules! atomic_int {
                 }
             }
 
-            /// Add to the current value, returning the previous value.
+            /// Adds to the current value, returning the previous value.
+            ///
+            /// This operation wraps around on overflow.
             ///
             /// # Examples
             ///
@@ -1218,7 +1221,9 @@ macro_rules! atomic_int {
                 unsafe { atomic_add(self.v.get(), val, order) }
             }
 
-            /// Subtract from the current value, returning the previous value.
+            /// Subtracts from the current value, returning the previous value.
+            ///
+            /// This operation wraps around on overflow.
             ///
             /// # Examples
             ///
@@ -1235,7 +1240,12 @@ macro_rules! atomic_int {
                 unsafe { atomic_sub(self.v.get(), val, order) }
             }
 
-            /// Bitwise and with the current value, returning the previous value.
+            /// Bitwise "and" with the current value.
+            ///
+            /// Performs a bitwise "and" operation on the current value and the argument `val`, and
+            /// sets the new value to the result.
+            ///
+            /// Returns the previous value.
             ///
             /// # Examples
             ///
@@ -1251,7 +1261,12 @@ macro_rules! atomic_int {
                 unsafe { atomic_and(self.v.get(), val, order) }
             }
 
-            /// Bitwise or with the current value, returning the previous value.
+            /// Bitwise "or" with the current value.
+            ///
+            /// Performs a bitwise "or" operation on the current value and the argument `val`, and
+            /// sets the new value to the result.
+            ///
+            /// Returns the previous value.
             ///
             /// # Examples
             ///
@@ -1267,7 +1282,12 @@ macro_rules! atomic_int {
                 unsafe { atomic_or(self.v.get(), val, order) }
             }
 
-            /// Bitwise xor with the current value, returning the previous value.
+            /// Bitwise "xor" with the current value.
+            ///
+            /// Performs a bitwise "xor" operation on the current value and the argument `val`, and
+            /// sets the new value to the result.
+            ///
+            /// Returns the previous value.
             ///
             /// # Examples
             ///
@@ -1415,7 +1435,7 @@ unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
     }
 }
 
-/// Returns the old value (like __sync_fetch_and_add).
+/// Returns the previous value (like __sync_fetch_and_add).
 #[inline]
 unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
@@ -1428,7 +1448,7 @@ unsafe fn atomic_add<T>(dst: *mut T, val: T, order: Ordering) -> T {
     }
 }
 
-/// Returns the old value (like __sync_fetch_and_sub).
+/// Returns the previous value (like __sync_fetch_and_sub).
 #[inline]
 unsafe fn atomic_sub<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
diff --git a/src/libcoretest/any.rs b/src/libcore/tests/any.rs
index 2d3e81aa131..2d3e81aa131 100644
--- a/src/libcoretest/any.rs
+++ b/src/libcore/tests/any.rs
diff --git a/src/libcoretest/array.rs b/src/libcore/tests/array.rs
index 6af031dee58..6af031dee58 100644
--- a/src/libcoretest/array.rs
+++ b/src/libcore/tests/array.rs
diff --git a/src/libcoretest/atomic.rs b/src/libcore/tests/atomic.rs
index b6bb5fddf4a..b6bb5fddf4a 100644
--- a/src/libcoretest/atomic.rs
+++ b/src/libcore/tests/atomic.rs
diff --git a/src/libcoretest/cell.rs b/src/libcore/tests/cell.rs
index 8585f2f0871..8585f2f0871 100644
--- a/src/libcoretest/cell.rs
+++ b/src/libcore/tests/cell.rs
diff --git a/src/libcoretest/char.rs b/src/libcore/tests/char.rs
index e4012ec91e2..e4012ec91e2 100644
--- a/src/libcoretest/char.rs
+++ b/src/libcore/tests/char.rs
diff --git a/src/libcoretest/clone.rs b/src/libcore/tests/clone.rs
index 91d68ba3344..91d68ba3344 100644
--- a/src/libcoretest/clone.rs
+++ b/src/libcore/tests/clone.rs
diff --git a/src/libcoretest/cmp.rs b/src/libcore/tests/cmp.rs
index e3c65ad8b33..e3c65ad8b33 100644
--- a/src/libcoretest/cmp.rs
+++ b/src/libcore/tests/cmp.rs
diff --git a/src/libcoretest/fmt/builders.rs b/src/libcore/tests/fmt/builders.rs
index e71e61bda5e..e71e61bda5e 100644
--- a/src/libcoretest/fmt/builders.rs
+++ b/src/libcore/tests/fmt/builders.rs
diff --git a/src/libcoretest/fmt/float.rs b/src/libcore/tests/fmt/float.rs
index 695001312e4..695001312e4 100644
--- a/src/libcoretest/fmt/float.rs
+++ b/src/libcore/tests/fmt/float.rs
diff --git a/src/libcoretest/fmt/mod.rs b/src/libcore/tests/fmt/mod.rs
index 5d204c7d523..5d204c7d523 100644
--- a/src/libcoretest/fmt/mod.rs
+++ b/src/libcore/tests/fmt/mod.rs
diff --git a/src/libcoretest/fmt/num.rs b/src/libcore/tests/fmt/num.rs
index 4ddedd91004..4ddedd91004 100644
--- a/src/libcoretest/fmt/num.rs
+++ b/src/libcore/tests/fmt/num.rs
diff --git a/src/libcoretest/hash/mod.rs b/src/libcore/tests/hash/mod.rs
index 53ac17c052f..53ac17c052f 100644
--- a/src/libcoretest/hash/mod.rs
+++ b/src/libcore/tests/hash/mod.rs
diff --git a/src/libcoretest/hash/sip.rs b/src/libcore/tests/hash/sip.rs
index 4a9657e0340..4a9657e0340 100644
--- a/src/libcoretest/hash/sip.rs
+++ b/src/libcore/tests/hash/sip.rs
diff --git a/src/libcoretest/intrinsics.rs b/src/libcore/tests/intrinsics.rs
index 2b380abf63c..2b380abf63c 100644
--- a/src/libcoretest/intrinsics.rs
+++ b/src/libcore/tests/intrinsics.rs
diff --git a/src/libcoretest/iter.rs b/src/libcore/tests/iter.rs
index 08442f9bcbf..08442f9bcbf 100644
--- a/src/libcoretest/iter.rs
+++ b/src/libcore/tests/iter.rs
diff --git a/src/libcoretest/lib.rs b/src/libcore/tests/lib.rs
index d92c378160d..d92c378160d 100644
--- a/src/libcoretest/lib.rs
+++ b/src/libcore/tests/lib.rs
diff --git a/src/libcoretest/mem.rs b/src/libcore/tests/mem.rs
index 86e59c736ba..86e59c736ba 100644
--- a/src/libcoretest/mem.rs
+++ b/src/libcore/tests/mem.rs
diff --git a/src/libcoretest/nonzero.rs b/src/libcore/tests/nonzero.rs
index 7a367ddeec8..7a367ddeec8 100644
--- a/src/libcoretest/nonzero.rs
+++ b/src/libcore/tests/nonzero.rs
diff --git a/src/libcoretest/num/bignum.rs b/src/libcore/tests/num/bignum.rs
index 58a9dd1b128..58a9dd1b128 100644
--- a/src/libcoretest/num/bignum.rs
+++ b/src/libcore/tests/num/bignum.rs
diff --git a/src/libcoretest/num/dec2flt/mod.rs b/src/libcore/tests/num/dec2flt/mod.rs
index 5d546c643e7..5d546c643e7 100644
--- a/src/libcoretest/num/dec2flt/mod.rs
+++ b/src/libcore/tests/num/dec2flt/mod.rs
diff --git a/src/libcoretest/num/dec2flt/parse.rs b/src/libcore/tests/num/dec2flt/parse.rs
index 09acf2bc517..09acf2bc517 100644
--- a/src/libcoretest/num/dec2flt/parse.rs
+++ b/src/libcore/tests/num/dec2flt/parse.rs
diff --git a/src/libcoretest/num/dec2flt/rawfp.rs b/src/libcore/tests/num/dec2flt/rawfp.rs
index 1a3533317da..1a3533317da 100644
--- a/src/libcoretest/num/dec2flt/rawfp.rs
+++ b/src/libcore/tests/num/dec2flt/rawfp.rs
diff --git a/src/libcoretest/num/flt2dec/estimator.rs b/src/libcore/tests/num/flt2dec/estimator.rs
index 0bca616ea9a..0bca616ea9a 100644
--- a/src/libcoretest/num/flt2dec/estimator.rs
+++ b/src/libcore/tests/num/flt2dec/estimator.rs
diff --git a/src/libcoretest/num/flt2dec/mod.rs b/src/libcore/tests/num/flt2dec/mod.rs
index 0f4d19e7092..0f4d19e7092 100644
--- a/src/libcoretest/num/flt2dec/mod.rs
+++ b/src/libcore/tests/num/flt2dec/mod.rs
diff --git a/src/libcoretest/num/flt2dec/strategy/dragon.rs b/src/libcore/tests/num/flt2dec/strategy/dragon.rs
index 4edb0f3df60..4edb0f3df60 100644
--- a/src/libcoretest/num/flt2dec/strategy/dragon.rs
+++ b/src/libcore/tests/num/flt2dec/strategy/dragon.rs
diff --git a/src/libcoretest/num/flt2dec/strategy/grisu.rs b/src/libcore/tests/num/flt2dec/strategy/grisu.rs
index 79e66ee669e..79e66ee669e 100644
--- a/src/libcoretest/num/flt2dec/strategy/grisu.rs
+++ b/src/libcore/tests/num/flt2dec/strategy/grisu.rs
diff --git a/src/libcoretest/num/i16.rs b/src/libcore/tests/num/i16.rs
index 7435831ac6d..7435831ac6d 100644
--- a/src/libcoretest/num/i16.rs
+++ b/src/libcore/tests/num/i16.rs
diff --git a/src/libcoretest/num/i32.rs b/src/libcore/tests/num/i32.rs
index 3b3407e1ada..3b3407e1ada 100644
--- a/src/libcoretest/num/i32.rs
+++ b/src/libcore/tests/num/i32.rs
diff --git a/src/libcoretest/num/i64.rs b/src/libcore/tests/num/i64.rs
index 9e1aec256ee..9e1aec256ee 100644
--- a/src/libcoretest/num/i64.rs
+++ b/src/libcore/tests/num/i64.rs
diff --git a/src/libcoretest/num/i8.rs b/src/libcore/tests/num/i8.rs
index f72244239b2..f72244239b2 100644
--- a/src/libcoretest/num/i8.rs
+++ b/src/libcore/tests/num/i8.rs
diff --git a/src/libcoretest/num/int_macros.rs b/src/libcore/tests/num/int_macros.rs
index 8d791283ab8..8d791283ab8 100644
--- a/src/libcoretest/num/int_macros.rs
+++ b/src/libcore/tests/num/int_macros.rs
diff --git a/src/libcoretest/num/mod.rs b/src/libcore/tests/num/mod.rs
index 51737c9c3b4..51737c9c3b4 100644
--- a/src/libcoretest/num/mod.rs
+++ b/src/libcore/tests/num/mod.rs
diff --git a/src/libcoretest/num/u16.rs b/src/libcore/tests/num/u16.rs
index 8455207583c..8455207583c 100644
--- a/src/libcoretest/num/u16.rs
+++ b/src/libcore/tests/num/u16.rs
diff --git a/src/libcoretest/num/u32.rs b/src/libcore/tests/num/u32.rs
index b44e60f6529..b44e60f6529 100644
--- a/src/libcoretest/num/u32.rs
+++ b/src/libcore/tests/num/u32.rs
diff --git a/src/libcoretest/num/u64.rs b/src/libcore/tests/num/u64.rs
index ffcd1015d58..ffcd1015d58 100644
--- a/src/libcoretest/num/u64.rs
+++ b/src/libcore/tests/num/u64.rs
diff --git a/src/libcoretest/num/u8.rs b/src/libcore/tests/num/u8.rs
index 4ee14e22f2d..4ee14e22f2d 100644
--- a/src/libcoretest/num/u8.rs
+++ b/src/libcore/tests/num/u8.rs
diff --git a/src/libcoretest/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs
index daa1cc3a7f4..daa1cc3a7f4 100644
--- a/src/libcoretest/num/uint_macros.rs
+++ b/src/libcore/tests/num/uint_macros.rs
diff --git a/src/libcoretest/ops.rs b/src/libcore/tests/ops.rs
index 1c6c13b0d02..1c6c13b0d02 100644
--- a/src/libcoretest/ops.rs
+++ b/src/libcore/tests/ops.rs
diff --git a/src/libcoretest/option.rs b/src/libcore/tests/option.rs
index 51b0655f680..51b0655f680 100644
--- a/src/libcoretest/option.rs
+++ b/src/libcore/tests/option.rs
diff --git a/src/libcoretest/ptr.rs b/src/libcore/tests/ptr.rs
index 7f6f472bfbb..7f6f472bfbb 100644
--- a/src/libcoretest/ptr.rs
+++ b/src/libcore/tests/ptr.rs
diff --git a/src/libcoretest/result.rs b/src/libcore/tests/result.rs
index 4c5f19dee12..4c5f19dee12 100644
--- a/src/libcoretest/result.rs
+++ b/src/libcore/tests/result.rs
diff --git a/src/libcoretest/slice.rs b/src/libcore/tests/slice.rs
index ec38345030f..ec38345030f 100644
--- a/src/libcoretest/slice.rs
+++ b/src/libcore/tests/slice.rs
diff --git a/src/libcoretest/str.rs b/src/libcore/tests/str.rs
index b7d9ba4463d..08daafccc54 100644
--- a/src/libcoretest/str.rs
+++ b/src/libcore/tests/str.rs
@@ -8,4 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// All `str` tests live in libcollectiontest::str
+// All `str` tests live in collectionstests::str
diff --git a/src/libcoretest/tuple.rs b/src/libcore/tests/tuple.rs
index 4fe5e0a740b..4fe5e0a740b 100644
--- a/src/libcoretest/tuple.rs
+++ b/src/libcore/tests/tuple.rs
diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs
index 809d5db3071..dca9ebb3397 100644
--- a/src/librustc/hir/map/definitions.rs
+++ b/src/librustc/hir/map/definitions.rs
@@ -394,6 +394,10 @@ impl Definitions {
         }
     }
 
+    pub fn node_to_hir_id(&self, node_id: ast::NodeId) -> hir::HirId {
+        self.node_to_hir_id[node_id]
+    }
+
     /// Add a definition with a parent definition.
     pub fn create_def_with_parent(&mut self,
                                   parent: Option<DefIndex>,
diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs
new file mode 100644
index 00000000000..73d81212cd7
--- /dev/null
+++ b/src/librustc/ich/hcx.rs
@@ -0,0 +1,300 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use hir;
+use hir::def_id::DefId;
+use ich::{self, CachingCodemapView, DefPathHashes};
+use session::config::DebugInfoLevel::NoDebugInfo;
+use ty;
+
+use std::hash as std_hash;
+
+use syntax::ast;
+use syntax::attr;
+use syntax::ext::hygiene::SyntaxContext;
+use syntax::symbol::Symbol;
+use syntax_pos::Span;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use rustc_data_structures::accumulate_vec::AccumulateVec;
+
+/// This is the context state available during incr. comp. hashing. It contains
+/// enough information to transform DefIds and HirIds into stable DefPaths (i.e.
+/// a reference to the TyCtxt) and it holds a few caches for speeding up various
+/// things (e.g. each DefId/DefPath is only hashed once).
+pub struct StableHashingContext<'a, 'tcx: 'a> {
+    tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
+    def_path_hashes: DefPathHashes<'a, 'tcx>,
+    codemap: CachingCodemapView<'tcx>,
+    hash_spans: bool,
+    hash_bodies: bool,
+    overflow_checks_enabled: bool,
+    node_id_hashing_mode: NodeIdHashingMode,
+    // A sorted array of symbol keys for fast lookup.
+    ignored_attr_names: Vec<Symbol>,
+}
+
+#[derive(PartialEq, Eq, Clone, Copy)]
+pub enum NodeIdHashingMode {
+    Ignore,
+    HashDefPath,
+    HashTraitsInScope,
+}
+
+impl<'a, 'tcx: 'a> StableHashingContext<'a, 'tcx> {
+
+    pub fn new(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> Self {
+        let hash_spans_initial = tcx.sess.opts.debuginfo != NoDebugInfo;
+        let check_overflow_initial = tcx.sess.overflow_checks();
+
+        let mut ignored_attr_names: Vec<_> = ich::IGNORED_ATTRIBUTES
+            .iter()
+            .map(|&s| Symbol::intern(s))
+            .collect();
+
+        ignored_attr_names.sort();
+
+        StableHashingContext {
+            tcx: tcx,
+            def_path_hashes: DefPathHashes::new(tcx),
+            codemap: CachingCodemapView::new(tcx),
+            hash_spans: hash_spans_initial,
+            hash_bodies: true,
+            overflow_checks_enabled: check_overflow_initial,
+            node_id_hashing_mode: NodeIdHashingMode::HashDefPath,
+            ignored_attr_names: ignored_attr_names,
+        }
+    }
+
+    #[inline]
+    pub fn while_hashing_hir_bodies<F: FnOnce(&mut Self)>(&mut self,
+                                                          hash_bodies: bool,
+                                                          f: F) {
+        let prev_hash_bodies = self.hash_bodies;
+        self.hash_bodies = hash_bodies;
+        f(self);
+        self.hash_bodies = prev_hash_bodies;
+    }
+
+    #[inline]
+    pub fn while_hashing_spans<F: FnOnce(&mut Self)>(&mut self,
+                                                     hash_spans: bool,
+                                                     f: F) {
+        let prev_hash_spans = self.hash_spans;
+        self.hash_spans = hash_spans;
+        f(self);
+        self.hash_spans = prev_hash_spans;
+    }
+
+    #[inline]
+    pub fn with_node_id_hashing_mode<F: FnOnce(&mut Self)>(&mut self,
+                                                           mode: NodeIdHashingMode,
+                                                           f: F) {
+        let prev = self.node_id_hashing_mode;
+        self.node_id_hashing_mode = mode;
+        f(self);
+        self.node_id_hashing_mode = prev;
+    }
+
+    #[inline]
+    pub fn tcx(&self) -> ty::TyCtxt<'a, 'tcx, 'tcx> {
+        self.tcx
+    }
+
+    #[inline]
+    pub fn def_path_hash(&mut self, def_id: DefId) -> u64 {
+        self.def_path_hashes.hash(def_id)
+    }
+
+    #[inline]
+    pub fn hash_spans(&self) -> bool {
+        self.hash_spans
+    }
+
+    #[inline]
+    pub fn hash_bodies(&self) -> bool {
+        self.hash_bodies
+    }
+
+    #[inline]
+    pub fn codemap(&mut self) -> &mut CachingCodemapView<'tcx> {
+        &mut self.codemap
+    }
+
+    #[inline]
+    pub fn is_ignored_attr(&self, name: Symbol) -> bool {
+        self.ignored_attr_names.binary_search(&name).is_ok()
+    }
+
+    pub fn hash_hir_item_like<F: FnOnce(&mut Self)>(&mut self,
+                                                    item_attrs: &[ast::Attribute],
+                                                    f: F) {
+        let prev_overflow_checks = self.overflow_checks_enabled;
+        if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") {
+            self.overflow_checks_enabled = true;
+        }
+        let prev_hash_node_ids = self.node_id_hashing_mode;
+        self.node_id_hashing_mode = NodeIdHashingMode::Ignore;
+
+        f(self);
+
+        self.node_id_hashing_mode = prev_hash_node_ids;
+        self.overflow_checks_enabled = prev_overflow_checks;
+    }
+
+    #[inline]
+    pub fn binop_can_panic_at_runtime(&self, binop: hir::BinOp_) -> bool
+    {
+        match binop {
+            hir::BiAdd |
+            hir::BiSub |
+            hir::BiMul => self.overflow_checks_enabled,
+
+            hir::BiDiv |
+            hir::BiRem => true,
+
+            hir::BiAnd |
+            hir::BiOr |
+            hir::BiBitXor |
+            hir::BiBitAnd |
+            hir::BiBitOr |
+            hir::BiShl |
+            hir::BiShr |
+            hir::BiEq |
+            hir::BiLt |
+            hir::BiLe |
+            hir::BiNe |
+            hir::BiGe |
+            hir::BiGt => false
+        }
+    }
+
+    #[inline]
+    pub fn unop_can_panic_at_runtime(&self, unop: hir::UnOp) -> bool
+    {
+        match unop {
+            hir::UnDeref |
+            hir::UnNot => false,
+            hir::UnNeg => self.overflow_checks_enabled,
+        }
+    }
+}
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::NodeId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        match hcx.node_id_hashing_mode {
+            NodeIdHashingMode::Ignore => {
+                // Most NodeIds in the HIR can be ignored, but if there is a
+                // corresponding entry in the `trait_map` we need to hash that.
+                // Make sure we don't ignore too much by checking that there is
+                // no entry in a debug_assert!().
+                debug_assert!(hcx.tcx.trait_map.get(self).is_none());
+            }
+            NodeIdHashingMode::HashDefPath => {
+                hcx.tcx.hir.definitions().node_to_hir_id(*self).hash_stable(hcx, hasher);
+            }
+            NodeIdHashingMode::HashTraitsInScope => {
+                if let Some(traits) = hcx.tcx.trait_map.get(self) {
+                    // The ordering of the candidates is not fixed. So we hash
+                    // the def-ids and then sort them and hash the collection.
+                    let mut candidates: AccumulateVec<[_; 8]> =
+                        traits.iter()
+                              .map(|&hir::TraitCandidate { def_id, import_id: _ }| {
+                                  hcx.def_path_hash(def_id)
+                              })
+                              .collect();
+                    if traits.len() > 1 {
+                        candidates.sort();
+                    }
+                    candidates.hash_stable(hcx, hasher);
+                }
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for Span {
+
+    // Hash a span in a stable way. We can't directly hash the span's BytePos
+    // fields (that would be similar to hashing pointers, since those are just
+    // offsets into the CodeMap). Instead, we hash the (file name, line, column)
+    // triple, which stays the same even if the containing FileMap has moved
+    // within the CodeMap.
+    // Also note that we are hashing byte offsets for the column, not unicode
+    // codepoint offsets. For the purpose of the hash that's sufficient.
+    // Also, hashing filenames is expensive so we avoid doing it twice when the
+    // span starts and ends in the same file, which is almost always the case.
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use syntax_pos::Pos;
+
+        if !hcx.hash_spans {
+            return
+        }
+
+        // If this is not an empty or invalid span, we want to hash the last
+        // position that belongs to it, as opposed to hashing the first
+        // position past it.
+        let span_hi = if self.hi > self.lo {
+            // We might end up in the middle of a multibyte character here,
+            // but that's OK, since we are not trying to decode anything at
+            // this position.
+            self.hi - ::syntax_pos::BytePos(1)
+        } else {
+            self.hi
+        };
+
+        {
+            let loc1 = hcx.codemap().byte_pos_to_line_and_col(self.lo);
+            let loc1 = loc1.as_ref()
+                           .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize()))
+                           .unwrap_or(("???", 0, 0));
+
+            let loc2 = hcx.codemap().byte_pos_to_line_and_col(span_hi);
+            let loc2 = loc2.as_ref()
+                           .map(|&(ref fm, line, col)| (&fm.name[..], line, col.to_usize()))
+                           .unwrap_or(("???", 0, 0));
+
+            if loc1.0 == loc2.0 {
+                std_hash::Hash::hash(&0u8, hasher);
+
+                std_hash::Hash::hash(loc1.0, hasher);
+                std_hash::Hash::hash(&loc1.1, hasher);
+                std_hash::Hash::hash(&loc1.2, hasher);
+
+                // Do not hash the file name twice
+                std_hash::Hash::hash(&loc2.1, hasher);
+                std_hash::Hash::hash(&loc2.2, hasher);
+            } else {
+                std_hash::Hash::hash(&1u8, hasher);
+
+                std_hash::Hash::hash(loc1.0, hasher);
+                std_hash::Hash::hash(&loc1.1, hasher);
+                std_hash::Hash::hash(&loc1.2, hasher);
+
+                std_hash::Hash::hash(loc2.0, hasher);
+                std_hash::Hash::hash(&loc2.1, hasher);
+                std_hash::Hash::hash(&loc2.2, hasher);
+            }
+        }
+
+        if self.ctxt == SyntaxContext::empty() {
+            0u8.hash_stable(hcx, hasher);
+        } else {
+            1u8.hash_stable(hcx, hasher);
+            self.source_callsite().hash_stable(hcx, hasher);
+        }
+    }
+}
diff --git a/src/librustc/ich/impls_const_math.rs b/src/librustc/ich/impls_const_math.rs
new file mode 100644
index 00000000000..6d11f2a87a4
--- /dev/null
+++ b/src/librustc/ich/impls_const_math.rs
@@ -0,0 +1,71 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module contains `HashStable` implementations for various data types
+//! from `rustc_const_math` in no particular order.
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstFloat {
+    F32(val),
+    F64(val)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstInt {
+    I8(val),
+    I16(val),
+    I32(val),
+    I64(val),
+    I128(val),
+    Isize(val),
+    U8(val),
+    U16(val),
+    U32(val),
+    U64(val),
+    U128(val),
+    Usize(val)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstIsize {
+    Is16(i16),
+    Is32(i32),
+    Is64(i64)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstUsize {
+    Us16(i16),
+    Us32(i32),
+    Us64(i64)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::ConstMathErr {
+    NotInRange,
+    CmpBetweenUnequalTypes,
+    UnequalTypes(op),
+    Overflow(op),
+    ShiftNegative,
+    DivisionByZero,
+    RemainderByZero,
+    UnsignedNegation,
+    ULitOutOfRange(int_ty),
+    LitOutOfRange(int_ty)
+});
+
+impl_stable_hash_for!(enum ::rustc_const_math::Op {
+    Add,
+    Sub,
+    Mul,
+    Div,
+    Rem,
+    Shr,
+    Shl,
+    Neg,
+    BitAnd,
+    BitOr,
+    BitXor
+});
diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs
new file mode 100644
index 00000000000..9cf8a0693d3
--- /dev/null
+++ b/src/librustc/ich/impls_hir.rs
@@ -0,0 +1,1106 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module contains `HashStable` implementations for various HIR data
+//! types in no particular order.
+
+use hir;
+use hir::def_id::DefId;
+use ich::{StableHashingContext, NodeIdHashingMode};
+use std::mem;
+
+use syntax::ast;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for DefId {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        hcx.def_path_hash(*self).hash_stable(hcx, hasher);
+    }
+}
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::HirId {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::HirId {
+            owner,
+            local_id,
+        } = *self;
+
+        hcx.def_path_hash(DefId::local(owner)).hash_stable(hcx, hasher);
+        local_id.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(tuple_struct hir::ItemLocalId { index });
+
+// The following implementations of HashStable for ItemId, TraitItemId, and
+// ImplItemId deserve special attention. Normally we do not hash NodeIds within
+// the HIR, since they just signify a HIR nodes own path. But ItemId et al
+// are used when another item in the HIR is *referenced* and we certainly
+// want to pick up on a reference changing its target, so we hash the NodeIds
+// in "DefPath Mode".
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::ItemId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::ItemId {
+            id
+        } = *self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            id.hash_stable(hcx, hasher);
+        })
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::TraitItemId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::TraitItemId {
+            node_id
+        } = * self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            node_id.hash_stable(hcx, hasher);
+        })
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::ImplItemId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::ImplItemId {
+            node_id
+        } = * self;
+
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| {
+            node_id.hash_stable(hcx, hasher);
+        })
+    }
+}
+
+impl_stable_hash_for!(struct hir::Lifetime {
+    id,
+    span,
+    name
+});
+
+impl_stable_hash_for!(struct hir::LifetimeDef {
+    lifetime,
+    bounds,
+    pure_wrt_drop
+});
+
+impl_stable_hash_for!(struct hir::Path {
+    span,
+    def,
+    segments
+});
+
+impl_stable_hash_for!(struct hir::PathSegment {
+    name,
+    parameters
+});
+
+impl_stable_hash_for!(enum hir::PathParameters {
+    AngleBracketedParameters(data),
+    ParenthesizedParameters(data)
+});
+
+impl_stable_hash_for!(struct hir::AngleBracketedParameterData {
+    lifetimes,
+    types,
+    infer_types,
+    bindings
+});
+
+impl_stable_hash_for!(struct hir::ParenthesizedParameterData {
+    span,
+    inputs,
+    output
+});
+
+impl_stable_hash_for!(enum hir::TyParamBound {
+    TraitTyParamBound(poly_trait_ref, trait_bound_modifier),
+    RegionTyParamBound(lifetime)
+});
+
+impl_stable_hash_for!(enum hir::TraitBoundModifier {
+    None,
+    Maybe
+});
+
+impl_stable_hash_for!(struct hir::TyParam {
+    name,
+    id,
+    bounds,
+    default,
+    span,
+    pure_wrt_drop
+});
+
+impl_stable_hash_for!(struct hir::Generics {
+    lifetimes,
+    ty_params,
+    where_clause,
+    span
+});
+
+impl_stable_hash_for!(struct hir::WhereClause {
+    id,
+    predicates
+});
+
+impl_stable_hash_for!(enum hir::WherePredicate {
+    BoundPredicate(pred),
+    RegionPredicate(pred),
+    EqPredicate(pred)
+});
+
+impl_stable_hash_for!(struct hir::WhereBoundPredicate {
+    span,
+    bound_lifetimes,
+    bounded_ty,
+    bounds
+});
+
+impl_stable_hash_for!(struct hir::WhereRegionPredicate {
+    span,
+    lifetime,
+    bounds
+});
+
+impl_stable_hash_for!(struct hir::WhereEqPredicate {
+    id,
+    span,
+    lhs_ty,
+    rhs_ty
+});
+
+impl_stable_hash_for!(struct hir::MutTy {
+    ty,
+    mutbl
+});
+
+impl_stable_hash_for!(struct hir::MethodSig {
+    unsafety,
+    constness,
+    abi,
+    decl,
+    generics
+});
+
+impl_stable_hash_for!(struct hir::TypeBinding {
+    id,
+    name,
+    ty,
+    span
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Ty {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let node_id_hashing_mode = match self.node {
+            hir::TySlice(..)       |
+            hir::TyArray(..)       |
+            hir::TyPtr(..)         |
+            hir::TyRptr(..)        |
+            hir::TyBareFn(..)      |
+            hir::TyNever           |
+            hir::TyTup(..)         |
+            hir::TyTraitObject(..) |
+            hir::TyImplTrait(..)   |
+            hir::TyTypeof(..)      |
+            hir::TyErr             |
+            hir::TyInfer           => {
+                NodeIdHashingMode::Ignore
+            }
+            hir::TyPath(..) => {
+                NodeIdHashingMode::HashTraitsInScope
+            }
+        };
+
+        hcx.while_hashing_hir_bodies(true, |hcx| {
+            let hir::Ty {
+                id,
+                ref node,
+                ref span,
+            } = *self;
+
+            hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| {
+                id.hash_stable(hcx, hasher);
+            });
+            node.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        })
+    }
+}
+
+impl_stable_hash_for!(enum hir::PrimTy {
+    TyInt(int_ty),
+    TyUint(uint_ty),
+    TyFloat(float_ty),
+    TyStr,
+    TyBool,
+    TyChar
+});
+
+impl_stable_hash_for!(struct hir::BareFnTy {
+    unsafety,
+    abi,
+    lifetimes,
+    decl
+});
+
+impl_stable_hash_for!(enum hir::Ty_ {
+    TySlice(t),
+    TyArray(t, body_id),
+    TyPtr(t),
+    TyRptr(lifetime, t),
+    TyBareFn(t),
+    TyNever,
+    TyTup(ts),
+    TyPath(qpath),
+    TyTraitObject(trait_refs, lifetime),
+    TyImplTrait(bounds),
+    TyTypeof(body_id),
+    TyErr,
+    TyInfer
+});
+
+impl_stable_hash_for!(struct hir::FnDecl {
+    inputs,
+    output,
+    variadic,
+    has_implicit_self
+});
+
+impl_stable_hash_for!(enum hir::FunctionRetTy {
+    DefaultReturn(span),
+    Return(t)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::TraitRef {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::TraitRef {
+            ref path,
+            ref_id,
+        } = *self;
+
+        path.hash_stable(hcx, hasher);
+        hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| {
+            ref_id.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+
+impl_stable_hash_for!(struct hir::PolyTraitRef {
+    bound_lifetimes,
+    trait_ref,
+    span
+});
+
+impl_stable_hash_for!(enum hir::QPath {
+    Resolved(t, path),
+    TypeRelative(t, path_segment)
+});
+
+impl_stable_hash_for!(struct hir::MacroDef {
+    name,
+    attrs,
+    id,
+    span,
+    body
+});
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Block {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::Block {
+            ref stmts,
+            ref expr,
+            id,
+            rules,
+            span,
+            targeted_by_break,
+        } = *self;
+
+        let non_item_stmts = || stmts.iter().filter(|stmt| {
+            match stmt.node {
+                hir::StmtDecl(ref decl, _) => {
+                    match decl.node {
+                        // If this is a declaration of a nested item, we don't
+                        // want to leave any trace of it in the hash value, not
+                        // even that it exists. Otherwise changing the position
+                        // of nested items would invalidate the containing item
+                        // even though that does not constitute a semantic
+                        // change.
+                        hir::DeclItem(_) => false,
+                        hir::DeclLocal(_) => true
+                    }
+                }
+                hir::StmtExpr(..) |
+                hir::StmtSemi(..) => true
+            }
+        });
+
+        let count = non_item_stmts().count();
+
+        count.hash_stable(hcx, hasher);
+
+        for stmt in non_item_stmts() {
+            stmt.hash_stable(hcx, hasher);
+        }
+
+        expr.hash_stable(hcx, hasher);
+        id.hash_stable(hcx, hasher);
+        rules.hash_stable(hcx, hasher);
+        span.hash_stable(hcx, hasher);
+        targeted_by_break.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Pat {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let node_id_hashing_mode = match self.node {
+            hir::PatKind::Wild        |
+            hir::PatKind::Binding(..) |
+            hir::PatKind::Tuple(..)   |
+            hir::PatKind::Box(..)     |
+            hir::PatKind::Ref(..)     |
+            hir::PatKind::Lit(..)     |
+            hir::PatKind::Range(..)   |
+            hir::PatKind::Slice(..)   => {
+                NodeIdHashingMode::Ignore
+            }
+            hir::PatKind::Path(..)        |
+            hir::PatKind::Struct(..)      |
+            hir::PatKind::TupleStruct(..) => {
+                NodeIdHashingMode::HashTraitsInScope
+            }
+        };
+
+        let hir::Pat {
+            id,
+            ref node,
+            ref span
+        } = *self;
+
+        hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| {
+            id.hash_stable(hcx, hasher);
+        });
+        node.hash_stable(hcx, hasher);
+        span.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for_spanned!(hir::FieldPat);
+impl_stable_hash_for!(struct hir::FieldPat {
+    name,
+    pat,
+    is_shorthand
+});
+
+impl_stable_hash_for!(enum hir::BindingMode {
+    BindByRef(mutability),
+    BindByValue(mutability)
+});
+
+impl_stable_hash_for!(enum hir::RangeEnd {
+    Included,
+    Excluded
+});
+
+impl_stable_hash_for!(enum hir::PatKind {
+    Wild,
+    Binding(binding_mode, var, name, sub),
+    Struct(path, field_pats, dotdot),
+    TupleStruct(path, field_pats, dotdot),
+    Path(path),
+    Tuple(field_pats, dotdot),
+    Box(sub),
+    Ref(sub, mutability),
+    Lit(expr),
+    Range(start, end, end_kind),
+    Slice(one, two, three)
+});
+
+impl_stable_hash_for!(enum hir::BinOp_ {
+    BiAdd,
+    BiSub,
+    BiMul,
+    BiDiv,
+    BiRem,
+    BiAnd,
+    BiOr,
+    BiBitXor,
+    BiBitAnd,
+    BiBitOr,
+    BiShl,
+    BiShr,
+    BiEq,
+    BiLt,
+    BiLe,
+    BiNe,
+    BiGe,
+    BiGt
+});
+
+impl_stable_hash_for_spanned!(hir::BinOp_);
+
+impl_stable_hash_for!(enum hir::UnOp {
+    UnDeref,
+    UnNot,
+    UnNeg
+});
+
+impl_stable_hash_for_spanned!(hir::Stmt_);
+
+impl_stable_hash_for!(struct hir::Local {
+    pat,
+    ty,
+    init,
+    id,
+    span,
+    attrs
+});
+
+impl_stable_hash_for_spanned!(hir::Decl_);
+impl_stable_hash_for!(enum hir::Decl_ {
+    DeclLocal(local),
+    DeclItem(item_id)
+});
+
+impl_stable_hash_for!(struct hir::Arm {
+    attrs,
+    pats,
+    guard,
+    body
+});
+
+impl_stable_hash_for!(struct hir::Field {
+    name,
+    expr,
+    span,
+    is_shorthand
+});
+
+impl_stable_hash_for_spanned!(ast::Name);
+
+
+impl_stable_hash_for!(enum hir::BlockCheckMode {
+    DefaultBlock,
+    UnsafeBlock(src),
+    PushUnsafeBlock(src),
+    PopUnsafeBlock(src)
+});
+
+impl_stable_hash_for!(enum hir::UnsafeSource {
+    CompilerGenerated,
+    UserProvided
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Expr {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        hcx.while_hashing_hir_bodies(true, |hcx| {
+            let hir::Expr {
+                id,
+                ref span,
+                ref node,
+                ref attrs
+            } = *self;
+
+            let (spans_always_on, node_id_hashing_mode) = match *node {
+                hir::ExprBox(..)        |
+                hir::ExprArray(..)      |
+                hir::ExprCall(..)       |
+                hir::ExprLit(..)        |
+                hir::ExprCast(..)       |
+                hir::ExprType(..)       |
+                hir::ExprIf(..)         |
+                hir::ExprWhile(..)      |
+                hir::ExprLoop(..)       |
+                hir::ExprMatch(..)      |
+                hir::ExprClosure(..)    |
+                hir::ExprBlock(..)      |
+                hir::ExprAssign(..)     |
+                hir::ExprTupField(..)   |
+                hir::ExprAddrOf(..)     |
+                hir::ExprBreak(..)      |
+                hir::ExprAgain(..)      |
+                hir::ExprRet(..)        |
+                hir::ExprInlineAsm(..)  |
+                hir::ExprRepeat(..)     |
+                hir::ExprTup(..)        => {
+                    // For these we only hash the span when debuginfo is on.
+                    (false, NodeIdHashingMode::Ignore)
+                }
+                // For the following, spans might be significant because of
+                // panic messages indicating the source location.
+                hir::ExprBinary(op, ..) => {
+                    (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore)
+                }
+                hir::ExprUnary(op, _) => {
+                    (hcx.unop_can_panic_at_runtime(op), NodeIdHashingMode::Ignore)
+                }
+                hir::ExprAssignOp(op, ..) => {
+                    (hcx.binop_can_panic_at_runtime(op.node), NodeIdHashingMode::Ignore)
+                }
+                hir::ExprIndex(..) => {
+                    (true, NodeIdHashingMode::Ignore)
+                }
+                // For these we don't care about the span, but want to hash the
+                // trait in scope
+                hir::ExprMethodCall(..) |
+                hir::ExprPath(..)       |
+                hir::ExprStruct(..)     |
+                hir::ExprField(..)      => {
+                    (false, NodeIdHashingMode::HashTraitsInScope)
+                }
+            };
+
+            hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| {
+                id.hash_stable(hcx, hasher);
+            });
+
+            if spans_always_on {
+                hcx.while_hashing_spans(true, |hcx| {
+                    span.hash_stable(hcx, hasher);
+                    node.hash_stable(hcx, hasher);
+                    attrs.hash_stable(hcx, hasher);
+                });
+            } else {
+                span.hash_stable(hcx, hasher);
+                node.hash_stable(hcx, hasher);
+                attrs.hash_stable(hcx, hasher);
+            }
+        })
+    }
+}
+
+impl_stable_hash_for!(enum hir::Expr_ {
+    ExprBox(sub),
+    ExprArray(subs),
+    ExprCall(callee, args),
+    ExprMethodCall(name, ts, args),
+    ExprTup(fields),
+    ExprBinary(op, lhs, rhs),
+    ExprUnary(op, operand),
+    ExprLit(value),
+    ExprCast(expr, t),
+    ExprType(expr, t),
+    ExprIf(cond, then, els),
+    ExprWhile(cond, body, label),
+    ExprLoop(body, label, loop_src),
+    ExprMatch(matchee, arms, match_src),
+    ExprClosure(capture_clause, decl, body_id, span),
+    ExprBlock(blk),
+    ExprAssign(lhs, rhs),
+    ExprAssignOp(op, lhs, rhs),
+    ExprField(owner, field_name),
+    ExprTupField(owner, idx),
+    ExprIndex(lhs, rhs),
+    ExprPath(path),
+    ExprAddrOf(mutability, sub),
+    ExprBreak(destination, sub),
+    ExprAgain(destination),
+    ExprRet(val),
+    ExprInlineAsm(asm, inputs, outputs),
+    ExprStruct(path, fields, base),
+    ExprRepeat(val, times)
+});
+
+impl_stable_hash_for!(enum hir::LoopSource {
+    Loop,
+    WhileLet,
+    ForLoop
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::MatchSource {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use hir::MatchSource;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            MatchSource::Normal |
+            MatchSource::WhileLetDesugar |
+            MatchSource::ForLoopDesugar |
+            MatchSource::TryDesugar => {
+                // No fields to hash.
+            }
+            MatchSource::IfLetDesugar { contains_else_clause } => {
+                contains_else_clause.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum hir::CaptureClause {
+    CaptureByValue,
+    CaptureByRef
+});
+
+impl_stable_hash_for_spanned!(usize);
+
+impl_stable_hash_for!(struct hir::Destination {
+    ident,
+    target_id
+});
+
+impl_stable_hash_for_spanned!(ast::Ident);
+
+impl_stable_hash_for!(enum hir::LoopIdResult {
+    Ok(node_id),
+    Err(loop_id_error)
+});
+
+impl_stable_hash_for!(enum hir::LoopIdError {
+    OutsideLoopScope,
+    UnlabeledCfInWhileCondition,
+    UnresolvedLabel
+});
+
+impl_stable_hash_for!(enum hir::ScopeTarget {
+    Block(node_id),
+    Loop(loop_id_result)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::Ident {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ast::Ident {
+            ref name,
+            ctxt: _ // Ignore this
+        } = *self;
+
+        name.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::TraitItem {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::TraitItem {
+            id,
+            name,
+            ref attrs,
+            ref node,
+            span
+        } = *self;
+
+        hcx.hash_hir_item_like(attrs, |hcx| {
+            id.hash_stable(hcx, hasher);
+            name.hash_stable(hcx, hasher);
+            attrs.hash_stable(hcx, hasher);
+            node.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+impl_stable_hash_for!(enum hir::TraitMethod {
+    Required(name),
+    Provided(body)
+});
+
+impl_stable_hash_for!(enum hir::TraitItemKind {
+    Const(t, body),
+    Method(sig, method),
+    Type(bounds, rhs)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::ImplItem {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::ImplItem {
+            id,
+            name,
+            ref vis,
+            defaultness,
+            ref attrs,
+            ref node,
+            span
+        } = *self;
+
+        hcx.hash_hir_item_like(attrs, |hcx| {
+            id.hash_stable(hcx, hasher);
+            name.hash_stable(hcx, hasher);
+            vis.hash_stable(hcx, hasher);
+            defaultness.hash_stable(hcx, hasher);
+            attrs.hash_stable(hcx, hasher);
+            node.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+impl_stable_hash_for!(enum hir::ImplItemKind {
+    Const(t, body),
+    Method(sig, body),
+    Type(t)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Visibility {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            hir::Visibility::Public |
+            hir::Visibility::Crate |
+            hir::Visibility::Inherited => {
+                // No fields to hash.
+            }
+            hir::Visibility::Restricted { ref path, id } => {
+                hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashTraitsInScope, |hcx| {
+                    id.hash_stable(hcx, hasher);
+                });
+                path.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Defaultness {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            hir::Defaultness::Final => {
+                // No fields to hash.
+            }
+            hir::Defaultness::Default { has_value } => {
+                has_value.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum hir::ImplPolarity {
+    Positive,
+    Negative
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Mod {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::Mod {
+            inner,
+            // We are not hashing the IDs of the items contained in the module.
+            // This is harmless and matches the current behavior but it's not
+            // actually correct. See issue #40876.
+            item_ids: _,
+        } = *self;
+
+        inner.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct hir::ForeignMod {
+    abi,
+    items
+});
+
+impl_stable_hash_for!(struct hir::EnumDef {
+    variants
+});
+
+impl_stable_hash_for!(struct hir::Variant_ {
+    name,
+    attrs,
+    data,
+    disr_expr
+});
+
+impl_stable_hash_for_spanned!(hir::Variant_);
+
+impl_stable_hash_for!(enum hir::UseKind {
+    Single,
+    Glob,
+    ListStem
+});
+
+impl_stable_hash_for!(struct hir::StructField {
+    span,
+    name,
+    vis,
+    id,
+    ty,
+    attrs
+});
+
+impl_stable_hash_for!(enum hir::VariantData {
+    Struct(fields, id),
+    Tuple(fields, id),
+    Unit(id)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::Item {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let node_id_hashing_mode = match self.node {
+            hir::ItemExternCrate(..) |
+            hir::ItemStatic(..)      |
+            hir::ItemConst(..)       |
+            hir::ItemFn(..)          |
+            hir::ItemMod(..)         |
+            hir::ItemForeignMod(..)  |
+            hir::ItemTy(..)          |
+            hir::ItemEnum(..)        |
+            hir::ItemStruct(..)      |
+            hir::ItemUnion(..)       |
+            hir::ItemTrait(..)       |
+            hir::ItemDefaultImpl(..) |
+            hir::ItemImpl(..)        => {
+                NodeIdHashingMode::Ignore
+            }
+            hir::ItemUse(..) => {
+                NodeIdHashingMode::HashTraitsInScope
+            }
+        };
+
+        let hir::Item {
+            name,
+            ref attrs,
+            id,
+            ref node,
+            ref vis,
+            span
+        } = *self;
+
+        hcx.hash_hir_item_like(attrs, |hcx| {
+            hcx.with_node_id_hashing_mode(node_id_hashing_mode, |hcx| {
+                id.hash_stable(hcx, hasher);
+            });
+            name.hash_stable(hcx, hasher);
+            attrs.hash_stable(hcx, hasher);
+            node.hash_stable(hcx, hasher);
+            vis.hash_stable(hcx, hasher);
+            span.hash_stable(hcx, hasher);
+        });
+    }
+}
+
+impl_stable_hash_for!(enum hir::Item_ {
+    ItemExternCrate(name),
+    ItemUse(path, use_kind),
+    ItemStatic(ty, mutability, body_id),
+    ItemConst(ty, body_id),
+    ItemFn(fn_decl, unsafety, constness, abi, generics, body_id),
+    ItemMod(module),
+    ItemForeignMod(foreign_mod),
+    ItemTy(ty, generics),
+    ItemEnum(enum_def, generics),
+    ItemStruct(variant_data, generics),
+    ItemUnion(variant_data, generics),
+    ItemTrait(unsafety, generics, bounds, item_refs),
+    ItemDefaultImpl(unsafety, trait_ref),
+    ItemImpl(unsafety, impl_polarity, generics, trait_ref, ty, impl_item_refs)
+});
+
+impl_stable_hash_for!(struct hir::TraitItemRef {
+    id,
+    name,
+    kind,
+    span,
+    defaultness
+});
+
+impl_stable_hash_for!(struct hir::ImplItemRef {
+    id,
+    name,
+    kind,
+    span,
+    vis,
+    defaultness
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::AssociatedItemKind {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            hir::AssociatedItemKind::Const |
+            hir::AssociatedItemKind::Type => {
+                // No fields to hash.
+            }
+            hir::AssociatedItemKind::Method { has_self } => {
+                has_self.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct hir::ForeignItem {
+    name,
+    attrs,
+    node,
+    id,
+    span,
+    vis
+});
+
+impl_stable_hash_for!(enum hir::ForeignItem_ {
+    ForeignItemFn(fn_decl, arg_names, generics),
+    ForeignItemStatic(ty, is_mutbl)
+});
+
+impl_stable_hash_for!(enum hir::Stmt_ {
+    StmtDecl(decl, id),
+    StmtExpr(expr, id),
+    StmtSemi(expr, id)
+});
+
+impl_stable_hash_for!(struct hir::Arg {
+    pat,
+    id
+});
+
+impl_stable_hash_for!(struct hir::Body {
+    arguments,
+    value
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::BodyId {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        if hcx.hash_bodies() {
+            hcx.tcx().hir.body(*self).hash_stable(hcx, hasher);
+        }
+    }
+}
+
+impl_stable_hash_for!(struct hir::InlineAsmOutput {
+    constraint,
+    is_rw,
+    is_indirect
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::InlineAsm {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let hir::InlineAsm {
+            asm,
+            asm_str_style,
+            ref outputs,
+            ref inputs,
+            ref clobbers,
+            volatile,
+            alignstack,
+            dialect,
+            ctxt: _, // This is used for error reporting
+        } = *self;
+
+        asm.hash_stable(hcx, hasher);
+        asm_str_style.hash_stable(hcx, hasher);
+        outputs.hash_stable(hcx, hasher);
+        inputs.hash_stable(hcx, hasher);
+        clobbers.hash_stable(hcx, hasher);
+        volatile.hash_stable(hcx, hasher);
+        alignstack.hash_stable(hcx, hasher);
+        dialect.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(enum hir::def::CtorKind {
+    Fn,
+    Const,
+    Fictive
+});
+
+impl_stable_hash_for!(enum hir::def::Def {
+    Mod(def_id),
+    Struct(def_id),
+    Union(def_id),
+    Enum(def_id),
+    Variant(def_id),
+    Trait(def_id),
+    TyAlias(def_id),
+    AssociatedTy(def_id),
+    PrimTy(prim_ty),
+    TyParam(def_id),
+    SelfTy(trait_def_id, impl_def_id),
+    Fn(def_id),
+    Const(def_id),
+    Static(def_id, is_mutbl),
+    StructCtor(def_id, ctor_kind),
+    VariantCtor(def_id, ctor_kind),
+    Method(def_id),
+    AssociatedConst(def_id),
+    Local(def_id),
+    Upvar(def_id, index, expr_id),
+    Label(node_id),
+    Macro(def_id, macro_kind),
+    Err
+});
+
+impl_stable_hash_for!(enum hir::Mutability {
+    MutMutable,
+    MutImmutable
+});
+
+
+impl_stable_hash_for!(enum hir::Unsafety {
+    Unsafe,
+    Normal
+});
+
+
+impl_stable_hash_for!(enum hir::Constness {
+    Const,
+    NotConst
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for hir::def_id::DefIndex {
+
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        DefId::local(*self).hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct hir::def::Export {
+    name,
+    def,
+    span
+});
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
new file mode 100644
index 00000000000..401f7e1921a
--- /dev/null
+++ b/src/librustc/ich/impls_mir.rs
@@ -0,0 +1,407 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module contains `HashStable` implementations for various MIR data
+//! types in no particular order.
+
+use ich::StableHashingContext;
+use mir;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use std::mem;
+
+
+impl_stable_hash_for!(struct mir::SourceInfo { span, scope });
+impl_stable_hash_for!(enum mir::Mutability { Mut, Not });
+impl_stable_hash_for!(enum mir::BorrowKind { Shared, Unique, Mut });
+impl_stable_hash_for!(enum mir::LocalKind { Var, Temp, Arg, ReturnPointer });
+impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { mutability, ty, name, source_info });
+impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref });
+impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup });
+impl_stable_hash_for!(struct mir::Terminator<'tcx> { source_info, kind });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Local {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::BasicBlock {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Field {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::VisibilityScope {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Promoted {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use rustc_data_structures::indexed_vec::Idx;
+        self.index().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::TerminatorKind<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::TerminatorKind::Goto { ref target } => {
+                target.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::SwitchInt { ref discr,
+                                             switch_ty,
+                                             ref values,
+                                             ref targets } => {
+                discr.hash_stable(hcx, hasher);
+                switch_ty.hash_stable(hcx, hasher);
+                values.hash_stable(hcx, hasher);
+                targets.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::Resume |
+            mir::TerminatorKind::Return |
+            mir::TerminatorKind::Unreachable => {}
+            mir::TerminatorKind::Drop { ref location, target, unwind } => {
+                location.hash_stable(hcx, hasher);
+                target.hash_stable(hcx, hasher);
+                unwind.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::DropAndReplace { ref location,
+                                                  ref value,
+                                                  target,
+                                                  unwind, } => {
+                location.hash_stable(hcx, hasher);
+                value.hash_stable(hcx, hasher);
+                target.hash_stable(hcx, hasher);
+                unwind.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::Call { ref func,
+                                        ref args,
+                                        ref destination,
+                                        cleanup } => {
+                func.hash_stable(hcx, hasher);
+                args.hash_stable(hcx, hasher);
+                destination.hash_stable(hcx, hasher);
+                cleanup.hash_stable(hcx, hasher);
+            }
+            mir::TerminatorKind::Assert { ref cond,
+                                          expected,
+                                          ref msg,
+                                          target,
+                                          cleanup } => {
+                cond.hash_stable(hcx, hasher);
+                expected.hash_stable(hcx, hasher);
+                msg.hash_stable(hcx, hasher);
+                target.hash_stable(hcx, hasher);
+                cleanup.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::AssertMessage<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::AssertMessage::BoundsCheck { ref len, ref index } => {
+                len.hash_stable(hcx, hasher);
+                index.hash_stable(hcx, hasher);
+            }
+            mir::AssertMessage::Math(ref const_math_err) => {
+                const_math_err.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct mir::Statement<'tcx> { source_info, kind });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::StatementKind<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::StatementKind::Assign(ref lvalue, ref rvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+                rvalue.hash_stable(hcx, hasher);
+            }
+            mir::StatementKind::SetDiscriminant { ref lvalue, variant_index } => {
+                lvalue.hash_stable(hcx, hasher);
+                variant_index.hash_stable(hcx, hasher);
+            }
+            mir::StatementKind::StorageLive(ref lvalue) |
+            mir::StatementKind::StorageDead(ref lvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::StatementKind::Nop => {}
+            mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => {
+                asm.hash_stable(hcx, hasher);
+                outputs.hash_stable(hcx, hasher);
+                inputs.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Lvalue<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::Lvalue::Local(ref local) => {
+                local.hash_stable(hcx, hasher);
+            }
+            mir::Lvalue::Static(ref statik) => {
+                statik.hash_stable(hcx, hasher);
+            }
+            mir::Lvalue::Projection(ref lvalue_projection) => {
+                lvalue_projection.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx, B, V> HashStable<StableHashingContext<'a, 'tcx>> for mir::Projection<'tcx, B, V>
+    where B: HashStable<StableHashingContext<'a, 'tcx>>,
+          V: HashStable<StableHashingContext<'a, 'tcx>>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let mir::Projection {
+            ref base,
+            ref elem,
+        } = *self;
+
+        base.hash_stable(hcx, hasher);
+        elem.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx, V> HashStable<StableHashingContext<'a, 'tcx>> for mir::ProjectionElem<'tcx, V>
+    where V: HashStable<StableHashingContext<'a, 'tcx>>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::ProjectionElem::Deref => {}
+            mir::ProjectionElem::Field(field, ty) => {
+                field.hash_stable(hcx, hasher);
+                ty.hash_stable(hcx, hasher);
+            }
+            mir::ProjectionElem::Index(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            mir::ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
+                offset.hash_stable(hcx, hasher);
+                min_length.hash_stable(hcx, hasher);
+                from_end.hash_stable(hcx, hasher);
+            }
+            mir::ProjectionElem::Subslice { from, to } => {
+                from.hash_stable(hcx, hasher);
+                to.hash_stable(hcx, hasher);
+            }
+            mir::ProjectionElem::Downcast(adt_def, variant) => {
+                adt_def.hash_stable(hcx, hasher);
+                variant.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Operand<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::Operand::Consume(ref lvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::Operand::Constant(ref constant) => {
+                constant.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Rvalue<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            mir::Rvalue::Use(ref operand) => {
+                operand.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Repeat(ref operand, ref val) => {
+                operand.hash_stable(hcx, hasher);
+                val.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Ref(region, borrow_kind, ref lvalue) => {
+                region.hash_stable(hcx, hasher);
+                borrow_kind.hash_stable(hcx, hasher);
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Len(ref lvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Cast(cast_kind, ref operand, ty) => {
+                cast_kind.hash_stable(hcx, hasher);
+                operand.hash_stable(hcx, hasher);
+                ty.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::BinaryOp(op, ref operand1, ref operand2) |
+            mir::Rvalue::CheckedBinaryOp(op, ref operand1, ref operand2) => {
+                op.hash_stable(hcx, hasher);
+                operand1.hash_stable(hcx, hasher);
+                operand2.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::UnaryOp(op, ref operand) => {
+                op.hash_stable(hcx, hasher);
+                operand.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Discriminant(ref lvalue) => {
+                lvalue.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Box(ty) => {
+                ty.hash_stable(hcx, hasher);
+            }
+            mir::Rvalue::Aggregate(ref kind, ref operands) => {
+                kind.hash_stable(hcx, hasher);
+                operands.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum mir::CastKind {
+    Misc,
+    ReifyFnPointer,
+    ClosureFnPointer,
+    UnsafeFnPointer,
+    Unsize
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::AggregateKind<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::AggregateKind::Tuple => {}
+            mir::AggregateKind::Array(t) => {
+                t.hash_stable(hcx, hasher);
+            }
+            mir::AggregateKind::Adt(adt_def, idx, substs, active_field) => {
+                adt_def.hash_stable(hcx, hasher);
+                idx.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+                active_field.hash_stable(hcx, hasher);
+            }
+            mir::AggregateKind::Closure(def_id, ref substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum mir::BinOp {
+    Add,
+    Sub,
+    Mul,
+    Div,
+    Rem,
+    BitXor,
+    BitAnd,
+    BitOr,
+    Shl,
+    Shr,
+    Eq,
+    Lt,
+    Le,
+    Ne,
+    Ge,
+    Gt
+});
+
+impl_stable_hash_for!(enum mir::UnOp {
+    Not,
+    Neg
+});
+
+
+impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for mir::Literal<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            mir::Literal::Item { def_id, substs } => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+            mir::Literal::Value { ref value } => {
+                value.hash_stable(hcx, hasher);
+            }
+            mir::Literal::Promoted { index } => {
+                index.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct mir::Location { block, statement_index });
diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs
new file mode 100644
index 00000000000..26734500001
--- /dev/null
+++ b/src/librustc/ich/impls_syntax.rs
@@ -0,0 +1,301 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module contains `HashStable` implementations for various data types
+//! from libsyntax in no particular order.
+
+use ich::StableHashingContext;
+
+use std::hash as std_hash;
+use std::mem;
+
+use syntax::ast;
+use syntax::parse::token;
+use syntax::tokenstream;
+use syntax_pos::Span;
+
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use rustc_data_structures::accumulate_vec::AccumulateVec;
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::syntax::symbol::InternedString {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let s: &str = &**self;
+        s.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::Name {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        self.as_str().hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(enum ::syntax::ast::AsmDialect {
+    Att,
+    Intel
+});
+
+impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind {
+    Bang,
+    Attr,
+    Derive
+});
+
+
+impl_stable_hash_for!(enum ::syntax::abi::Abi {
+    Cdecl,
+    Stdcall,
+    Fastcall,
+    Vectorcall,
+    Aapcs,
+    Win64,
+    SysV64,
+    PtxKernel,
+    Msp430Interrupt,
+    X86Interrupt,
+    Rust,
+    C,
+    System,
+    RustIntrinsic,
+    RustCall,
+    PlatformIntrinsic,
+    Unadjusted
+});
+
+impl_stable_hash_for!(struct ::syntax::attr::Deprecation { since, note });
+impl_stable_hash_for!(struct ::syntax::attr::Stability { level, feature, rustc_depr });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::syntax::attr::StabilityLevel {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ::syntax::attr::StabilityLevel::Unstable { ref reason, ref issue } => {
+                reason.hash_stable(hcx, hasher);
+                issue.hash_stable(hcx, hasher);
+            }
+            ::syntax::attr::StabilityLevel::Stable { ref since } => {
+                since.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ::syntax::attr::RustcDeprecation { since, reason });
+
+
+impl_stable_hash_for!(enum ::syntax::attr::IntType {
+    SignedInt(int_ty),
+    UnsignedInt(uint_ty)
+});
+
+impl_stable_hash_for!(enum ::syntax::ast::LitIntType {
+    Signed(int_ty),
+    Unsigned(int_ty),
+    Unsuffixed
+});
+
+impl_stable_hash_for_spanned!(::syntax::ast::LitKind);
+impl_stable_hash_for!(enum ::syntax::ast::LitKind {
+    Str(value, style),
+    ByteStr(value),
+    Byte(value),
+    Char(value),
+    Int(value, lit_int_type),
+    Float(value, float_ty),
+    FloatUnsuffixed(value),
+    Bool(value)
+});
+
+impl_stable_hash_for!(enum ::syntax::ast::IntTy { Is, I8, I16, I32, I64, I128 });
+impl_stable_hash_for!(enum ::syntax::ast::UintTy { Us, U8, U16, U32, U64, U128 });
+impl_stable_hash_for!(enum ::syntax::ast::FloatTy { F32, F64 });
+impl_stable_hash_for!(enum ::syntax::ast::Unsafety { Unsafe, Normal });
+impl_stable_hash_for!(enum ::syntax::ast::Constness { Const, NotConst });
+impl_stable_hash_for!(enum ::syntax::ast::Defaultness { Default, Final });
+impl_stable_hash_for!(struct ::syntax::ast::Lifetime { id, span, name });
+impl_stable_hash_for!(enum ::syntax::ast::StrStyle { Cooked, Raw(pounds) });
+impl_stable_hash_for!(enum ::syntax::ast::AttrStyle { Outer, Inner });
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for [ast::Attribute] {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        // Some attributes are always ignored during hashing.
+        let filtered: AccumulateVec<[&ast::Attribute; 8]> = self
+            .iter()
+            .filter(|attr| {
+                !attr.is_sugared_doc &&
+                attr.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true)
+            })
+            .collect();
+
+        filtered.len().hash_stable(hcx, hasher);
+        for attr in filtered {
+            attr.hash_stable(hcx, hasher);
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ast::Attribute {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        // Make sure that these have been filtered out.
+        debug_assert!(self.name().map(|name| !hcx.is_ignored_attr(name)).unwrap_or(true));
+        debug_assert!(!self.is_sugared_doc);
+
+        let ast::Attribute {
+            id: _,
+            style,
+            ref path,
+            ref tokens,
+            is_sugared_doc: _,
+            span,
+        } = *self;
+
+        style.hash_stable(hcx, hasher);
+        path.segments.len().hash_stable(hcx, hasher);
+        for segment in &path.segments {
+            segment.identifier.name.hash_stable(hcx, hasher);
+        }
+        for tt in tokens.trees() {
+            tt.hash_stable(hcx, hasher);
+        }
+        span.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for tokenstream::TokenTree {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            tokenstream::TokenTree::Token(span, ref token) => {
+                span.hash_stable(hcx, hasher);
+                hash_token(token, hcx, hasher, span);
+            }
+            tokenstream::TokenTree::Delimited(span, ref delimited) => {
+                span.hash_stable(hcx, hasher);
+                std_hash::Hash::hash(&delimited.delim, hasher);
+                for sub_tt in delimited.stream().trees() {
+                    sub_tt.hash_stable(hcx, hasher);
+                }
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for tokenstream::TokenStream {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        for sub_tt in self.trees() {
+            sub_tt.hash_stable(hcx, hasher);
+        }
+    }
+}
+
+fn hash_token<'a, 'tcx, W: StableHasherResult>(token: &token::Token,
+                                               hcx: &mut StableHashingContext<'a, 'tcx>,
+                                               hasher: &mut StableHasher<W>,
+                                               error_reporting_span: Span) {
+    mem::discriminant(token).hash_stable(hcx, hasher);
+    match *token {
+        token::Token::Eq |
+        token::Token::Lt |
+        token::Token::Le |
+        token::Token::EqEq |
+        token::Token::Ne |
+        token::Token::Ge |
+        token::Token::Gt |
+        token::Token::AndAnd |
+        token::Token::OrOr |
+        token::Token::Not |
+        token::Token::Tilde |
+        token::Token::At |
+        token::Token::Dot |
+        token::Token::DotDot |
+        token::Token::DotDotDot |
+        token::Token::Comma |
+        token::Token::Semi |
+        token::Token::Colon |
+        token::Token::ModSep |
+        token::Token::RArrow |
+        token::Token::LArrow |
+        token::Token::FatArrow |
+        token::Token::Pound |
+        token::Token::Dollar |
+        token::Token::Question |
+        token::Token::Underscore |
+        token::Token::Whitespace |
+        token::Token::Comment |
+        token::Token::Eof => {}
+
+        token::Token::BinOp(bin_op_token) |
+        token::Token::BinOpEq(bin_op_token) => {
+            std_hash::Hash::hash(&bin_op_token, hasher);
+        }
+
+        token::Token::OpenDelim(delim_token) |
+        token::Token::CloseDelim(delim_token) => {
+            std_hash::Hash::hash(&delim_token, hasher);
+        }
+        token::Token::Literal(ref lit, ref opt_name) => {
+            mem::discriminant(lit).hash_stable(hcx, hasher);
+            match *lit {
+                token::Lit::Byte(val) |
+                token::Lit::Char(val) |
+                token::Lit::Integer(val) |
+                token::Lit::Float(val) |
+                token::Lit::Str_(val) |
+                token::Lit::ByteStr(val) => val.hash_stable(hcx, hasher),
+                token::Lit::StrRaw(val, n) |
+                token::Lit::ByteStrRaw(val, n) => {
+                    val.hash_stable(hcx, hasher);
+                    n.hash_stable(hcx, hasher);
+                }
+            };
+            opt_name.hash_stable(hcx, hasher);
+        }
+
+        token::Token::Ident(ident) |
+        token::Token::Lifetime(ident) |
+        token::Token::SubstNt(ident) => ident.name.hash_stable(hcx, hasher),
+
+        token::Token::Interpolated(ref non_terminal) => {
+            // FIXME(mw): This could be implemented properly. It's just a
+            //            lot of work, since we would need to hash the AST
+            //            in a stable way, in addition to the HIR.
+            //            Since this is hardly used anywhere, just emit a
+            //            warning for now.
+            if hcx.tcx().sess.opts.debugging_opts.incremental.is_some() {
+                let msg = format!("Quasi-quoting might make incremental \
+                                   compilation very inefficient: {:?}",
+                                  non_terminal);
+                hcx.tcx().sess.span_warn(error_reporting_span, &msg[..]);
+            }
+
+            std_hash::Hash::hash(non_terminal, hasher);
+        }
+
+        token::Token::DocComment(val) |
+        token::Token::Shebang(val) => val.hash_stable(hcx, hasher),
+    }
+}
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
new file mode 100644
index 00000000000..7b6f3af2a11
--- /dev/null
+++ b/src/librustc/ich/impls_ty.rs
@@ -0,0 +1,415 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This module contains `HashStable` implementations for various data types
+//! from rustc::ty in no particular order.
+
+use ich::StableHashingContext;
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use std::hash as std_hash;
+use std::mem;
+use ty;
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Ty<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let type_hash = hcx.tcx().type_id_hash(*self);
+        type_hash.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct ty::ItemSubsts<'tcx> { substs });
+
+impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> for ty::Slice<T>
+    where T: HashStable<StableHashingContext<'a, 'tcx>> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        (&**self).hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::subst::Kind<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        self.as_type().hash_stable(hcx, hasher);
+        self.as_region().hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Region {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::ReErased |
+            ty::ReStatic |
+            ty::ReEmpty => {
+                // No variant fields to hash for these ...
+            }
+            ty::ReLateBound(db, ty::BrAnon(i)) => {
+                db.depth.hash_stable(hcx, hasher);
+                i.hash_stable(hcx, hasher);
+            }
+            ty::ReEarlyBound(ty::EarlyBoundRegion { index, name }) => {
+                index.hash_stable(hcx, hasher);
+                name.hash_stable(hcx, hasher);
+            }
+            ty::ReLateBound(..) |
+            ty::ReFree(..) |
+            ty::ReScope(..) |
+            ty::ReVar(..) |
+            ty::ReSkolemized(..) => {
+                bug!("TypeIdHasher: unexpected region {:?}", *self)
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::AutoBorrow<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::adjustment::AutoBorrow::Ref(ref region, mutability) => {
+                region.hash_stable(hcx, hasher);
+                mutability.hash_stable(hcx, hasher);
+            }
+            ty::adjustment::AutoBorrow::RawPtr(mutability) => {
+                mutability.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::adjustment::Adjust<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::adjustment::Adjust::NeverToAny |
+            ty::adjustment::Adjust::ReifyFnPointer |
+            ty::adjustment::Adjust::UnsafeFnPointer |
+            ty::adjustment::Adjust::ClosureFnPointer |
+            ty::adjustment::Adjust::MutToConstPointer => {}
+            ty::adjustment::Adjust::DerefRef { autoderefs, ref autoref, unsize } => {
+                autoderefs.hash_stable(hcx, hasher);
+                autoref.hash_stable(hcx, hasher);
+                unsize.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ty::adjustment::Adjustment<'tcx> { kind, target });
+impl_stable_hash_for!(struct ty::MethodCall { expr_id, autoderef });
+impl_stable_hash_for!(struct ty::MethodCallee<'tcx> { def_id, ty, substs });
+impl_stable_hash_for!(struct ty::UpvarId { var_id, closure_expr_id });
+impl_stable_hash_for!(struct ty::UpvarBorrow<'tcx> { kind, region });
+
+impl_stable_hash_for!(enum ty::BorrowKind {
+    ImmBorrow,
+    UniqueImmBorrow,
+    MutBorrow
+});
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::UpvarCapture<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::UpvarCapture::ByValue => {}
+            ty::UpvarCapture::ByRef(ref up_var_borrow) => {
+                up_var_borrow.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ty::FnSig<'tcx> {
+    inputs_and_output,
+    variadic,
+    unsafety,
+    abi
+});
+
+impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>> for ty::Binder<T>
+    where T: HashStable<StableHashingContext<'a, 'tcx>> + ty::fold::TypeFoldable<'tcx>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        hcx.tcx().anonymize_late_bound_regions(self).0.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(enum ty::ClosureKind { Fn, FnMut, FnOnce });
+
+impl_stable_hash_for!(enum ty::Visibility {
+    Public,
+    Restricted(def_id),
+    Invisible
+});
+
+impl_stable_hash_for!(struct ty::TraitRef<'tcx> { def_id, substs });
+impl_stable_hash_for!(struct ty::TraitPredicate<'tcx> { trait_ref });
+impl_stable_hash_for!(tuple_struct ty::EquatePredicate<'tcx> { t1, t2 });
+
+impl<'a, 'tcx, A, B> HashStable<StableHashingContext<'a, 'tcx>> for ty::OutlivesPredicate<A, B>
+    where A: HashStable<StableHashingContext<'a, 'tcx>>,
+          B: HashStable<StableHashingContext<'a, 'tcx>>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::OutlivesPredicate(ref a, ref b) = *self;
+        a.hash_stable(hcx, hasher);
+        b.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct ty::ProjectionPredicate<'tcx> { projection_ty, ty });
+impl_stable_hash_for!(struct ty::ProjectionTy<'tcx> { trait_ref, item_name });
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Predicate<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            ty::Predicate::Trait(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::Equate(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::RegionOutlives(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::TypeOutlives(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::Projection(ref pred) => {
+                pred.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::WellFormed(ty) => {
+                ty.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::ObjectSafe(def_id) => {
+                def_id.hash_stable(hcx, hasher);
+            }
+            ty::Predicate::ClosureKind(def_id, closure_kind) => {
+                def_id.hash_stable(hcx, hasher);
+                closure_kind.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::AdtFlags {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        std_hash::Hash::hash(self, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct ty::VariantDef {
+    did,
+    name,
+    discr,
+    fields,
+    ctor_kind
+});
+
+impl_stable_hash_for!(enum ty::VariantDiscr {
+    Explicit(def_id),
+    Relative(distance)
+});
+
+impl_stable_hash_for!(struct ty::FieldDef {
+    did,
+    name,
+    vis
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>>
+for ::middle::const_val::ConstVal<'tcx> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use middle::const_val::ConstVal;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+
+        match *self {
+            ConstVal::Float(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Integral(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Str(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::ByteStr(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Bool(value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Function(def_id, substs) => {
+                def_id.hash_stable(hcx, hasher);
+                substs.hash_stable(hcx, hasher);
+            }
+            ConstVal::Struct(ref _name_value_map) => {
+                // BTreeMap<ast::Name, ConstVal<'tcx>>),
+                panic!("Ordering still unstable")
+            }
+            ConstVal::Tuple(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Array(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+            ConstVal::Repeat(ref value, times) => {
+                value.hash_stable(hcx, hasher);
+                times.hash_stable(hcx, hasher);
+            }
+            ConstVal::Char(value) => {
+                value.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs });
+
+
+impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> {
+    parent,
+    predicates
+});
+
+impl_stable_hash_for!(enum ty::Variance {
+    Covariant,
+    Invariant,
+    Contravariant,
+    Bivariant
+});
+
+impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized {
+    Struct(index)
+});
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::Generics {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::Generics {
+            parent,
+            parent_regions,
+            parent_types,
+            ref regions,
+            ref types,
+
+            // Reverse map to each `TypeParameterDef`'s `index` field, from
+            // `def_id.index` (`def_id.krate` is the same as the item's).
+            type_param_to_index: _, // Don't hash this
+            has_self,
+        } = *self;
+
+        parent.hash_stable(hcx, hasher);
+        parent_regions.hash_stable(hcx, hasher);
+        parent_types.hash_stable(hcx, hasher);
+        regions.hash_stable(hcx, hasher);
+        types.hash_stable(hcx, hasher);
+        has_self.hash_stable(hcx, hasher);
+    }
+}
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ty::RegionParameterDef {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::RegionParameterDef {
+            name,
+            def_id,
+            index,
+            issue_32330: _,
+            pure_wrt_drop
+        } = *self;
+
+        name.hash_stable(hcx, hasher);
+        def_id.hash_stable(hcx, hasher);
+        index.hash_stable(hcx, hasher);
+        pure_wrt_drop.hash_stable(hcx, hasher);
+    }
+}
+
+impl_stable_hash_for!(struct ty::TypeParameterDef {
+    name,
+    def_id,
+    index,
+    has_default,
+    object_lifetime_default,
+    pure_wrt_drop
+});
+
+
+impl<'a, 'tcx, T> HashStable<StableHashingContext<'a, 'tcx>>
+for ::middle::resolve_lifetime::Set1<T>
+    where T: HashStable<StableHashingContext<'a, 'tcx>>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        use middle::resolve_lifetime::Set1;
+
+        mem::discriminant(self).hash_stable(hcx, hasher);
+        match *self {
+            Set1::Empty |
+            Set1::Many => {
+                // Nothing to do.
+            }
+            Set1::One(ref value) => {
+                value.hash_stable(hcx, hasher);
+            }
+        }
+    }
+}
+
+impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region {
+    Static,
+    EarlyBound(index, decl),
+    LateBound(db_index, decl),
+    LateBoundAnon(db_index, anon_index),
+    Free(call_site_scope_data, decl)
+});
+
+impl_stable_hash_for!(struct ::middle::region::CallSiteScopeData {
+    fn_id,
+    body_id
+});
+
+impl_stable_hash_for!(struct ty::DebruijnIndex {
+    depth
+});
diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs
index 209953f3c68..f0601a0efab 100644
--- a/src/librustc/ich/mod.rs
+++ b/src/librustc/ich/mod.rs
@@ -8,13 +8,23 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+//! ICH - Incremental Compilation Hash
+
 pub use self::fingerprint::Fingerprint;
 pub use self::def_path_hash::DefPathHashes;
 pub use self::caching_codemap_view::CachingCodemapView;
+pub use self::hcx::{StableHashingContext, NodeIdHashingMode};
 
 mod fingerprint;
 mod def_path_hash;
 mod caching_codemap_view;
+mod hcx;
+
+mod impls_const_math;
+mod impls_hir;
+mod impls_mir;
+mod impls_ty;
+mod impls_syntax;
 
 pub const ATTR_DIRTY: &'static str = "rustc_dirty";
 pub const ATTR_CLEAN: &'static str = "rustc_clean";
@@ -22,6 +32,20 @@ pub const ATTR_DIRTY_METADATA: &'static str = "rustc_metadata_dirty";
 pub const ATTR_CLEAN_METADATA: &'static str = "rustc_metadata_clean";
 pub const ATTR_IF_THIS_CHANGED: &'static str = "rustc_if_this_changed";
 pub const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need";
+pub const ATTR_PARTITION_REUSED: &'static str = "rustc_partition_reused";
+pub const ATTR_PARTITION_TRANSLATED: &'static str = "rustc_partition_translated";
+
+
+pub const DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[
+    ATTR_IF_THIS_CHANGED,
+    ATTR_THEN_THIS_WOULD_NEED,
+    ATTR_DIRTY,
+    ATTR_CLEAN,
+    ATTR_DIRTY_METADATA,
+    ATTR_CLEAN_METADATA,
+    ATTR_PARTITION_REUSED,
+    ATTR_PARTITION_TRANSLATED,
+];
 
 pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
     "cfg",
@@ -30,5 +54,7 @@ pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[
     ATTR_DIRTY,
     ATTR_CLEAN,
     ATTR_DIRTY_METADATA,
-    ATTR_CLEAN_METADATA
+    ATTR_CLEAN_METADATA,
+    ATTR_PARTITION_REUSED,
+    ATTR_PARTITION_TRANSLATED,
 ];
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 294f80d7d23..3b002fd4dfc 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -41,6 +41,7 @@
 #![feature(specialization)]
 #![feature(staged_api)]
 #![feature(unboxed_closures)]
+#![feature(discriminant_value)]
 
 extern crate arena;
 extern crate core;
diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs
index 76dca1bb5b6..c18e585f795 100644
--- a/src/librustc/macros.rs
+++ b/src/librustc/macros.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// ignore-tidy-linelength
+
 macro_rules! enum_from_u32 {
     ($(#[$attr:meta])* pub enum $name:ident {
         $($variant:ident = $e:expr,)*
@@ -59,3 +61,80 @@ macro_rules! span_bug {
         $crate::session::span_bug_fmt(file!(), line!(), $span, format_args!($($message)*))
     })
 }
+
+#[macro_export]
+macro_rules! __impl_stable_hash_field {
+    (DECL IGNORED) => (_);
+    (DECL $name:ident) => (ref $name);
+    (USE IGNORED $ctx:expr, $hasher:expr) => ({});
+    (USE $name:ident, $ctx:expr, $hasher:expr) => ($name.hash_stable($ctx, $hasher));
+}
+
+#[macro_export]
+macro_rules! impl_stable_hash_for {
+    (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* }) => {
+        impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $enum_name {
+            #[inline]
+            fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
+                                                  __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>,
+                                                  __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
+                use $enum_name::*;
+                ::std::mem::discriminant(self).hash_stable(__ctx, __hasher);
+
+                match *self {
+                    $(
+                        $variant $( ( $( __impl_stable_hash_field!(DECL $arg) ),* ) )* => {
+                            $($( __impl_stable_hash_field!(USE $arg, __ctx, __hasher) );*)*
+                        }
+                    )*
+                }
+            }
+        }
+    };
+    (struct $struct_name:path { $($field:ident),* }) => {
+        impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name {
+            #[inline]
+            fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
+                                                  __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>,
+                                                  __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
+                let $struct_name {
+                    $(ref $field),*
+                } = *self;
+
+                $( $field.hash_stable(__ctx, __hasher));*
+            }
+        }
+    };
+    (tuple_struct $struct_name:path { $($field:ident),* }) => {
+        impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a, 'tcx>> for $struct_name {
+            #[inline]
+            fn hash_stable<W: ::rustc_data_structures::stable_hasher::StableHasherResult>(&self,
+                                                  __ctx: &mut $crate::ich::StableHashingContext<'a, 'tcx>,
+                                                  __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<W>) {
+                let $struct_name (
+                    $(ref $field),*
+                ) = *self;
+
+                $( $field.hash_stable(__ctx, __hasher));*
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! impl_stable_hash_for_spanned {
+    ($T:path) => (
+
+        impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for ::syntax::codemap::Spanned<$T>
+        {
+            #[inline]
+            fn hash_stable<W: StableHasherResult>(&self,
+                                                  hcx: &mut StableHashingContext<'a, 'tcx>,
+                                                  hasher: &mut StableHasher<W>) {
+                self.node.hash_stable(hcx, hasher);
+                self.span.hash_stable(hcx, hasher);
+            }
+        }
+    );
+}
+
diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs
index 3b52e85e08e..7d3c17a0489 100644
--- a/src/librustc/middle/mem_categorization.rs
+++ b/src/librustc/middle/mem_categorization.rs
@@ -202,11 +202,14 @@ pub enum ImmutabilityBlame<'tcx> {
 }
 
 impl<'tcx> cmt_<'tcx> {
-    fn resolve_field(&self, field_name: FieldName) -> (&'tcx ty::AdtDef, &'tcx ty::FieldDef)
+    fn resolve_field(&self, field_name: FieldName) -> Option<(&'tcx ty::AdtDef, &'tcx ty::FieldDef)>
     {
-        let adt_def = self.ty.ty_adt_def().unwrap_or_else(|| {
-            bug!("interior cmt {:?} is not an ADT", self)
-        });
+        let adt_def = match self.ty.sty {
+            ty::TyAdt(def, _) => def,
+            ty::TyTuple(..) => return None,
+            // closures get `Categorization::Upvar` rather than `Categorization::Interior`
+            _ =>  bug!("interior cmt {:?} is not an ADT", self)
+        };
         let variant_def = match self.cat {
             Categorization::Downcast(_, variant_did) => {
                 adt_def.variant_with_id(variant_did)
@@ -220,7 +223,7 @@ impl<'tcx> cmt_<'tcx> {
             NamedField(name) => variant_def.field_named(name),
             PositionalField(idx) => &variant_def.fields[idx]
         };
-        (adt_def, field_def)
+        Some((adt_def, field_def))
     }
 
     pub fn immutability_blame(&self) -> Option<ImmutabilityBlame<'tcx>> {
@@ -232,8 +235,9 @@ impl<'tcx> cmt_<'tcx> {
                     Categorization::Local(node_id) =>
                         Some(ImmutabilityBlame::LocalDeref(node_id)),
                     Categorization::Interior(ref base_cmt, InteriorField(field_name)) => {
-                        let (adt_def, field_def) = base_cmt.resolve_field(field_name);
-                        Some(ImmutabilityBlame::AdtFieldDeref(adt_def, field_def))
+                        base_cmt.resolve_field(field_name).map(|(adt_def, field_def)| {
+                            ImmutabilityBlame::AdtFieldDeref(adt_def, field_def)
+                        })
                     }
                     Categorization::Upvar(Upvar { id, .. }) => {
                         if let NoteClosureEnv(..) = self.note {
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index b0e39442af9..e5dd48534a6 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -15,11 +15,11 @@
 // makes all other generics or inline functions that it references
 // reachable as well.
 
-use dep_graph::DepNode;
 use hir::map as hir_map;
 use hir::def::Def;
-use hir::def_id::DefId;
+use hir::def_id::{DefId, CrateNum};
 use ty::{self, TyCtxt};
+use ty::maps::Providers;
 use middle::privacy;
 use session::config;
 use util::nodemap::{NodeSet, FxHashSet};
@@ -362,7 +362,11 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a,
 }
 
 pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet {
-    let _task = tcx.dep_graph.in_task(DepNode::Reachability);
+    ty::queries::reachable_set::get(tcx, DUMMY_SP, LOCAL_CRATE)
+}
+
+fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> NodeSet {
+    debug_assert!(crate_num == LOCAL_CRATE);
 
     let access_levels = &ty::queries::privacy_access_levels::get(tcx, DUMMY_SP, LOCAL_CRATE);
 
@@ -408,3 +412,10 @@ pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> NodeSet {
     // Return the set of reachable symbols.
     reachable_context.reachable_symbols
 }
+
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        reachable_set,
+        ..*providers
+    };
+}
diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs
index bc9bbebb179..799686ceca4 100644
--- a/src/librustc/mir/cache.rs
+++ b/src/librustc/mir/cache.rs
@@ -10,7 +10,9 @@
 
 use std::cell::{Ref, RefCell};
 use rustc_data_structures::indexed_vec::IndexVec;
-
+use rustc_data_structures::stable_hasher::{HashStable, StableHasher,
+                                           StableHasherResult};
+use ich::StableHashingContext;
 use mir::{Mir, BasicBlock};
 
 use rustc_serialize as serialize;
@@ -33,6 +35,13 @@ impl serialize::Decodable for Cache {
     }
 }
 
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for Cache {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut StableHashingContext<'a, 'tcx>,
+                                          _: &mut StableHasher<W>) {
+        // do nothing
+    }
+}
 
 impl Cache {
     pub fn new() -> Self {
diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs
index 01dc7f51e29..aea4684e526 100644
--- a/src/librustc/mir/mod.rs
+++ b/src/librustc/mir/mod.rs
@@ -243,6 +243,19 @@ impl<'tcx> Mir<'tcx> {
     }
 }
 
+impl_stable_hash_for!(struct Mir<'tcx> {
+    basic_blocks,
+    visibility_scopes,
+    promoted,
+    return_ty,
+    local_decls,
+    arg_count,
+    upvar_decls,
+    spread_arg,
+    span,
+    cache
+});
+
 impl<'tcx> Index<BasicBlock> for Mir<'tcx> {
     type Output = BasicBlockData<'tcx>;
 
@@ -830,6 +843,11 @@ pub struct Static<'tcx> {
     pub ty: Ty<'tcx>,
 }
 
+impl_stable_hash_for!(struct Static<'tcx> {
+    def_id,
+    ty
+});
+
 /// The `Projection` data structure defines things of the form `B.x`
 /// or `*B` or `B[index]`. Note that it is parameterized because it is
 /// shared between `Constant` and `Lvalue`. See the aliases
diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs
index 123db6e8947..571ef30b6b9 100644
--- a/src/librustc/ty/layout.rs
+++ b/src/librustc/ty/layout.rs
@@ -267,7 +267,7 @@ impl Size {
 
 /// Alignment of a type in bytes, both ABI-mandated and preferred.
 /// Since alignments are always powers of 2, we can pack both in one byte,
-/// giving each a nibble (4 bits) for a maximum alignment of 2^15 = 32768.
+/// giving each a nibble (4 bits) for a maximum alignment of 2<sup>15</sup> = 32768.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 pub struct Align {
     raw: u8
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 4a183191cef..823bdc9e092 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -15,6 +15,7 @@ use middle::privacy::AccessLevels;
 use mir;
 use session::CompileResult;
 use ty::{self, CrateInherentImpls, Ty, TyCtxt};
+use util::nodemap::NodeSet;
 
 use rustc_data_structures::indexed_vec::IndexVec;
 use std::cell::{RefCell, RefMut};
@@ -209,6 +210,11 @@ impl<'tcx> QueryDescription for queries::typeck_item_bodies<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::reachable_set<'tcx> {
+    fn describe(_: TyCtxt, _: CrateNum) -> String {
+        format!("reachability")
+    }
+}
 
 macro_rules! define_maps {
     (<$tcx:tt>
@@ -440,6 +446,8 @@ define_maps! { <'tcx>
     /// Performs the privacy check and computes "access levels".
     pub privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc<AccessLevels>,
 
+    pub reachable_set: reachability_dep_node(CrateNum) -> NodeSet,
+
     pub mir_shims: mir_shim(ty::InstanceDef<'tcx>) -> &'tcx RefCell<mir::Mir<'tcx>>
 }
 
@@ -451,6 +459,10 @@ fn crate_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> {
     DepNode::Coherence
 }
 
+fn reachability_dep_node(_: CrateNum) -> DepNode<DefId> {
+    DepNode::Reachability
+}
+
 fn mir_shim(instance: ty::InstanceDef) -> DepNode<DefId> {
     instance.dep_node()
 }
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 6a4e7db21dd..3c529a69820 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -19,6 +19,7 @@ use dep_graph::{self, DepNode};
 use hir::{map as hir_map, FreevarMap, TraitMap};
 use hir::def::{Def, CtorKind, ExportMap};
 use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use ich::StableHashingContext;
 use middle::const_val::ConstVal;
 use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
 use middle::privacy::AccessLevels;
@@ -50,6 +51,8 @@ use syntax_pos::{DUMMY_SP, Span};
 use rustc_const_math::ConstInt;
 
 use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
+use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
+                                           HashStable};
 
 use hir;
 use hir::itemlikevisit::ItemLikeVisitor;
@@ -1379,6 +1382,25 @@ impl<'tcx> serialize::UseSpecializedEncodable for &'tcx AdtDef {
 
 impl<'tcx> serialize::UseSpecializedDecodable for &'tcx AdtDef {}
 
+
+impl<'a, 'tcx> HashStable<StableHashingContext<'a, 'tcx>> for AdtDef {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut StableHashingContext<'a, 'tcx>,
+                                          hasher: &mut StableHasher<W>) {
+        let ty::AdtDef {
+            did,
+            ref variants,
+            ref flags,
+            ref repr,
+        } = *self;
+
+        did.hash_stable(hcx, hasher);
+        variants.hash_stable(hcx, hasher);
+        flags.hash_stable(hcx, hasher);
+        repr.hash_stable(hcx, hasher);
+    }
+}
+
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum AdtKind { Struct, Union, Enum }
 
@@ -1391,6 +1413,13 @@ pub struct ReprOptions {
     pub int: Option<attr::IntType>,
 }
 
+impl_stable_hash_for!(struct ReprOptions {
+    c,
+    packed,
+    simd,
+    int
+});
+
 impl ReprOptions {
     pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
         let mut ret = ReprOptions::default();
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index c5d577ce571..54f5cff16ed 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -490,6 +490,17 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
               _ => span_bug!(e.span, "typeck error"),
              })
           }
+          (Char(a), Char(b)) => {
+            Bool(match op.node {
+              hir::BiEq => a == b,
+              hir::BiNe => a != b,
+              hir::BiLt => a < b,
+              hir::BiLe => a <= b,
+              hir::BiGe => a >= b,
+              hir::BiGt => a > b,
+              _ => span_bug!(e.span, "typeck error"),
+             })
+          }
 
           _ => signal!(e, MiscBinaryOp),
         }
diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs
index 9ccd95dd8d8..c1735b4a4ec 100644
--- a/src/librustc_data_structures/lib.rs
+++ b/src/librustc_data_structures/lib.rs
@@ -37,6 +37,8 @@
 #![feature(unsize)]
 #![feature(i128_type)]
 #![feature(conservative_impl_trait)]
+#![feature(discriminant_value)]
+#![feature(specialization)]
 
 #![cfg_attr(unix, feature(libc))]
 #![cfg_attr(test, feature(test))]
diff --git a/src/librustc_data_structures/stable_hasher.rs b/src/librustc_data_structures/stable_hasher.rs
index 231c01c9ab7..dc412a0763e 100644
--- a/src/librustc_data_structures/stable_hasher.rs
+++ b/src/librustc_data_structures/stable_hasher.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use std::hash::Hasher;
+use std::hash::{Hash, Hasher};
 use std::marker::PhantomData;
 use std::mem;
 use blake2b::Blake2bHasher;
@@ -174,3 +174,193 @@ impl<W> Hasher for StableHasher<W> {
         self.write_ileb128(i as i64);
     }
 }
+
+
+/// Something that implements `HashStable<CTX>` can be hashed in a way that is
+/// stable across multiple compiliation sessions.
+pub trait HashStable<CTX> {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut CTX,
+                                          hasher: &mut StableHasher<W>);
+}
+
+// Implement HashStable by just calling `Hash::hash()`. This works fine for
+// self-contained values that don't depend on the hashing context `CTX`.
+macro_rules! impl_stable_hash_via_hash {
+    ($t:ty) => (
+        impl<CTX> HashStable<CTX> for $t {
+            #[inline]
+            fn hash_stable<W: StableHasherResult>(&self,
+                                                  _: &mut CTX,
+                                                  hasher: &mut StableHasher<W>) {
+                ::std::hash::Hash::hash(self, hasher);
+            }
+        }
+    );
+}
+
+impl_stable_hash_via_hash!(i8);
+impl_stable_hash_via_hash!(i16);
+impl_stable_hash_via_hash!(i32);
+impl_stable_hash_via_hash!(i64);
+impl_stable_hash_via_hash!(isize);
+
+impl_stable_hash_via_hash!(u8);
+impl_stable_hash_via_hash!(u16);
+impl_stable_hash_via_hash!(u32);
+impl_stable_hash_via_hash!(u64);
+impl_stable_hash_via_hash!(usize);
+
+impl_stable_hash_via_hash!(u128);
+impl_stable_hash_via_hash!(i128);
+
+impl_stable_hash_via_hash!(char);
+impl_stable_hash_via_hash!(());
+
+impl<CTX> HashStable<CTX> for f32 {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        let val: u32 = unsafe {
+            ::std::mem::transmute(*self)
+        };
+        val.hash_stable(ctx, hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for f64 {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        let val: u64 = unsafe {
+            ::std::mem::transmute(*self)
+        };
+        val.hash_stable(ctx, hasher);
+    }
+}
+
+impl<T1: HashStable<CTX>, T2: HashStable<CTX>, CTX> HashStable<CTX> for (T1, T2) {
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.0.hash_stable(ctx, hasher);
+        self.1.hash_stable(ctx, hasher);
+    }
+}
+
+impl<T: HashStable<CTX>, CTX> HashStable<CTX> for [T] {
+    default fn hash_stable<W: StableHasherResult>(&self,
+                                                  ctx: &mut CTX,
+                                                  hasher: &mut StableHasher<W>) {
+        self.len().hash_stable(ctx, hasher);
+        for item in self {
+            item.hash_stable(ctx, hasher);
+        }
+    }
+}
+
+impl<T: HashStable<CTX>, CTX> HashStable<CTX> for Vec<T> {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (&self[..]).hash_stable(ctx, hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for str {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.len().hash(hasher);
+        self.as_bytes().hash(hasher);
+    }
+}
+
+impl<CTX> HashStable<CTX> for bool {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (if *self { 1u8 } else { 0u8 }).hash_stable(ctx, hasher);
+    }
+}
+
+
+impl<T, CTX> HashStable<CTX> for Option<T>
+    where T: HashStable<CTX>
+{
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        if let Some(ref value) = *self {
+            1u8.hash_stable(ctx, hasher);
+            value.hash_stable(ctx, hasher);
+        } else {
+            0u8.hash_stable(ctx, hasher);
+        }
+    }
+}
+
+impl<'a, T, CTX> HashStable<CTX> for &'a T
+    where T: HashStable<CTX>
+{
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (**self).hash_stable(ctx, hasher);
+    }
+}
+
+impl<T, CTX> HashStable<CTX> for ::std::mem::Discriminant<T> {
+    #[inline]
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          _: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        ::std::hash::Hash::hash(self, hasher);
+    }
+}
+
+impl<K, V, CTX> HashStable<CTX> for ::std::collections::BTreeMap<K, V>
+    where K: Ord + HashStable<CTX>,
+          V: HashStable<CTX>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.len().hash_stable(ctx, hasher);
+        for (k, v) in self {
+            k.hash_stable(ctx, hasher);
+            v.hash_stable(ctx, hasher);
+        }
+    }
+}
+
+impl<T, CTX> HashStable<CTX> for ::std::collections::BTreeSet<T>
+    where T: Ord + HashStable<CTX>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.len().hash_stable(ctx, hasher);
+        for v in self {
+            v.hash_stable(ctx, hasher);
+        }
+    }
+}
+
+impl<I: ::indexed_vec::Idx, T, CTX> HashStable<CTX> for ::indexed_vec::IndexVec<I, T>
+    where T: HashStable<CTX>,
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          ctx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        self.len().hash_stable(ctx, hasher);
+        for v in &self.raw {
+            v.hash_stable(ctx, hasher);
+        }
+    }
+}
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 977382b33ad..0fb386341a9 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -889,6 +889,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
     rustc_privacy::provide(&mut local_providers);
     typeck::provide(&mut local_providers);
     ty::provide(&mut local_providers);
+    reachable::provide(&mut local_providers);
 
     let mut extern_providers = ty::maps::Providers::default();
     cstore::provide(&mut extern_providers);
@@ -1358,10 +1359,9 @@ pub fn build_output_filenames(input: &Input,
                                            .values()
                                            .filter(|a| a.is_none())
                                            .count();
-            let ofile = if unnamed_output_types > 1 &&
-                            sess.opts.output_types.contains_key(&OutputType::Exe) {
-                sess.warn("ignoring specified output filename for 'link' output because multiple \
-                           outputs were requested");
+            let ofile = if unnamed_output_types > 1 {
+                sess.warn("due to multiple output types requested, the explicitly specified \
+                           output file name will be adapted for each output type");
                 None
             } else {
                 Some(out_file.clone())
diff --git a/src/librustc_incremental/calculate_svh/mod.rs b/src/librustc_incremental/calculate_svh/mod.rs
index c9496a4deb8..c80a5a16277 100644
--- a/src/librustc_incremental/calculate_svh/mod.rs
+++ b/src/librustc_incremental/calculate_svh/mod.rs
@@ -27,24 +27,17 @@
 //! at the end of compilation would be different from those computed
 //! at the beginning.
 
-use syntax::ast;
 use std::cell::RefCell;
 use std::hash::Hash;
 use rustc::dep_graph::DepNode;
 use rustc::hir;
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
-use rustc::hir::intravisit as visit;
-use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
-use rustc::ich::{Fingerprint, DefPathHashes, CachingCodemapView};
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::ich::{Fingerprint, StableHashingContext};
 use rustc::ty::TyCtxt;
-use rustc_data_structures::stable_hasher::StableHasher;
+use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc::util::common::record_time;
-use rustc::session::config::DebugInfoLevel::NoDebugInfo;
-
-use self::svh_visitor::StrictVersionHashVisitor;
-
-mod svh_visitor;
 
 pub type IchHasher = StableHasher<Fingerprint>;
 
@@ -94,91 +87,42 @@ impl<'a> ::std::ops::Index<&'a DepNode<DefId>> for IncrementalHashesMap {
     }
 }
 
-
-pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                                    -> IncrementalHashesMap {
-    let _ignore = tcx.dep_graph.in_ignore();
-    let krate = tcx.hir.krate();
-    let hash_spans = tcx.sess.opts.debuginfo != NoDebugInfo;
-    let mut visitor = HashItemsVisitor {
-        tcx: tcx,
-        hashes: IncrementalHashesMap::new(),
-        def_path_hashes: DefPathHashes::new(tcx),
-        codemap: CachingCodemapView::new(tcx),
-        hash_spans: hash_spans,
-    };
-    record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
-        visitor.calculate_def_id(DefId::local(CRATE_DEF_INDEX), |v| {
-            v.hash_crate_root_module(krate);
-        });
-        krate.visit_all_item_likes(&mut visitor.as_deep_visitor());
-
-        for macro_def in krate.exported_macros.iter() {
-            visitor.calculate_node_id(macro_def.id,
-                                      |v| v.visit_macro_def(macro_def));
-        }
-    });
-
-    tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
-
-    record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
-    visitor.hashes
-}
-
-struct HashItemsVisitor<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    def_path_hashes: DefPathHashes<'a, 'tcx>,
-    codemap: CachingCodemapView<'tcx>,
+struct ComputeItemHashesVisitor<'a, 'tcx: 'a> {
+    hcx: StableHashingContext<'a, 'tcx>,
     hashes: IncrementalHashesMap,
-    hash_spans: bool,
 }
 
-impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
-    fn calculate_node_id<W>(&mut self, id: ast::NodeId, walk_op: W)
-        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
-    {
-        let def_id = self.tcx.hir.local_def_id(id);
-        self.calculate_def_id(def_id, walk_op)
-    }
-
-    fn calculate_def_id<W>(&mut self, def_id: DefId, mut walk_op: W)
-        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
+impl<'a, 'tcx: 'a> ComputeItemHashesVisitor<'a, 'tcx> {
+    fn compute_and_store_ich_for_item_like<T>(&mut self,
+                                              dep_node: DepNode<DefId>,
+                                              hash_bodies: bool,
+                                              item_like: T)
+        where T: HashStable<StableHashingContext<'a, 'tcx>>
     {
-        assert!(def_id.is_local());
-        debug!("HashItemsVisitor::calculate(def_id={:?})", def_id);
-        self.calculate_def_hash(DepNode::Hir(def_id), false, &mut walk_op);
-        self.calculate_def_hash(DepNode::HirBody(def_id), true, &mut walk_op);
-    }
+        let mut hasher = IchHasher::new();
+        self.hcx.while_hashing_hir_bodies(hash_bodies, |hcx| {
+            item_like.hash_stable(hcx, &mut hasher);
+        });
 
-    fn calculate_def_hash<W>(&mut self,
-                             dep_node: DepNode<DefId>,
-                             hash_bodies: bool,
-                             walk_op: &mut W)
-        where W: for<'v> FnMut(&mut StrictVersionHashVisitor<'v, 'a, 'tcx>)
-    {
-        let mut state = IchHasher::new();
-        walk_op(&mut StrictVersionHashVisitor::new(&mut state,
-                                                   self.tcx,
-                                                   &mut self.def_path_hashes,
-                                                   &mut self.codemap,
-                                                   self.hash_spans,
-                                                   hash_bodies));
-        let bytes_hashed = state.bytes_hashed();
-        let item_hash = state.finish();
+        let bytes_hashed = hasher.bytes_hashed();
+        let item_hash = hasher.finish();
         debug!("calculate_def_hash: dep_node={:?} hash={:?}", dep_node, item_hash);
         self.hashes.insert(dep_node, item_hash);
 
-        let bytes_hashed = self.tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
+        let tcx = self.hcx.tcx();
+        let bytes_hashed =
+            tcx.sess.perf_stats.incr_comp_bytes_hashed.get() +
             bytes_hashed;
-        self.tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
+        tcx.sess.perf_stats.incr_comp_bytes_hashed.set(bytes_hashed);
     }
 
     fn compute_crate_hash(&mut self) {
-        let krate = self.tcx.hir.krate();
+        let tcx = self.hcx.tcx();
+        let krate = tcx.hir.krate();
 
         let mut crate_state = IchHasher::new();
 
-        let crate_disambiguator = self.tcx.sess.local_crate_disambiguator();
+        let crate_disambiguator = tcx.sess.local_crate_disambiguator();
         "crate_disambiguator".hash(&mut crate_state);
         crate_disambiguator.as_str().len().hash(&mut crate_state);
         crate_disambiguator.as_str().hash(&mut crate_state);
@@ -186,7 +130,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
         // add each item (in some deterministic order) to the overall
         // crate hash.
         {
-            let def_path_hashes = &mut self.def_path_hashes;
+            let hcx = &mut self.hcx;
             let mut item_hashes: Vec<_> =
                 self.hashes.iter()
                            .map(|(item_dep_node, &item_hash)| {
@@ -194,7 +138,7 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
                                // DepNode<u64> where the u64 is the
                                // hash of the def-id's def-path:
                                let item_dep_node =
-                                   item_dep_node.map_def(|&did| Some(def_path_hashes.hash(did)))
+                                   item_dep_node.map_def(|&did| Some(hcx.def_path_hash(did)))
                                                 .unwrap();
                                (item_dep_node, item_hash)
                            })
@@ -203,40 +147,85 @@ impl<'a, 'tcx> HashItemsVisitor<'a, 'tcx> {
             item_hashes.hash(&mut crate_state);
         }
 
-        {
-            let mut visitor = StrictVersionHashVisitor::new(&mut crate_state,
-                                                            self.tcx,
-                                                            &mut self.def_path_hashes,
-                                                            &mut self.codemap,
-                                                            self.hash_spans,
-                                                            false);
-            visitor.hash_attributes(&krate.attrs);
-        }
+        krate.attrs.hash_stable(&mut self.hcx, &mut crate_state);
 
         let crate_hash = crate_state.finish();
         self.hashes.insert(DepNode::Krate, crate_hash);
         debug!("calculate_crate_hash: crate_hash={:?}", crate_hash);
     }
-}
 
-
-impl<'a, 'tcx> Visitor<'tcx> for HashItemsVisitor<'a, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
-        NestedVisitorMap::None
+    fn hash_crate_root_module(&mut self, krate: &'tcx hir::Crate) {
+        let hir::Crate {
+            ref module,
+            // Crate attributes are not copied over to the root `Mod`, so hash
+            // them explicitly here.
+            ref attrs,
+            span,
+
+            // These fields are handled separately:
+            exported_macros: _,
+            items: _,
+            trait_items: _,
+            impl_items: _,
+            bodies: _,
+            trait_impls: _,
+            trait_default_impl: _,
+            body_ids: _,
+        } = *krate;
+
+        let def_id = DefId::local(CRATE_DEF_INDEX);
+        self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id),
+                                                 false,
+                                                 (module, (span, attrs)));
+        self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id),
+                                                 true,
+                                                 (module, (span, attrs)));
     }
+}
 
+impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for ComputeItemHashesVisitor<'a, 'tcx> {
     fn visit_item(&mut self, item: &'tcx hir::Item) {
-        self.calculate_node_id(item.id, |v| v.visit_item(item));
-        visit::walk_item(self, item);
+        let def_id = self.hcx.tcx().hir.local_def_id(item.id);
+        self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
+        self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
     }
 
-    fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
-        self.calculate_node_id(trait_item.id, |v| v.visit_trait_item(trait_item));
-        visit::walk_trait_item(self, trait_item);
+    fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
+        let def_id = self.hcx.tcx().hir.local_def_id(item.id);
+        self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
+        self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
     }
 
-    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
-        self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item));
-        visit::walk_impl_item(self, impl_item);
+    fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
+        let def_id = self.hcx.tcx().hir.local_def_id(item.id);
+        self.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, item);
+        self.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, item);
     }
 }
+
+pub fn compute_incremental_hashes_map<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                                                    -> IncrementalHashesMap {
+    let _ignore = tcx.dep_graph.in_ignore();
+    let krate = tcx.hir.krate();
+
+    let mut visitor = ComputeItemHashesVisitor {
+        hcx: StableHashingContext::new(tcx),
+        hashes: IncrementalHashesMap::new(),
+    };
+
+    record_time(&tcx.sess.perf_stats.incr_comp_hashes_time, || {
+        visitor.hash_crate_root_module(krate);
+        krate.visit_all_item_likes(&mut visitor);
+
+        for macro_def in krate.exported_macros.iter() {
+            let def_id = tcx.hir.local_def_id(macro_def.id);
+            visitor.compute_and_store_ich_for_item_like(DepNode::Hir(def_id), false, macro_def);
+            visitor.compute_and_store_ich_for_item_like(DepNode::HirBody(def_id), true, macro_def);
+        }
+    });
+
+    tcx.sess.perf_stats.incr_comp_hashes_count.set(visitor.hashes.len() as u64);
+
+    record_time(&tcx.sess.perf_stats.svh_time, || visitor.compute_crate_hash());
+    visitor.hashes
+}
diff --git a/src/librustc_incremental/calculate_svh/svh_visitor.rs b/src/librustc_incremental/calculate_svh/svh_visitor.rs
deleted file mode 100644
index 4700b77be07..00000000000
--- a/src/librustc_incremental/calculate_svh/svh_visitor.rs
+++ /dev/null
@@ -1,1113 +0,0 @@
-// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-use self::SawExprComponent::*;
-use self::SawAbiComponent::*;
-use self::SawItemComponent::*;
-use self::SawPatComponent::*;
-use self::SawTyComponent::*;
-use self::SawTraitOrImplItemComponent::*;
-use syntax::abi::Abi;
-use syntax::ast::{self, Name, NodeId};
-use syntax::attr;
-use syntax::ext::hygiene::SyntaxContext;
-use syntax::parse::token;
-use syntax::symbol::InternedString;
-use syntax_pos::{Span, BytePos};
-use syntax::tokenstream;
-use rustc::hir;
-use rustc::hir::*;
-use rustc::hir::def::Def;
-use rustc::hir::def_id::DefId;
-use rustc::hir::intravisit::{self as visit, Visitor};
-use rustc::ich::{DefPathHashes, CachingCodemapView, IGNORED_ATTRIBUTES};
-use rustc::ty::TyCtxt;
-use std::hash::{Hash, Hasher};
-
-use super::IchHasher;
-
-pub struct StrictVersionHashVisitor<'a, 'hash: 'a, 'tcx: 'hash> {
-    pub tcx: TyCtxt<'hash, 'tcx, 'tcx>,
-    pub st: &'a mut IchHasher,
-    // collect a deterministic hash of def-ids that we have seen
-    def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
-    hash_spans: bool,
-    codemap: &'a mut CachingCodemapView<'tcx>,
-    overflow_checks_enabled: bool,
-    hash_bodies: bool,
-}
-
-impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
-    pub fn new(st: &'a mut IchHasher,
-               tcx: TyCtxt<'hash, 'tcx, 'tcx>,
-               def_path_hashes: &'a mut DefPathHashes<'hash, 'tcx>,
-               codemap: &'a mut CachingCodemapView<'tcx>,
-               hash_spans: bool,
-               hash_bodies: bool)
-               -> Self {
-        let check_overflow = tcx.sess.overflow_checks();
-
-        StrictVersionHashVisitor {
-            st: st,
-            tcx: tcx,
-            def_path_hashes: def_path_hashes,
-            hash_spans: hash_spans,
-            codemap: codemap,
-            overflow_checks_enabled: check_overflow,
-            hash_bodies: hash_bodies,
-        }
-    }
-
-    fn compute_def_id_hash(&mut self, def_id: DefId) -> u64 {
-        self.def_path_hashes.hash(def_id)
-    }
-
-    // Hash a span in a stable way. We can't directly hash the span's BytePos
-    // fields (that would be similar to hashing pointers, since those are just
-    // offsets into the CodeMap). Instead, we hash the (file name, line, column)
-    // triple, which stays the same even if the containing FileMap has moved
-    // within the CodeMap.
-    // Also note that we are hashing byte offsets for the column, not unicode
-    // codepoint offsets. For the purpose of the hash that's sufficient.
-    // Also, hashing filenames is expensive so we avoid doing it twice when the
-    // span starts and ends in the same file, which is almost always the case.
-    fn hash_span(&mut self, span: Span) {
-        debug!("hash_span: st={:?}", self.st);
-
-        // If this is not an empty or invalid span, we want to hash the last
-        // position that belongs to it, as opposed to hashing the first
-        // position past it.
-        let span_hi = if span.hi > span.lo {
-            // We might end up in the middle of a multibyte character here,
-            // but that's OK, since we are not trying to decode anything at
-            // this position.
-            span.hi - BytePos(1)
-        } else {
-            span.hi
-        };
-
-        let expn_kind = if span.ctxt == SyntaxContext::empty() {
-            SawSpanExpnKind::NoExpansion
-        } else {
-            SawSpanExpnKind::SomeExpansion
-        };
-
-        let loc1 = self.codemap.byte_pos_to_line_and_col(span.lo);
-        let loc1 = loc1.as_ref()
-                       .map(|&(ref fm, line, col)| (&fm.name[..], line, col))
-                       .unwrap_or(("???", 0, BytePos(0)));
-
-        let loc2 = self.codemap.byte_pos_to_line_and_col(span_hi);
-        let loc2 = loc2.as_ref()
-                       .map(|&(ref fm, line, col)| (&fm.name[..], line, col))
-                       .unwrap_or(("???", 0, BytePos(0)));
-
-        let saw = if loc1.0 == loc2.0 {
-            SawSpan(loc1.0,
-                    loc1.1, loc1.2,
-                    loc2.1, loc2.2,
-                    expn_kind)
-        } else {
-            SawSpanTwoFiles(loc1.0, loc1.1, loc1.2,
-                            loc2.0, loc2.1, loc2.2,
-                            expn_kind)
-        };
-        saw.hash(self.st);
-
-        if expn_kind == SawSpanExpnKind::SomeExpansion {
-            self.hash_span(span.source_callsite());
-        }
-    }
-
-    fn hash_discriminant<T>(&mut self, v: &T) {
-        unsafe {
-            let disr = ::std::intrinsics::discriminant_value(v);
-            debug!("hash_discriminant: disr={}, st={:?}", disr, self.st);
-            disr.hash(self.st);
-        }
-    }
-}
-
-// To off-load the bulk of the hash-computation on #[derive(Hash)],
-// we define a set of enums corresponding to the content that our
-// crate visitor will encounter as it traverses the ast.
-//
-// The important invariant is that all of the Saw*Component enums
-// do not carry any Spans, Names, or Idents.
-//
-// Not carrying any Names/Idents is the important fix for problem
-// noted on PR #13948: using the ident.name as the basis for a
-// hash leads to unstable SVH, because ident.name is just an index
-// into intern table (i.e. essentially a random address), not
-// computed from the name content.
-//
-// With the below enums, the SVH computation is not sensitive to
-// artifacts of how rustc was invoked nor of how the source code
-// was laid out.  (Or at least it is *less* sensitive.)
-
-// This enum represents the different potential bits of code the
-// visitor could encounter that could affect the ABI for the crate,
-// and assigns each a distinct tag to feed into the hash computation.
-#[derive(Hash)]
-enum SawAbiComponent<'a> {
-
-    // FIXME (#14132): should we include (some function of)
-    // ident.ctxt as well?
-    SawIdent(InternedString),
-    SawStructDef(InternedString),
-
-    SawLifetime,
-    SawLifetimeDef(usize),
-
-    SawMod,
-    SawForeignItem(SawForeignItemComponent),
-    SawItem(SawItemComponent),
-    SawTy(SawTyComponent),
-    SawFnDecl(bool),
-    SawGenerics,
-    SawTraitItem(SawTraitOrImplItemComponent),
-    SawImplItem(SawTraitOrImplItemComponent),
-    SawStructField,
-    SawVariant(bool),
-    SawQPath,
-    SawPathSegment,
-    SawPathParameters,
-    SawBlock,
-    SawPat(SawPatComponent),
-    SawLocal,
-    SawArm,
-    SawExpr(SawExprComponent<'a>),
-    SawStmt,
-    SawVis,
-    SawAssociatedItemKind(hir::AssociatedItemKind),
-    SawDefaultness(hir::Defaultness),
-    SawWherePredicate,
-    SawTyParamBound,
-    SawPolyTraitRef,
-    SawAssocTypeBinding,
-    SawAttribute(ast::AttrStyle),
-    SawMacroDef,
-    SawSpan(&'a str,
-            usize, BytePos,
-            usize, BytePos,
-            SawSpanExpnKind),
-    SawSpanTwoFiles(&'a str, usize, BytePos,
-                    &'a str, usize, BytePos,
-                    SawSpanExpnKind),
-}
-
-/// SawExprComponent carries all of the information that we want
-/// to include in the hash that *won't* be covered by the
-/// subsequent recursive traversal of the expression's
-/// substructure by the visitor.
-///
-/// We know every Expr_ variant is covered by a variant because
-/// `fn saw_expr` maps each to some case below.  Ensuring that
-/// each variant carries an appropriate payload has to be verified
-/// by hand.
-///
-/// (However, getting that *exactly* right is not so important
-/// because the SVH is just a developer convenience; there is no
-/// guarantee of collision-freedom, hash collisions are just
-/// (hopefully) unlikely.)
-///
-/// The xxxComponent enums and saw_xxx functions for Item, Pat,
-/// Ty, TraitItem and ImplItem follow the same methodology.
-#[derive(Hash)]
-enum SawExprComponent<'a> {
-
-    SawExprLoop(Option<InternedString>),
-    SawExprField(InternedString),
-    SawExprTupField(usize),
-    SawExprBreak(Option<InternedString>),
-    SawExprAgain(Option<InternedString>),
-
-    SawExprBox,
-    SawExprArray,
-    SawExprCall,
-    SawExprMethodCall,
-    SawExprTup,
-    SawExprBinary(hir::BinOp_),
-    SawExprUnary(hir::UnOp),
-    SawExprLit(ast::LitKind),
-    SawExprLitStr(InternedString, ast::StrStyle),
-    SawExprLitFloat(InternedString, Option<ast::FloatTy>),
-    SawExprCast,
-    SawExprType,
-    SawExprIf,
-    SawExprWhile,
-    SawExprMatch,
-    SawExprClosure(CaptureClause),
-    SawExprBlock,
-    SawExprAssign,
-    SawExprAssignOp(hir::BinOp_),
-    SawExprIndex,
-    SawExprPath,
-    SawExprAddrOf(hir::Mutability),
-    SawExprRet,
-    SawExprInlineAsm(StableInlineAsm<'a>),
-    SawExprStruct,
-    SawExprRepeat,
-}
-
-// The boolean returned indicates whether the span of this expression is always
-// significant, regardless of debuginfo.
-fn saw_expr<'a>(node: &'a Expr_,
-                overflow_checks_enabled: bool)
-                -> (SawExprComponent<'a>, bool) {
-    let binop_can_panic_at_runtime = |binop| {
-        match binop {
-            BiAdd |
-            BiSub |
-            BiMul => overflow_checks_enabled,
-
-            BiDiv |
-            BiRem => true,
-
-            BiAnd |
-            BiOr |
-            BiBitXor |
-            BiBitAnd |
-            BiBitOr |
-            BiShl |
-            BiShr |
-            BiEq |
-            BiLt |
-            BiLe |
-            BiNe |
-            BiGe |
-            BiGt => false
-        }
-    };
-
-    let unop_can_panic_at_runtime = |unop| {
-        match unop {
-            UnDeref |
-            UnNot => false,
-            UnNeg => overflow_checks_enabled,
-        }
-    };
-
-    match *node {
-        ExprBox(..)              => (SawExprBox, false),
-        ExprArray(..)            => (SawExprArray, false),
-        ExprCall(..)             => (SawExprCall, false),
-        ExprMethodCall(..)       => (SawExprMethodCall, false),
-        ExprTup(..)              => (SawExprTup, false),
-        ExprBinary(op, ..)       => {
-            (SawExprBinary(op.node), binop_can_panic_at_runtime(op.node))
-        }
-        ExprUnary(op, _)         => {
-            (SawExprUnary(op), unop_can_panic_at_runtime(op))
-        }
-        ExprLit(ref lit)         => (saw_lit(lit), false),
-        ExprCast(..)             => (SawExprCast, false),
-        ExprType(..)             => (SawExprType, false),
-        ExprIf(..)               => (SawExprIf, false),
-        ExprWhile(..)            => (SawExprWhile, false),
-        ExprLoop(_, id, _)       => (SawExprLoop(id.map(|id| id.node.as_str())), false),
-        ExprMatch(..)            => (SawExprMatch, false),
-        ExprClosure(cc, _, _, _) => (SawExprClosure(cc), false),
-        ExprBlock(..)            => (SawExprBlock, false),
-        ExprAssign(..)           => (SawExprAssign, false),
-        ExprAssignOp(op, ..)     => {
-            (SawExprAssignOp(op.node), binop_can_panic_at_runtime(op.node))
-        }
-        ExprField(_, name)       => (SawExprField(name.node.as_str()), false),
-        ExprTupField(_, id)      => (SawExprTupField(id.node), false),
-        ExprIndex(..)            => (SawExprIndex, true),
-        ExprPath(_)              => (SawExprPath, false),
-        ExprAddrOf(m, _)         => (SawExprAddrOf(m), false),
-        ExprBreak(label, _)      => (SawExprBreak(label.ident.map(|i|
-                                                    i.node.name.as_str())), false),
-        ExprAgain(label)         => (SawExprAgain(label.ident.map(|i|
-                                                    i.node.name.as_str())), false),
-        ExprRet(..)              => (SawExprRet, false),
-        ExprInlineAsm(ref a,..)  => (SawExprInlineAsm(StableInlineAsm(a)), false),
-        ExprStruct(..)           => (SawExprStruct, false),
-        ExprRepeat(..)           => (SawExprRepeat, false),
-    }
-}
-
-fn saw_lit(lit: &ast::Lit) -> SawExprComponent<'static> {
-    match lit.node {
-        ast::LitKind::Str(s, style) => SawExprLitStr(s.as_str(), style),
-        ast::LitKind::Float(s, ty) => SawExprLitFloat(s.as_str(), Some(ty)),
-        ast::LitKind::FloatUnsuffixed(s) => SawExprLitFloat(s.as_str(), None),
-        ref node @ _ => SawExprLit(node.clone()),
-    }
-}
-
-#[derive(Hash)]
-enum SawItemComponent {
-    SawItemExternCrate,
-    SawItemUse(UseKind),
-    SawItemStatic(Mutability),
-    SawItemConst,
-    SawItemFn(Unsafety, Constness, Abi),
-    SawItemMod,
-    SawItemForeignMod(Abi),
-    SawItemTy,
-    SawItemEnum,
-    SawItemStruct,
-    SawItemUnion,
-    SawItemTrait(Unsafety),
-    SawItemDefaultImpl(Unsafety),
-    SawItemImpl(Unsafety, ImplPolarity)
-}
-
-fn saw_item(node: &Item_) -> SawItemComponent {
-    match *node {
-        ItemExternCrate(..) => SawItemExternCrate,
-        ItemUse(_, kind) => SawItemUse(kind),
-        ItemStatic(_, mutability, _) => SawItemStatic(mutability),
-        ItemConst(..) =>SawItemConst,
-        ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi),
-        ItemMod(..) => SawItemMod,
-        ItemForeignMod(ref fm) => SawItemForeignMod(fm.abi),
-        ItemTy(..) => SawItemTy,
-        ItemEnum(..) => SawItemEnum,
-        ItemStruct(..) => SawItemStruct,
-        ItemUnion(..) => SawItemUnion,
-        ItemTrait(unsafety, ..) => SawItemTrait(unsafety),
-        ItemDefaultImpl(unsafety, _) => SawItemDefaultImpl(unsafety),
-        ItemImpl(unsafety, implpolarity, ..) => SawItemImpl(unsafety, implpolarity)
-    }
-}
-
-#[derive(Hash)]
-enum SawForeignItemComponent {
-    Static { mutable: bool },
-    Fn,
-}
-
-#[derive(Hash)]
-enum SawPatComponent {
-    SawPatWild,
-    SawPatBinding(BindingMode),
-    SawPatStruct,
-    SawPatTupleStruct,
-    SawPatPath,
-    SawPatTuple,
-    SawPatBox,
-    SawPatRef(Mutability),
-    SawPatLit,
-    SawPatRange,
-    SawPatSlice
-}
-
-fn saw_pat(node: &PatKind) -> SawPatComponent {
-    match *node {
-        PatKind::Wild => SawPatWild,
-        PatKind::Binding(bindingmode, ..) => SawPatBinding(bindingmode),
-        PatKind::Struct(..) => SawPatStruct,
-        PatKind::TupleStruct(..) => SawPatTupleStruct,
-        PatKind::Path(_) => SawPatPath,
-        PatKind::Tuple(..) => SawPatTuple,
-        PatKind::Box(..) => SawPatBox,
-        PatKind::Ref(_, mutability) => SawPatRef(mutability),
-        PatKind::Lit(..) => SawPatLit,
-        PatKind::Range(..) => SawPatRange,
-        PatKind::Slice(..) => SawPatSlice
-    }
-}
-
-#[derive(Hash)]
-enum SawTyComponent {
-    SawTySlice,
-    SawTyArray,
-    SawTyPtr(Mutability),
-    SawTyRptr(Mutability),
-    SawTyBareFn(Unsafety, Abi),
-    SawTyNever,
-    SawTyTup,
-    SawTyPath,
-    SawTyObjectSum,
-    SawTyImplTrait,
-    SawTyTypeof,
-    SawTyInfer,
-    SawTyErr,
-}
-
-fn saw_ty(node: &Ty_) -> SawTyComponent {
-    match *node {
-      TySlice(..) => SawTySlice,
-      TyArray(..) => SawTyArray,
-      TyPtr(ref mty) => SawTyPtr(mty.mutbl),
-      TyRptr(_, ref mty) => SawTyRptr(mty.mutbl),
-      TyBareFn(ref barefnty) => SawTyBareFn(barefnty.unsafety, barefnty.abi),
-      TyNever => SawTyNever,
-      TyTup(..) => SawTyTup,
-      TyPath(_) => SawTyPath,
-      TyTraitObject(..) => SawTyObjectSum,
-      TyImplTrait(..) => SawTyImplTrait,
-      TyTypeof(..) => SawTyTypeof,
-      TyInfer => SawTyInfer,
-      TyErr => SawTyErr,
-    }
-}
-
-#[derive(Hash)]
-enum SawTraitOrImplItemComponent {
-    SawTraitOrImplItemConst,
-    // The boolean signifies whether a body is present
-    SawTraitOrImplItemMethod(Unsafety, Constness, Abi, bool),
-    SawTraitOrImplItemType
-}
-
-fn saw_trait_item(ti: &TraitItemKind) -> SawTraitOrImplItemComponent {
-    match *ti {
-        TraitItemKind::Const(..) => SawTraitOrImplItemConst,
-        TraitItemKind::Method(ref sig, TraitMethod::Required(_)) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, false),
-        TraitItemKind::Method(ref sig, TraitMethod::Provided(_)) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
-        TraitItemKind::Type(..) => SawTraitOrImplItemType
-    }
-}
-
-fn saw_impl_item(ii: &ImplItemKind) -> SawTraitOrImplItemComponent {
-    match *ii {
-        ImplItemKind::Const(..) => SawTraitOrImplItemConst,
-        ImplItemKind::Method(ref sig, _) =>
-            SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
-        ImplItemKind::Type(..) => SawTraitOrImplItemType
-    }
-}
-
-#[derive(Clone, Copy, Hash, Eq, PartialEq)]
-enum SawSpanExpnKind {
-    NoExpansion,
-    SomeExpansion,
-}
-
-/// A wrapper that provides a stable Hash implementation.
-struct StableInlineAsm<'a>(&'a InlineAsm);
-
-impl<'a> Hash for StableInlineAsm<'a> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        let InlineAsm {
-            asm,
-            asm_str_style,
-            ref outputs,
-            ref inputs,
-            ref clobbers,
-            volatile,
-            alignstack,
-            dialect,
-            ctxt: _, // This is used for error reporting
-        } = *self.0;
-
-        asm.as_str().hash(state);
-        asm_str_style.hash(state);
-        outputs.len().hash(state);
-        for output in outputs {
-            let InlineAsmOutput { constraint, is_rw, is_indirect } = *output;
-            constraint.as_str().hash(state);
-            is_rw.hash(state);
-            is_indirect.hash(state);
-        }
-        inputs.len().hash(state);
-        for input in inputs {
-            input.as_str().hash(state);
-        }
-        clobbers.len().hash(state);
-        for clobber in clobbers {
-            clobber.as_str().hash(state);
-        }
-        volatile.hash(state);
-        alignstack.hash(state);
-        dialect.hash(state);
-    }
-}
-
-macro_rules! hash_attrs {
-    ($visitor:expr, $attrs:expr) => ({
-        let attrs = $attrs;
-        if attrs.len() > 0 {
-            $visitor.hash_attributes(attrs);
-        }
-    })
-}
-
-macro_rules! hash_span {
-    ($visitor:expr, $span:expr) => ({
-        hash_span!($visitor, $span, false)
-    });
-    ($visitor:expr, $span:expr, $force:expr) => ({
-        if $force || $visitor.hash_spans {
-            $visitor.hash_span($span);
-        }
-    });
-}
-
-impl<'a, 'hash, 'tcx> Visitor<'tcx> for StrictVersionHashVisitor<'a, 'hash, 'tcx> {
-    fn nested_visit_map<'this>(&'this mut self) -> visit::NestedVisitorMap<'this, 'tcx> {
-        if self.hash_bodies {
-            visit::NestedVisitorMap::OnlyBodies(&self.tcx.hir)
-        } else {
-            visit::NestedVisitorMap::None
-        }
-    }
-
-    fn visit_variant_data(&mut self,
-                          s: &'tcx VariantData,
-                          name: Name,
-                          _: &'tcx Generics,
-                          _: NodeId,
-                          span: Span) {
-        debug!("visit_variant_data: st={:?}", self.st);
-        SawStructDef(name.as_str()).hash(self.st);
-        hash_span!(self, span);
-        visit::walk_struct_def(self, s);
-    }
-
-    fn visit_variant(&mut self,
-                     v: &'tcx Variant,
-                     g: &'tcx Generics,
-                     item_id: NodeId) {
-        debug!("visit_variant: st={:?}", self.st);
-        SawVariant(v.node.disr_expr.is_some()).hash(self.st);
-        hash_attrs!(self, &v.node.attrs);
-        visit::walk_variant(self, v, g, item_id)
-    }
-
-    fn visit_name(&mut self, span: Span, name: Name) {
-        debug!("visit_name: st={:?}", self.st);
-        SawIdent(name.as_str()).hash(self.st);
-        hash_span!(self, span);
-    }
-
-    fn visit_lifetime(&mut self, l: &'tcx Lifetime) {
-        debug!("visit_lifetime: st={:?}", self.st);
-        SawLifetime.hash(self.st);
-        visit::walk_lifetime(self, l);
-    }
-
-    fn visit_lifetime_def(&mut self, l: &'tcx LifetimeDef) {
-        debug!("visit_lifetime_def: st={:?}", self.st);
-        SawLifetimeDef(l.bounds.len()).hash(self.st);
-        visit::walk_lifetime_def(self, l);
-    }
-
-    fn visit_expr(&mut self, ex: &'tcx Expr) {
-        debug!("visit_expr: st={:?}", self.st);
-        let (saw_expr, force_span) = saw_expr(&ex.node,
-                                              self.overflow_checks_enabled);
-        SawExpr(saw_expr).hash(self.st);
-        // No need to explicitly hash the discriminant here, since we are
-        // implicitly hashing the discriminant of SawExprComponent.
-        hash_span!(self, ex.span, force_span);
-        hash_attrs!(self, &ex.attrs);
-
-        // Always hash nested constant bodies (e.g. n in `[x; n]`).
-        let hash_bodies = self.hash_bodies;
-        self.hash_bodies = true;
-        visit::walk_expr(self, ex);
-        self.hash_bodies = hash_bodies;
-    }
-
-    fn visit_stmt(&mut self, s: &'tcx Stmt) {
-        debug!("visit_stmt: st={:?}", self.st);
-
-        // We don't want to modify the hash for decls, because
-        // they might be item decls (if they are local decls,
-        // we'll hash that fact in visit_local); but we do want to
-        // remember if this was a StmtExpr or StmtSemi (the later
-        // had an explicit semi-colon; this affects the typing
-        // rules).
-        match s.node {
-            StmtDecl(..) => (),
-            StmtExpr(..) => {
-                SawStmt.hash(self.st);
-                self.hash_discriminant(&s.node);
-                hash_span!(self, s.span);
-            }
-            StmtSemi(..) => {
-                SawStmt.hash(self.st);
-                self.hash_discriminant(&s.node);
-                hash_span!(self, s.span);
-            }
-        }
-
-        visit::walk_stmt(self, s)
-    }
-
-    fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) {
-        debug!("visit_foreign_item: st={:?}", self.st);
-
-        match i.node {
-            ForeignItemFn(..) => {
-                SawForeignItem(SawForeignItemComponent::Fn)
-            }
-            ForeignItemStatic(_, mutable) => {
-                SawForeignItem(SawForeignItemComponent::Static {
-                    mutable: mutable
-                })
-            }
-        }.hash(self.st);
-
-        hash_span!(self, i.span);
-        hash_attrs!(self, &i.attrs);
-        visit::walk_foreign_item(self, i)
-    }
-
-    fn visit_item(&mut self, i: &'tcx Item) {
-        debug!("visit_item: {:?} st={:?}", i, self.st);
-
-        self.maybe_enable_overflow_checks(&i.attrs);
-
-        SawItem(saw_item(&i.node)).hash(self.st);
-        hash_span!(self, i.span);
-        hash_attrs!(self, &i.attrs);
-        visit::walk_item(self, i)
-    }
-
-    fn visit_mod(&mut self, m: &'tcx Mod, span: Span, n: NodeId) {
-        debug!("visit_mod: st={:?}", self.st);
-        SawMod.hash(self.st);
-        hash_span!(self, span);
-        visit::walk_mod(self, m, n)
-    }
-
-    fn visit_ty(&mut self, t: &'tcx Ty) {
-        debug!("visit_ty: st={:?}", self.st);
-        SawTy(saw_ty(&t.node)).hash(self.st);
-        hash_span!(self, t.span);
-
-        // Always hash nested constant bodies (e.g. N in `[T; N]`).
-        let hash_bodies = self.hash_bodies;
-        self.hash_bodies = true;
-        visit::walk_ty(self, t);
-        self.hash_bodies = hash_bodies;
-    }
-
-    fn visit_generics(&mut self, g: &'tcx Generics) {
-        debug!("visit_generics: st={:?}", self.st);
-        SawGenerics.hash(self.st);
-        visit::walk_generics(self, g)
-    }
-
-    fn visit_fn_decl(&mut self, fd: &'tcx FnDecl) {
-        debug!("visit_fn_decl: st={:?}", self.st);
-        SawFnDecl(fd.variadic).hash(self.st);
-        visit::walk_fn_decl(self, fd)
-    }
-
-    fn visit_trait_item(&mut self, ti: &'tcx TraitItem) {
-        debug!("visit_trait_item: st={:?}", self.st);
-
-        self.maybe_enable_overflow_checks(&ti.attrs);
-
-        SawTraitItem(saw_trait_item(&ti.node)).hash(self.st);
-        hash_span!(self, ti.span);
-        hash_attrs!(self, &ti.attrs);
-        visit::walk_trait_item(self, ti)
-    }
-
-    fn visit_impl_item(&mut self, ii: &'tcx ImplItem) {
-        debug!("visit_impl_item: st={:?}", self.st);
-
-        self.maybe_enable_overflow_checks(&ii.attrs);
-
-        SawImplItem(saw_impl_item(&ii.node)).hash(self.st);
-        hash_span!(self, ii.span);
-        hash_attrs!(self, &ii.attrs);
-        visit::walk_impl_item(self, ii)
-    }
-
-    fn visit_struct_field(&mut self, s: &'tcx StructField) {
-        debug!("visit_struct_field: st={:?}", self.st);
-        SawStructField.hash(self.st);
-        hash_span!(self, s.span);
-        hash_attrs!(self, &s.attrs);
-        visit::walk_struct_field(self, s)
-    }
-
-    fn visit_qpath(&mut self, qpath: &'tcx QPath, id: NodeId, span: Span) {
-        debug!("visit_qpath: st={:?}", self.st);
-        SawQPath.hash(self.st);
-        self.hash_discriminant(qpath);
-        visit::walk_qpath(self, qpath, id, span)
-    }
-
-    fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) {
-        debug!("visit_path: st={:?}", self.st);
-        hash_span!(self, path.span);
-        visit::walk_path(self, path)
-    }
-
-    fn visit_def_mention(&mut self, def: Def) {
-        self.hash_def(def);
-    }
-
-    fn visit_block(&mut self, b: &'tcx Block) {
-        debug!("visit_block: st={:?}", self.st);
-        SawBlock.hash(self.st);
-        hash_span!(self, b.span);
-        visit::walk_block(self, b)
-    }
-
-    fn visit_pat(&mut self, p: &'tcx Pat) {
-        debug!("visit_pat: st={:?}", self.st);
-        SawPat(saw_pat(&p.node)).hash(self.st);
-        hash_span!(self, p.span);
-        visit::walk_pat(self, p)
-    }
-
-    fn visit_local(&mut self, l: &'tcx Local) {
-        debug!("visit_local: st={:?}", self.st);
-        SawLocal.hash(self.st);
-        hash_attrs!(self, &l.attrs);
-        visit::walk_local(self, l)
-        // No need to hash span, we are hashing all component spans
-    }
-
-    fn visit_arm(&mut self, a: &'tcx Arm) {
-        debug!("visit_arm: st={:?}", self.st);
-        SawArm.hash(self.st);
-        hash_attrs!(self, &a.attrs);
-        visit::walk_arm(self, a)
-    }
-
-    fn visit_id(&mut self, id: NodeId) {
-        debug!("visit_id: id={} st={:?}", id, self.st);
-        self.hash_resolve(id)
-    }
-
-    fn visit_vis(&mut self, v: &'tcx Visibility) {
-        debug!("visit_vis: st={:?}", self.st);
-        SawVis.hash(self.st);
-        self.hash_discriminant(v);
-        visit::walk_vis(self, v)
-    }
-
-    fn visit_associated_item_kind(&mut self, kind: &'tcx AssociatedItemKind) {
-        debug!("visit_associated_item_kind: st={:?}", self.st);
-        SawAssociatedItemKind(*kind).hash(self.st);
-        visit::walk_associated_item_kind(self, kind);
-    }
-
-    fn visit_defaultness(&mut self, defaultness: &'tcx Defaultness) {
-        debug!("visit_associated_item_kind: st={:?}", self.st);
-        SawDefaultness(*defaultness).hash(self.st);
-        visit::walk_defaultness(self, defaultness);
-    }
-
-    fn visit_where_predicate(&mut self, predicate: &'tcx WherePredicate) {
-        debug!("visit_where_predicate: st={:?}", self.st);
-        SawWherePredicate.hash(self.st);
-        self.hash_discriminant(predicate);
-        // Ignoring span. Any important nested components should be visited.
-        visit::walk_where_predicate(self, predicate)
-    }
-
-    fn visit_ty_param_bound(&mut self, bounds: &'tcx TyParamBound) {
-        debug!("visit_ty_param_bound: st={:?}", self.st);
-        SawTyParamBound.hash(self.st);
-        self.hash_discriminant(bounds);
-        // The TraitBoundModifier in TraitTyParamBound will be hash in
-        // visit_poly_trait_ref()
-        visit::walk_ty_param_bound(self, bounds)
-    }
-
-    fn visit_poly_trait_ref(&mut self, t: &'tcx PolyTraitRef, m: TraitBoundModifier) {
-        debug!("visit_poly_trait_ref: st={:?}", self.st);
-        SawPolyTraitRef.hash(self.st);
-        m.hash(self.st);
-        visit::walk_poly_trait_ref(self, t, m)
-    }
-
-    fn visit_path_segment(&mut self, path_span: Span, path_segment: &'tcx PathSegment) {
-        debug!("visit_path_segment: st={:?}", self.st);
-        SawPathSegment.hash(self.st);
-        visit::walk_path_segment(self, path_span, path_segment)
-    }
-
-    fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'tcx PathParameters) {
-        debug!("visit_path_parameters: st={:?}", self.st);
-        SawPathParameters.hash(self.st);
-        self.hash_discriminant(path_parameters);
-        visit::walk_path_parameters(self, path_span, path_parameters)
-    }
-
-    fn visit_assoc_type_binding(&mut self, type_binding: &'tcx TypeBinding) {
-        debug!("visit_assoc_type_binding: st={:?}", self.st);
-        SawAssocTypeBinding.hash(self.st);
-        hash_span!(self, type_binding.span);
-        visit::walk_assoc_type_binding(self, type_binding)
-    }
-
-    fn visit_attribute(&mut self, _: &ast::Attribute) {
-        // We explicitly do not use this method, since doing that would
-        // implicitly impose an order on the attributes being hashed, while we
-        // explicitly don't want their order to matter
-    }
-
-    fn visit_macro_def(&mut self, macro_def: &'tcx MacroDef) {
-        debug!("visit_macro_def: st={:?}", self.st);
-        SawMacroDef.hash(self.st);
-        hash_attrs!(self, &macro_def.attrs);
-        for tt in macro_def.body.trees() {
-            self.hash_token_tree(&tt);
-        }
-        visit::walk_macro_def(self, macro_def)
-    }
-}
-
-#[derive(Hash)]
-pub enum DefHash {
-    SawDefId,
-    SawLabel,
-    SawPrimTy,
-    SawSelfTy,
-    SawErr,
-}
-
-impl<'a, 'hash, 'tcx> StrictVersionHashVisitor<'a, 'hash, 'tcx> {
-    fn hash_resolve(&mut self, id: ast::NodeId) {
-        // Because whether or not a given id has an entry is dependent
-        // solely on expr variant etc, we don't need to hash whether
-        // or not an entry was present (we are already hashing what
-        // variant it is above when we visit the HIR).
-
-        if let Some(traits) = self.tcx.trait_map.get(&id) {
-            debug!("hash_resolve: id={:?} traits={:?} st={:?}", id, traits, self.st);
-            traits.len().hash(self.st);
-
-            // The ordering of the candidates is not fixed. So we hash
-            // the def-ids and then sort them and hash the collection.
-            let mut candidates: Vec<_> =
-                traits.iter()
-                      .map(|&TraitCandidate { def_id, import_id: _ }| {
-                          self.compute_def_id_hash(def_id)
-                      })
-                      .collect();
-            candidates.sort();
-            candidates.hash(self.st);
-        }
-    }
-
-    fn hash_def_id(&mut self, def_id: DefId) {
-        self.compute_def_id_hash(def_id).hash(self.st);
-    }
-
-    fn hash_def(&mut self, def: Def) {
-        match def {
-            // Crucial point: for all of these variants, the variant +
-            // add'l data that is added is always the same if the
-            // def-id is the same, so it suffices to hash the def-id
-            Def::Fn(..) |
-            Def::Mod(..) |
-            Def::Static(..) |
-            Def::Variant(..) |
-            Def::VariantCtor(..) |
-            Def::Enum(..) |
-            Def::TyAlias(..) |
-            Def::AssociatedTy(..) |
-            Def::TyParam(..) |
-            Def::Struct(..) |
-            Def::StructCtor(..) |
-            Def::Union(..) |
-            Def::Trait(..) |
-            Def::Method(..) |
-            Def::Const(..) |
-            Def::AssociatedConst(..) |
-            Def::Local(..) |
-            Def::Upvar(..) |
-            Def::Macro(..) => {
-                DefHash::SawDefId.hash(self.st);
-                self.hash_def_id(def.def_id());
-            }
-
-            Def::Label(..) => {
-                DefHash::SawLabel.hash(self.st);
-                // we don't encode the `id` because it always refers to something
-                // within this item, so if it changed, there would have to be other
-                // changes too
-            }
-            Def::PrimTy(ref prim_ty) => {
-                DefHash::SawPrimTy.hash(self.st);
-                prim_ty.hash(self.st);
-            }
-            Def::SelfTy(..) => {
-                DefHash::SawSelfTy.hash(self.st);
-                // the meaning of Self is always the same within a
-                // given context, so we don't need to hash the other
-                // fields
-            }
-            Def::Err => {
-                DefHash::SawErr.hash(self.st);
-            }
-        }
-    }
-
-    pub fn hash_attributes(&mut self, attributes: &[ast::Attribute]) {
-        debug!("hash_attributes: st={:?}", self.st);
-        let indices = self.indices_sorted_by(attributes, |attr| attr.name());
-
-        for i in indices {
-            let attr = &attributes[i];
-            match attr.name() {
-                Some(name) if IGNORED_ATTRIBUTES.contains(&&*name.as_str()) => continue,
-                _ => {}
-            };
-            if !attr.is_sugared_doc {
-                SawAttribute(attr.style).hash(self.st);
-                for segment in &attr.path.segments {
-                    SawIdent(segment.identifier.name.as_str()).hash(self.st);
-                }
-                for tt in attr.tokens.trees() {
-                    self.hash_token_tree(&tt);
-                }
-            }
-        }
-    }
-
-    fn indices_sorted_by<T, K, F>(&mut self, items: &[T], get_key: F) -> Vec<usize>
-        where K: Ord,
-              F: Fn(&T) -> K
-    {
-        let mut indices = Vec::with_capacity(items.len());
-        indices.extend(0 .. items.len());
-        indices.sort_by_key(|index| get_key(&items[*index]));
-        indices
-    }
-
-    fn maybe_enable_overflow_checks(&mut self, item_attrs: &[ast::Attribute]) {
-        if attr::contains_name(item_attrs, "rustc_inherit_overflow_checks") {
-            self.overflow_checks_enabled = true;
-        }
-    }
-
-    fn hash_token_tree(&mut self, tt: &tokenstream::TokenTree) {
-        self.hash_discriminant(tt);
-        match *tt {
-            tokenstream::TokenTree::Token(span, ref token) => {
-                hash_span!(self, span);
-                self.hash_token(token, span);
-            }
-            tokenstream::TokenTree::Delimited(span, ref delimited) => {
-                hash_span!(self, span);
-                delimited.delim.hash(self.st);
-                for sub_tt in delimited.stream().trees() {
-                    self.hash_token_tree(&sub_tt);
-                }
-            }
-        }
-    }
-
-    fn hash_token(&mut self,
-                  token: &token::Token,
-                  error_reporting_span: Span) {
-        self.hash_discriminant(token);
-        match *token {
-            token::Token::Eq |
-            token::Token::Lt |
-            token::Token::Le |
-            token::Token::EqEq |
-            token::Token::Ne |
-            token::Token::Ge |
-            token::Token::Gt |
-            token::Token::AndAnd |
-            token::Token::OrOr |
-            token::Token::Not |
-            token::Token::Tilde |
-            token::Token::At |
-            token::Token::Dot |
-            token::Token::DotDot |
-            token::Token::DotDotDot |
-            token::Token::Comma |
-            token::Token::Semi |
-            token::Token::Colon |
-            token::Token::ModSep |
-            token::Token::RArrow |
-            token::Token::LArrow |
-            token::Token::FatArrow |
-            token::Token::Pound |
-            token::Token::Dollar |
-            token::Token::Question |
-            token::Token::Underscore |
-            token::Token::Whitespace |
-            token::Token::Comment |
-            token::Token::Eof => {}
-
-            token::Token::BinOp(bin_op_token) |
-            token::Token::BinOpEq(bin_op_token) => bin_op_token.hash(self.st),
-
-            token::Token::OpenDelim(delim_token) |
-            token::Token::CloseDelim(delim_token) => delim_token.hash(self.st),
-
-            token::Token::Literal(ref lit, ref opt_name) => {
-                self.hash_discriminant(lit);
-                match *lit {
-                    token::Lit::Byte(val) |
-                    token::Lit::Char(val) |
-                    token::Lit::Integer(val) |
-                    token::Lit::Float(val) |
-                    token::Lit::Str_(val) |
-                    token::Lit::ByteStr(val) => val.as_str().hash(self.st),
-                    token::Lit::StrRaw(val, n) |
-                    token::Lit::ByteStrRaw(val, n) => {
-                        val.as_str().hash(self.st);
-                        n.hash(self.st);
-                    }
-                };
-                opt_name.map(ast::Name::as_str).hash(self.st);
-            }
-
-            token::Token::Ident(ident) |
-            token::Token::Lifetime(ident) |
-            token::Token::SubstNt(ident) => ident.name.as_str().hash(self.st),
-
-            token::Token::Interpolated(ref non_terminal) => {
-                // FIXME(mw): This could be implemented properly. It's just a
-                //            lot of work, since we would need to hash the AST
-                //            in a stable way, in addition to the HIR.
-                //            Since this is hardly used anywhere, just emit a
-                //            warning for now.
-                if self.tcx.sess.opts.debugging_opts.incremental.is_some() {
-                    let msg = format!("Quasi-quoting might make incremental \
-                                       compilation very inefficient: {:?}",
-                                      non_terminal);
-                    self.tcx.sess.span_warn(error_reporting_span, &msg[..]);
-                }
-
-                non_terminal.hash(self.st);
-            }
-
-            token::Token::DocComment(val) |
-            token::Token::Shebang(val) => val.as_str().hash(self.st),
-        }
-    }
-
-    pub fn hash_crate_root_module(&mut self, krate: &'tcx Crate) {
-        let hir::Crate {
-            ref module,
-            ref attrs,
-            span,
-
-            // These fields are handled separately:
-            exported_macros: _,
-            items: _,
-            trait_items: _,
-            impl_items: _,
-            bodies: _,
-            trait_impls: _,
-            trait_default_impl: _,
-            body_ids: _,
-        } = *krate;
-
-        visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
-        // Crate attributes are not copied over to the root `Mod`, so hash them
-        // explicitly here.
-        hash_attrs!(self, attrs);
-    }
-}
diff --git a/src/librustc_incremental/lib.rs b/src/librustc_incremental/lib.rs
index 477777c975d..d10df17f858 100644
--- a/src/librustc_incremental/lib.rs
+++ b/src/librustc_incremental/lib.rs
@@ -22,7 +22,6 @@
 #![feature(rustc_private)]
 #![feature(staged_api)]
 #![feature(rand)]
-#![feature(core_intrinsics)]
 #![feature(conservative_impl_trait)]
 #![cfg_attr(stage0, feature(pub_restricted))]
 
diff --git a/src/librustc_llvm/build.rs b/src/librustc_llvm/build.rs
index 2b945e0a3af..7d5887e699f 100644
--- a/src/librustc_llvm/build.rs
+++ b/src/librustc_llvm/build.rs
@@ -259,4 +259,10 @@ fn main() {
             println!("cargo:rustc-link-lib={}", stdcppname);
         }
     }
+
+    // LLVM requires symbols from this library, but apparently they're not printeds
+    // during llvm-config?
+    if target.contains("windows") {
+        println!("cargo:rustc-link-lib=ole32");
+    }
 }
diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs
index 26c7a9166e6..32c9183ece9 100644
--- a/src/librustc_llvm/ffi.rs
+++ b/src/librustc_llvm/ffi.rs
@@ -1662,10 +1662,3 @@ extern "C" {
     pub fn LLVMRustUnsetComdat(V: ValueRef);
     pub fn LLVMRustSetModulePIELevel(M: ModuleRef);
 }
-
-
-// LLVM requires symbols from this library, but apparently they're not printed
-// during llvm-config?
-#[cfg(windows)]
-#[link(name = "ole32")]
-extern "C" {}
diff --git a/src/librustc_mir/build/cfg.rs b/src/librustc_mir/build/cfg.rs
index 71e97e4bfe0..c503b8c7fe0 100644
--- a/src/librustc_mir/build/cfg.rs
+++ b/src/librustc_mir/build/cfg.rs
@@ -25,6 +25,9 @@ impl<'tcx> CFG<'tcx> {
         &mut self.basic_blocks[blk]
     }
 
+    // llvm.org/PR32488 makes this function use an excess of stack space. Mark
+    // it as #[inline(never)] to keep rustc's stack use in check.
+    #[inline(never)]
     pub fn start_new_block(&mut self) -> BasicBlock {
         self.basic_blocks.push(BasicBlockData::new(None))
     }
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 05f30f039c8..966cb7ee8d8 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -222,8 +222,10 @@ impl<'a> base::Resolver for Resolver<'a> {
             let name = unwrap_or!(attrs[i].name(), continue);
 
             if name == "derive" {
-                let result = attrs[i].parse_list(&self.session.parse_sess,
-                                                 |parser| parser.parse_path(PathStyle::Mod));
+                let result = attrs[i].parse_list(&self.session.parse_sess, |parser| {
+                    parser.parse_path_allowing_meta(PathStyle::Mod)
+                });
+
                 let mut traits = match result {
                     Ok(traits) => traits,
                     Err(mut e) => {
diff --git a/src/librustc_save_analysis/dump_visitor.rs b/src/librustc_save_analysis/dump_visitor.rs
index f2aa89ba4b6..3fd0ce45e36 100644
--- a/src/librustc_save_analysis/dump_visitor.rs
+++ b/src/librustc_save_analysis/dump_visitor.rs
@@ -1149,8 +1149,32 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                                     &trait_item.attrs,
                                     trait_item.span);
             }
-            ast::TraitItemKind::Const(_, None) |
-            ast::TraitItemKind::Type(..) |
+            ast::TraitItemKind::Type(ref _bounds, ref default_ty) => {
+                // FIXME do something with _bounds (for type refs)
+                let name = trait_item.ident.name.to_string();
+                let qualname = format!("::{}", self.tcx.node_path_str(trait_item.id));
+                let sub_span = self.span.sub_span_after_keyword(trait_item.span, keywords::Type);
+
+                if !self.span.filter_generated(sub_span, trait_item.span) {
+                    self.dumper.typedef(TypeDefData {
+                        span: sub_span.expect("No span found for assoc type"),
+                        name: name,
+                        id: trait_item.id,
+                        qualname: qualname,
+                        value: self.span.snippet(trait_item.span),
+                        visibility: Visibility::Public,
+                        parent: Some(trait_id),
+                        docs: docs_for_attrs(&trait_item.attrs),
+                        sig: None,
+                        attributes: trait_item.attrs.clone(),
+                    }.lower(self.tcx));
+                }
+
+                if let &Some(ref default_ty) = default_ty {
+                    self.visit_ty(default_ty)
+                }
+            }
+            ast::TraitItemKind::Const(ref ty, None) => self.visit_ty(ty),
             ast::TraitItemKind::Macro(_) => {}
         }
     }
@@ -1177,7 +1201,7 @@ impl<'l, 'tcx: 'l, 'll, D: Dump + 'll> DumpVisitor<'l, 'tcx, 'll, D> {
                                     &impl_item.attrs,
                                     impl_item.span);
             }
-            ast::ImplItemKind::Type(_) |
+            ast::ImplItemKind::Type(ref ty) => self.visit_ty(ty),
             ast::ImplItemKind::Macro(_) => {}
         }
     }
@@ -1377,15 +1401,6 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
         debug!("visit_expr {:?}", ex.node);
         self.process_macro_use(ex.span, ex.id);
         match ex.node {
-            ast::ExprKind::Call(ref _f, ref _args) => {
-                // Don't need to do anything for function calls,
-                // because just walking the callee path does what we want.
-                visit::walk_expr(self, ex);
-            }
-            ast::ExprKind::Path(_, ref path) => {
-                self.process_path(ex.id, path, None);
-                visit::walk_expr(self, ex);
-            }
             ast::ExprKind::Struct(ref path, ref fields, ref base) => {
                 let hir_expr = self.save_ctxt.tcx.hir.expect_expr(ex.id);
                 let adt = match self.save_ctxt.tables.expr_ty_opt(&hir_expr) {
@@ -1483,6 +1498,8 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
                 self.visit_expr(element);
                 self.nest_tables(count.id, |v| v.visit_expr(count));
             }
+            // In particular, we take this branch for call and path expressions,
+            // where we'll index the idents involved just by continuing to walk.
             _ => {
                 visit::walk_expr(self, ex)
             }
@@ -1582,4 +1599,39 @@ impl<'l, 'tcx: 'l, 'll, D: Dump +'ll> Visitor<'l> for DumpVisitor<'l, 'tcx, 'll,
         walk_list!(self, visit_ty, &l.ty);
         walk_list!(self, visit_expr, &l.init);
     }
+
+    fn visit_foreign_item(&mut self, item: &'l ast::ForeignItem) {
+        match item.node {
+            ast::ForeignItemKind::Fn(ref decl, ref generics) => {
+                if let Some(fn_data) = self.save_ctxt.get_extern_item_data(item) {
+                    down_cast_data!(fn_data, FunctionData, item.span);
+                    if !self.span.filter_generated(Some(fn_data.span), item.span) {
+                        self.dumper.function(fn_data.clone().lower(self.tcx));
+                    }
+
+                    self.nest_tables(item.id, |v| v.process_formals(&decl.inputs,
+                                                                    &fn_data.qualname));
+                    self.process_generic_params(generics, item.span, &fn_data.qualname, item.id);
+                }
+
+                for arg in &decl.inputs {
+                    self.visit_ty(&arg.ty);
+                }
+
+                if let ast::FunctionRetTy::Ty(ref ret_ty) = decl.output {
+                    self.visit_ty(&ret_ty);
+                }
+            }
+            ast::ForeignItemKind::Static(ref ty, _) => {
+                if let Some(var_data) = self.save_ctxt.get_extern_item_data(item) {
+                    down_cast_data!(var_data, VariableData, item.span);
+                    if !self.span.filter_generated(Some(var_data.span), item.span) {
+                        self.dumper.variable(var_data.lower(self.tcx));
+                    }
+                }
+
+                self.visit_ty(ty);
+            }
+        }
+    }
 }
diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs
index 1de9fbc8e49..44615071a56 100644
--- a/src/librustc_save_analysis/lib.rs
+++ b/src/librustc_save_analysis/lib.rs
@@ -120,6 +120,50 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         result
     }
 
+    pub fn get_extern_item_data(&self, item: &ast::ForeignItem) -> Option<Data> {
+        let qualname = format!("::{}", self.tcx.node_path_str(item.id));
+        match item.node {
+            ast::ForeignItemKind::Fn(ref decl, ref generics) => {
+                let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Fn);
+                filter!(self.span_utils, sub_span, item.span, None);
+                Some(Data::FunctionData(FunctionData {
+                    id: item.id,
+                    name: item.ident.to_string(),
+                    qualname: qualname,
+                    declaration: None,
+                    span: sub_span.unwrap(),
+                    scope: self.enclosing_scope(item.id),
+                    value: make_signature(decl, generics),
+                    visibility: From::from(&item.vis),
+                    parent: None,
+                    docs: docs_for_attrs(&item.attrs),
+                    sig: self.sig_base_extern(item),
+                    attributes: item.attrs.clone(),
+                }))
+            }
+            ast::ForeignItemKind::Static(ref ty, m) => {
+                let keyword = if m { keywords::Mut } else { keywords::Static };
+                let sub_span = self.span_utils.sub_span_after_keyword(item.span, keyword);
+                filter!(self.span_utils, sub_span, item.span, None);
+                Some(Data::VariableData(VariableData {
+                    id: item.id,
+                    kind: VariableKind::Static,
+                    name: item.ident.to_string(),
+                    qualname: qualname,
+                    span: sub_span.unwrap(),
+                    scope: self.enclosing_scope(item.id),
+                    parent: None,
+                    value: String::new(),
+                    type_value: ty_to_string(ty),
+                    visibility: From::from(&item.vis),
+                    docs: docs_for_attrs(&item.attrs),
+                    sig: Some(self.sig_base_extern(item)),
+                    attributes: item.attrs.clone(),
+                }))
+            }
+        }
+    }
+
     pub fn get_item_data(&self, item: &ast::Item) -> Option<Data> {
         match item.node {
             ast::ItemKind::Fn(ref decl, .., ref generics, _) => {
@@ -751,6 +795,21 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> {
         }
     }
 
+    fn sig_base_extern(&self, item: &ast::ForeignItem) -> Signature {
+        let text = self.span_utils.signature_string_for_span(item.span);
+        let name = item.ident.to_string();
+        let ident_start = text.find(&name).expect("Name not in signature?");
+        let ident_end = ident_start + name.len();
+        Signature {
+            span: Span { hi: item.span.lo + BytePos(text.len() as u32), ..item.span },
+            text: text,
+            ident_start: ident_start,
+            ident_end: ident_end,
+            defs: vec![],
+            refs: vec![],
+        }
+    }
+
     #[inline]
     pub fn enclosing_scope(&self, id: NodeId) -> NodeId {
         self.tcx.hir.get_enclosing_scope(id).unwrap_or(CRATE_NODE_ID)
diff --git a/src/librustc_trans/assert_module_sources.rs b/src/librustc_trans/assert_module_sources.rs
index 8528482c785..63cfe591ce3 100644
--- a/src/librustc_trans/assert_module_sources.rs
+++ b/src/librustc_trans/assert_module_sources.rs
@@ -32,8 +32,7 @@ use syntax::ast;
 
 use {ModuleSource, ModuleTranslation};
 
-const PARTITION_REUSED: &'static str = "rustc_partition_reused";
-const PARTITION_TRANSLATED: &'static str = "rustc_partition_translated";
+use rustc::ich::{ATTR_PARTITION_REUSED, ATTR_PARTITION_TRANSLATED};
 
 const MODULE: &'static str = "module";
 const CFG: &'static str = "cfg";
@@ -62,9 +61,9 @@ struct AssertModuleSource<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> AssertModuleSource<'a, 'tcx> {
     fn check_attr(&self, attr: &ast::Attribute) {
-        let disposition = if attr.check_name(PARTITION_REUSED) {
+        let disposition = if attr.check_name(ATTR_PARTITION_REUSED) {
             Disposition::Reused
-        } else if attr.check_name(PARTITION_TRANSLATED) {
+        } else if attr.check_name(ATTR_PARTITION_TRANSLATED) {
             Disposition::Translated
         } else {
             return;
diff --git a/src/librustc_trans/back/link.rs b/src/librustc_trans/back/link.rs
index 6d17b2f0eed..12a1ffa2767 100644
--- a/src/librustc_trans/back/link.rs
+++ b/src/librustc_trans/back/link.rs
@@ -734,9 +734,10 @@ fn link_natively(sess: &Session,
     }
 
     {
-        let mut linker = trans.linker_info.to_linker(&mut cmd, &sess);
+        let mut linker = trans.linker_info.to_linker(cmd, &sess);
         link_args(&mut *linker, sess, crate_type, tmpdir,
                   objects, out_filename, outputs, trans);
+        cmd = linker.finalize();
     }
     cmd.args(&sess.target.target.options.late_link_args);
     for obj in &sess.target.target.options.post_link_objects {
@@ -1021,38 +1022,18 @@ fn add_local_native_libraries(cmd: &mut Linker, sess: &Session) {
         }
     });
 
-    let pair = sess.cstore.used_libraries().into_iter().filter(|l| {
+    let relevant_libs = sess.cstore.used_libraries().into_iter().filter(|l| {
         relevant_lib(sess, l)
-    }).partition(|lib| {
-        lib.kind == NativeLibraryKind::NativeStatic
     });
-    let (staticlibs, others): (Vec<_>, Vec<_>) = pair;
-
-    // Some platforms take hints about whether a library is static or dynamic.
-    // For those that support this, we ensure we pass the option if the library
-    // was flagged "static" (most defaults are dynamic) to ensure that if
-    // libfoo.a and libfoo.so both exist that the right one is chosen.
-    cmd.hint_static();
 
     let search_path = archive_search_paths(sess);
-    for l in staticlibs {
-        // Here we explicitly ask that the entire archive is included into the
-        // result artifact. For more details see #15460, but the gist is that
-        // the linker will strip away any unused objects in the archive if we
-        // don't otherwise explicitly reference them. This can occur for
-        // libraries which are just providing bindings, libraries with generic
-        // functions, etc.
-        cmd.link_whole_staticlib(&l.name.as_str(), &search_path);
-    }
-
-    cmd.hint_dynamic();
-
-    for lib in others {
+    for lib in relevant_libs {
         match lib.kind {
             NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()),
             NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()),
             NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&lib.name.as_str()),
-            NativeLibraryKind::NativeStatic => bug!(),
+            NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&lib.name.as_str(),
+                                                                        &search_path)
         }
     }
 }
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index 80801e8161c..a178d17a7c2 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -43,7 +43,7 @@ impl<'a, 'tcx> LinkerInfo {
     }
 
     pub fn to_linker(&'a self,
-                     cmd: &'a mut Command,
+                     cmd: Command,
                      sess: &'a Session) -> Box<Linker+'a> {
         if sess.target.target.options.is_like_msvc {
             Box::new(MsvcLinker {
@@ -61,7 +61,8 @@ impl<'a, 'tcx> LinkerInfo {
             Box::new(GnuLinker {
                 cmd: cmd,
                 sess: sess,
-                info: self
+                info: self,
+                hinted_static: false,
             }) as Box<Linker>
         }
     }
@@ -93,30 +94,49 @@ pub trait Linker {
     fn no_default_libraries(&mut self);
     fn build_dylib(&mut self, out_filename: &Path);
     fn args(&mut self, args: &[String]);
-    fn hint_static(&mut self);
-    fn hint_dynamic(&mut self);
-    fn whole_archives(&mut self);
-    fn no_whole_archives(&mut self);
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
     fn subsystem(&mut self, subsystem: &str);
+    // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?).
+    fn finalize(&mut self) -> Command;
 }
 
 pub struct GnuLinker<'a> {
-    cmd: &'a mut Command,
+    cmd: Command,
     sess: &'a Session,
-    info: &'a LinkerInfo
+    info: &'a LinkerInfo,
+    hinted_static: bool, // Keeps track of the current hinting mode.
 }
 
 impl<'a> GnuLinker<'a> {
     fn takes_hints(&self) -> bool {
         !self.sess.target.target.options.is_like_osx
     }
+
+    // Some platforms take hints about whether a library is static or dynamic.
+    // For those that support this, we ensure we pass the option if the library
+    // was flagged "static" (most defaults are dynamic) to ensure that if
+    // libfoo.a and libfoo.so both exist that the right one is chosen.
+    fn hint_static(&mut self) {
+        if !self.takes_hints() { return }
+        if !self.hinted_static {
+            self.cmd.arg("-Wl,-Bstatic");
+            self.hinted_static = true;
+        }
+    }
+
+    fn hint_dynamic(&mut self) {
+        if !self.takes_hints() { return }
+        if self.hinted_static {
+            self.cmd.arg("-Wl,-Bdynamic");
+            self.hinted_static = false;
+        }
+    }
 }
 
 impl<'a> Linker for GnuLinker<'a> {
-    fn link_dylib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); }
-    fn link_staticlib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); }
-    fn link_rlib(&mut self, lib: &Path) { self.cmd.arg(lib); }
+    fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg("-l").arg(lib); }
+    fn link_staticlib(&mut self, lib: &str) { self.hint_static(); self.cmd.arg("-l").arg(lib); }
+    fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); }
     fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); }
     fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); }
     fn output_filename(&mut self, path: &Path) { self.cmd.arg("-o").arg(path); }
@@ -125,14 +145,23 @@ impl<'a> Linker for GnuLinker<'a> {
     fn args(&mut self, args: &[String]) { self.cmd.args(args); }
 
     fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
+        self.hint_dynamic();
         self.cmd.arg("-l").arg(lib);
     }
 
     fn link_framework(&mut self, framework: &str) {
+        self.hint_dynamic();
         self.cmd.arg("-framework").arg(framework);
     }
 
+    // Here we explicitly ask that the entire archive is included into the
+    // result artifact. For more details see #15460, but the gist is that
+    // the linker will strip away any unused objects in the archive if we
+    // don't otherwise explicitly reference them. This can occur for
+    // libraries which are just providing bindings, libraries with generic
+    // functions, etc.
     fn link_whole_staticlib(&mut self, lib: &str, search_path: &[PathBuf]) {
+        self.hint_static();
         let target = &self.sess.target.target;
         if !target.options.is_like_osx {
             self.cmd.arg("-Wl,--whole-archive")
@@ -148,6 +177,7 @@ impl<'a> Linker for GnuLinker<'a> {
     }
 
     fn link_whole_rlib(&mut self, lib: &Path) {
+        self.hint_static();
         if self.sess.target.target.options.is_like_osx {
             let mut v = OsString::from("-Wl,-force_load,");
             v.push(lib);
@@ -228,26 +258,6 @@ impl<'a> Linker for GnuLinker<'a> {
         }
     }
 
-    fn whole_archives(&mut self) {
-        if !self.takes_hints() { return }
-        self.cmd.arg("-Wl,--whole-archive");
-    }
-
-    fn no_whole_archives(&mut self) {
-        if !self.takes_hints() { return }
-        self.cmd.arg("-Wl,--no-whole-archive");
-    }
-
-    fn hint_static(&mut self) {
-        if !self.takes_hints() { return }
-        self.cmd.arg("-Wl,-Bstatic");
-    }
-
-    fn hint_dynamic(&mut self) {
-        if !self.takes_hints() { return }
-        self.cmd.arg("-Wl,-Bdynamic");
-    }
-
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
         // If we're compiling a dylib, then we let symbol visibility in object
         // files to take care of whether they're exported or not.
@@ -311,10 +321,17 @@ impl<'a> Linker for GnuLinker<'a> {
     fn subsystem(&mut self, subsystem: &str) {
         self.cmd.arg(&format!("-Wl,--subsystem,{}", subsystem));
     }
+
+    fn finalize(&mut self) -> Command {
+        self.hint_dynamic(); // Reset to default before returning the composed command line.
+        let mut cmd = Command::new("");
+        ::std::mem::swap(&mut cmd, &mut self.cmd);
+        cmd
+    }
 }
 
 pub struct MsvcLinker<'a> {
-    cmd: &'a mut Command,
+    cmd: Command,
     sess: &'a Session,
     info: &'a LinkerInfo
 }
@@ -416,22 +433,6 @@ impl<'a> Linker for MsvcLinker<'a> {
         self.cmd.arg("/DEBUG");
     }
 
-    fn whole_archives(&mut self) {
-        // hints not supported?
-    }
-    fn no_whole_archives(&mut self) {
-        // hints not supported?
-    }
-
-    // On windows static libraries are of the form `foo.lib` and dynamic
-    // libraries are not linked against directly, but rather through their
-    // import libraries also called `foo.lib`. As a result there's no
-    // possibility for a native library to appear both dynamically and
-    // statically in the same folder so we don't have to worry about hints like
-    // we do on Unix platforms.
-    fn hint_static(&mut self) {}
-    fn hint_dynamic(&mut self) {}
-
     // Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
     // export symbols from a dynamic library. When building a dynamic library,
     // however, we're going to want some symbols exported, so this function
@@ -492,10 +493,16 @@ impl<'a> Linker for MsvcLinker<'a> {
             self.cmd.arg("/ENTRY:mainCRTStartup");
         }
     }
+
+    fn finalize(&mut self) -> Command {
+        let mut cmd = Command::new("");
+        ::std::mem::swap(&mut cmd, &mut self.cmd);
+        cmd
+    }
 }
 
 pub struct EmLinker<'a> {
-    cmd: &'a mut Command,
+    cmd: Command,
     sess: &'a Session,
     info: &'a LinkerInfo
 }
@@ -591,22 +598,6 @@ impl<'a> Linker for EmLinker<'a> {
         bug!("building dynamic library is unsupported on Emscripten")
     }
 
-    fn whole_archives(&mut self) {
-        // noop
-    }
-
-    fn no_whole_archives(&mut self) {
-        // noop
-    }
-
-    fn hint_static(&mut self) {
-        // noop
-    }
-
-    fn hint_dynamic(&mut self) {
-        // noop
-    }
-
     fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
         let symbols = &self.info.exports[&crate_type];
 
@@ -640,6 +631,12 @@ impl<'a> Linker for EmLinker<'a> {
     fn subsystem(&mut self, _subsystem: &str) {
         // noop
     }
+
+    fn finalize(&mut self) -> Command {
+        let mut cmd = Command::new("");
+        ::std::mem::swap(&mut cmd, &mut self.cmd);
+        cmd
+    }
 }
 
 fn exported_symbols(scx: &SharedCrateContext,
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index ec45c559363..d204703b775 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -50,7 +50,7 @@ use builder::Builder;
 use callee;
 use common::{C_bool, C_bytes_in_context, C_i32, C_uint};
 use collector::{self, TransItemCollectionMode};
-use common::{C_struct_in_context, C_u64, C_undef};
+use common::{C_struct_in_context, C_u64, C_undef, C_array};
 use common::CrateContext;
 use common::{type_is_zero_size, val_ty};
 use common;
@@ -1187,6 +1187,23 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 }
             }
 
+            // Create the llvm.used variable
+            // This variable has type [N x i8*] and is stored in the llvm.metadata section
+            if !ccx.used_statics().borrow().is_empty() {
+                let name = CString::new("llvm.used").unwrap();
+                let section = CString::new("llvm.metadata").unwrap();
+                let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow());
+
+                unsafe {
+                    let g = llvm::LLVMAddGlobal(ccx.llmod(),
+                                                val_ty(array).to_ref(),
+                                                name.as_ptr());
+                    llvm::LLVMSetInitializer(g, array);
+                    llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
+                    llvm::LLVMSetSection(g, section.as_ptr());
+                }
+            }
+
             // Finalize debuginfo
             if ccx.sess().opts.debuginfo != NoDebugInfo {
                 debuginfo::finalize(&ccx);
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 0c3d211912a..daf1a1ba95f 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -276,6 +276,12 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
         base::set_link_section(ccx, g, attrs);
 
+        if attr::contains_name(attrs, "used") {
+            // This static will be stored in the llvm.used variable which is an array of i8*
+            let cast = llvm::LLVMConstPointerCast(g, Type::i8p(ccx).to_ref());
+            ccx.used_statics().borrow_mut().push(cast);
+        }
+
         Ok(g)
     }
 }
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 73602dc420b..afb94f546ab 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -132,6 +132,10 @@ pub struct LocalCrateContext<'tcx> {
     /// to constants.)
     statics_to_rauw: RefCell<Vec<(ValueRef, ValueRef)>>,
 
+    /// Statics that will be placed in the llvm.used variable
+    /// See http://llvm.org/docs/LangRef.html#the-llvm-used-global-variable for details
+    used_statics: RefCell<Vec<ValueRef>>,
+
     lltypes: RefCell<FxHashMap<Ty<'tcx>, Type>>,
     llsizingtypes: RefCell<FxHashMap<Ty<'tcx>, Type>>,
     type_hashcodes: RefCell<FxHashMap<Ty<'tcx>, String>>,
@@ -587,6 +591,7 @@ impl<'tcx> LocalCrateContext<'tcx> {
                 impl_method_cache: RefCell::new(FxHashMap()),
                 closure_bare_wrapper_cache: RefCell::new(FxHashMap()),
                 statics_to_rauw: RefCell::new(Vec::new()),
+                used_statics: RefCell::new(Vec::new()),
                 lltypes: RefCell::new(FxHashMap()),
                 llsizingtypes: RefCell::new(FxHashMap()),
                 type_hashcodes: RefCell::new(FxHashMap()),
@@ -754,6 +759,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         &self.local().statics_to_rauw
     }
 
+    pub fn used_statics<'a>(&'a self) -> &'a RefCell<Vec<ValueRef>> {
+        &self.local().used_statics
+    }
+
     pub fn lltypes<'a>(&'a self) -> &'a RefCell<FxHashMap<Ty<'tcx>, Type>> {
         &self.local().lltypes
     }
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 226d40948c4..d69f31a4504 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -762,7 +762,6 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
             let llretty = Type::struct_(ccx, &[Type::i8p(ccx), Type::i32(ccx)], false);
             let slot = bcx.alloca(llretty, "personalityslot");
             self.llpersonalityslot = Some(slot);
-            Lifetime::Start.call(bcx, slot);
             slot
         }
     }
@@ -794,6 +793,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
         let llretval = bcx.landing_pad(llretty, llpersonality, 1, self.llfn);
         bcx.set_cleanup(llretval);
         let slot = self.get_personality_slot(&bcx);
+        Lifetime::Start.call(&bcx, slot);
         bcx.store(llretval, slot, None);
         bcx.br(target_bb);
         bcx.llbb()
diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs
index 67ee7ef5865..4b975d7b324 100644
--- a/src/librustc_typeck/check/method/suggest.rs
+++ b/src/librustc_typeck/check/method/suggest.rs
@@ -196,19 +196,23 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                                     let field_ty = field.ty(tcx, substs);
 
-                                    if self.is_fn_ty(&field_ty, span) {
-                                        err.help(&format!("use `({0}.{1})(...)` if you \
-                                                           meant to call the function \
-                                                           stored in the `{1}` field",
-                                                          expr_string,
-                                                          item_name));
+                                    if tcx.vis_is_accessible_from(field.vis, self.body_id) {
+                                        if self.is_fn_ty(&field_ty, span) {
+                                            err.help(&format!("use `({0}.{1})(...)` if you \
+                                                               meant to call the function \
+                                                               stored in the `{1}` field",
+                                                              expr_string,
+                                                              item_name));
+                                        } else {
+                                            err.help(&format!("did you mean to write `{0}.{1}` \
+                                                               instead of `{0}.{1}(...)`?",
+                                                              expr_string,
+                                                              item_name));
+                                        }
+                                        err.span_label(span, &"field, not a method");
                                     } else {
-                                        err.help(&format!("did you mean to write `{0}.{1}` \
-                                                           instead of `{0}.{1}(...)`?",
-                                                          expr_string,
-                                                          item_name));
+                                        err.span_label(span, &"private field, not a method");
                                     }
-                                    err.span_label(span, &"field, not a method");
                                     break;
                                 }
                             }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index aaa3cf0f29e..c995b7e9284 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -3884,7 +3884,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                           element_ty
                       }
                       None => {
-                          self.check_expr_has_type(&idx, self.tcx.types.err);
                           let mut err = self.type_error_struct(
                               expr.span,
                               |actual| {
diff --git a/src/librustc_typeck/check/op.rs b/src/librustc_typeck/check/op.rs
index f492ab12e3f..cc33bd8754d 100644
--- a/src/librustc_typeck/check/op.rs
+++ b/src/librustc_typeck/check/op.rs
@@ -184,9 +184,14 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
         // particularly for things like `String + &String`.
         let rhs_ty_var = self.next_ty_var(TypeVariableOrigin::MiscVariable(rhs_expr.span));
 
-        let return_ty = match self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var],
-                                                    Symbol::intern(name), trait_def_id,
-                                                    lhs_expr) {
+        let return_ty = self.lookup_op_method(expr, lhs_ty, vec![rhs_ty_var],
+                                              Symbol::intern(name), trait_def_id,
+                                              lhs_expr);
+
+        // see `NB` above
+        let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var);
+
+        let return_ty = match return_ty {
             Ok(return_ty) => return_ty,
             Err(()) => {
                 // error types are considered "builtin"
@@ -209,7 +214,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
 
                         if let TypeVariants::TyRef(_, ref ty_mut) = lhs_ty.sty {
                             if !self.infcx.type_moves_by_default(ty_mut.ty, lhs_expr.span) &&
-                                self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty_var],
+                                self.lookup_op_method(expr, ty_mut.ty, vec![rhs_ty],
                                     Symbol::intern(name), trait_def_id,
                                     lhs_expr).is_ok() {
                                 err.note(
@@ -240,7 +245,7 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                         if let Some(missing_trait) = missing_trait {
                             if missing_trait == "std::ops::Add" &&
                                 self.check_str_addition(expr, lhs_expr, lhs_ty,
-                                                         rhs_expr, rhs_ty_var, &mut err) {
+                                                         rhs_expr, rhs_ty, &mut err) {
                                 // This has nothing here because it means we did string
                                 // concatenation (e.g. "Hello " + "World!"). This means
                                 // we don't want the note in the else clause to be emitted
@@ -257,9 +262,6 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
             }
         };
 
-        // see `NB` above
-        self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var);
-
         (rhs_ty_var, return_ty)
     }
 
@@ -268,12 +270,11 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
                           lhs_expr: &'gcx hir::Expr,
                           lhs_ty: Ty<'tcx>,
                           rhs_expr: &'gcx hir::Expr,
-                          rhs_ty_var: Ty<'tcx>,
+                          rhs_ty: Ty<'tcx>,
                           mut err: &mut errors::DiagnosticBuilder) -> bool {
         // If this function returns true it means a note was printed, so we don't need
         // to print the normal "implementation of `std::ops::Add` might be missing" note
         let mut is_string_addition = false;
-        let rhs_ty = self.check_expr_coercable_to_type(rhs_expr, rhs_ty_var);
         if let TyRef(_, l_ty) = lhs_ty.sty {
             if let TyRef(_, r_ty) = rhs_ty.sty {
                 if l_ty.ty.sty == TyStr && r_ty.ty.sty == TyStr {
diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
index 4b36072243c..33280fb931a 100644
--- a/src/librustc_typeck/coherence/inherent_impls_overlap.rs
+++ b/src/librustc_typeck/coherence/inherent_impls_overlap.rs
@@ -11,7 +11,6 @@
 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
 use rustc::hir;
 use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use rustc::lint;
 use rustc::traits::{self, Reveal};
 use rustc::ty::{self, TyCtxt};
 
@@ -53,12 +52,16 @@ impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
 
             for &item2 in &impl_items2[..] {
                 if (name, namespace) == name_and_namespace(item2) {
-                    let msg = format!("duplicate definitions with name `{}`", name);
-                    let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
-                    self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
-                                           node_id,
-                                           self.tcx.span_of_impl(item1).unwrap(),
-                                           msg);
+                    struct_span_err!(self.tcx.sess,
+                                     self.tcx.span_of_impl(item1).unwrap(),
+                                     E0592,
+                                     "duplicate definitions with name `{}`",
+                                     name)
+                        .span_label(self.tcx.span_of_impl(item1).unwrap(),
+                                    &format!("duplicate definitions for `{}`", name))
+                        .span_label(self.tcx.span_of_impl(item2).unwrap(),
+                                    &format!("other definition for `{}`", name))
+                        .emit();
                 }
             }
         }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 117cfbabb52..1e687d63f58 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -16,10 +16,10 @@
 //! of `fmt::Display`. Example usage:
 //!
 //! ```rust,ignore
-//! use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle};
+//! use rustdoc::html::markdown::Markdown;
 //!
 //! let s = "My *markdown* _text_";
-//! let html = format!("{}", Markdown(s, MarkdownOutputStyle::Fancy));
+//! let html = format!("{}", Markdown(s));
 //! // ... something using html
 //! ```
 
@@ -27,6 +27,7 @@
 
 use std::ascii::AsciiExt;
 use std::cell::RefCell;
+use std::collections::{HashMap, VecDeque};
 use std::default::Default;
 use std::fmt::{self, Write};
 use std::str;
@@ -36,43 +37,23 @@ use syntax::codemap::Span;
 use html::render::derive_id;
 use html::toc::TocBuilder;
 use html::highlight;
-use html::escape::Escape;
 use test;
 
-use pulldown_cmark::{self, Event, Parser, Tag};
-
-#[derive(Copy, Clone)]
-pub enum MarkdownOutputStyle {
-    Compact,
-    Fancy,
-}
-
-impl MarkdownOutputStyle {
-    pub fn is_compact(&self) -> bool {
-        match *self {
-            MarkdownOutputStyle::Compact => true,
-            _ => false,
-        }
-    }
-
-    pub fn is_fancy(&self) -> bool {
-        match *self {
-            MarkdownOutputStyle::Fancy => true,
-            _ => false,
-        }
-    }
-}
+use pulldown_cmark::{html, Event, Tag, Parser};
+use pulldown_cmark::{Options, OPTION_ENABLE_FOOTNOTES, OPTION_ENABLE_TABLES};
 
 /// A unit struct which has the `fmt::Display` trait implemented. When
 /// formatted, this struct will emit the HTML corresponding to the rendered
 /// version of the contained markdown string.
 // The second parameter is whether we need a shorter version or not.
-pub struct Markdown<'a>(pub &'a str, pub MarkdownOutputStyle);
+pub struct Markdown<'a>(pub &'a str);
 /// A unit struct like `Markdown`, that renders the markdown with a
 /// table of contents.
 pub struct MarkdownWithToc<'a>(pub &'a str);
 /// A unit struct like `Markdown`, that renders the markdown escaping HTML tags.
 pub struct MarkdownHtml<'a>(pub &'a str);
+/// A unit struct like `Markdown`, that renders only the first paragraph.
+pub struct MarkdownSummaryLine<'a>(pub &'a str);
 
 /// Returns Some(code) if `s` is a line that should be stripped from
 /// documentation but used in example code. `code` is the portion of
@@ -89,12 +70,21 @@ fn stripped_filtered_line<'a>(s: &'a str) -> Option<&'a str> {
     }
 }
 
-/// Returns a new string with all consecutive whitespace collapsed into
-/// single spaces.
+/// Convert chars from a title for an id.
 ///
-/// Any leading or trailing whitespace will be trimmed.
-fn collapse_whitespace(s: &str) -> String {
-    s.split_whitespace().collect::<Vec<_>>().join(" ")
+/// "Hello, world!" -> "hello-world"
+fn slugify(c: char) -> Option<char> {
+    if c.is_alphanumeric() || c == '-' || c == '_' {
+        if c.is_ascii() {
+            Some(c.to_ascii_lowercase())
+        } else {
+            Some(c)
+        }
+    } else if c.is_whitespace() && c.is_ascii() {
+        Some('-')
+    } else {
+        None
+    }
 }
 
 // Information about the playground if a URL has been specified, containing an
@@ -103,72 +93,50 @@ thread_local!(pub static PLAYGROUND: RefCell<Option<(Option<String>, String)>> =
     RefCell::new(None)
 });
 
-macro_rules! event_loop_break {
-    ($parser:expr, $toc_builder:expr, $shorter:expr, $buf:expr, $escape:expr, $id:expr,
-     $($end_event:pat)|*) => {{
-        fn inner(id: &mut Option<&mut String>, s: &str) {
-            if let Some(ref mut id) = *id {
-                id.push_str(s);
-            }
+/// Adds syntax highlighting and playground Run buttons to rust code blocks.
+struct CodeBlocks<'a, I: Iterator<Item = Event<'a>>> {
+    inner: I,
+}
+
+impl<'a, I: Iterator<Item = Event<'a>>> CodeBlocks<'a, I> {
+    fn new(iter: I) -> Self {
+        CodeBlocks {
+            inner: iter,
         }
-        while let Some(event) = $parser.next() {
-            match event {
-                $($end_event)|* => break,
-                Event::Text(ref s) => {
-                    inner($id, s);
-                    if $escape {
-                        $buf.push_str(&format!("{}", Escape(s)));
-                    } else {
-                        $buf.push_str(s);
-                    }
-                }
-                Event::SoftBreak | Event::HardBreak if !$buf.is_empty() => {
-                    $buf.push(' ');
-                }
-                x => {
-                    looper($parser, &mut $buf, Some(x), $toc_builder, $shorter, $id);
-                }
+    }
+}
+
+impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'a, I> {
+    type Item = Event<'a>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let event = self.inner.next();
+        if let Some(Event::Start(Tag::CodeBlock(lang))) = event {
+            if !LangString::parse(&lang).rust {
+                return Some(Event::Start(Tag::CodeBlock(lang)));
             }
+        } else {
+            return event;
         }
-    }}
-}
 
-pub fn render(w: &mut fmt::Formatter,
-              s: &str,
-              print_toc: bool,
-              shorter: MarkdownOutputStyle) -> fmt::Result {
-    fn code_block(parser: &mut Parser, buffer: &mut String, lang: &str) {
         let mut origtext = String::new();
-        while let Some(event) = parser.next() {
+        for event in &mut self.inner {
             match event {
-                Event::End(Tag::CodeBlock(_)) => break,
+                Event::End(Tag::CodeBlock(..)) => break,
                 Event::Text(ref s) => {
                     origtext.push_str(s);
                 }
                 _ => {}
             }
         }
-        let origtext = origtext.trim_left();
-        debug!("docblock: ==============\n{:?}\n=======", origtext);
-
         let lines = origtext.lines().filter(|l| {
             stripped_filtered_line(*l).is_none()
         });
         let text = lines.collect::<Vec<&str>>().join("\n");
-        let block_info = if lang.is_empty() {
-            LangString::all_false()
-        } else {
-            LangString::parse(lang)
-        };
-        if !block_info.rust {
-            buffer.push_str(&format!("<pre><code class=\"language-{}\">{}</code></pre>",
-                            lang, text));
-            return
-        }
         PLAYGROUND.with(|play| {
             // insert newline to clearly separate it from the
             // previous block so we can shorten the html output
-            buffer.push('\n');
+            let mut s = String::from("\n");
             let playground_button = play.borrow().as_ref().and_then(|&(ref krate, ref url)| {
                 if url.is_empty() {
                     return None;
@@ -178,7 +146,7 @@ pub fn render(w: &mut fmt::Formatter,
                 }).collect::<Vec<&str>>().join("\n");
                 let krate = krate.as_ref().map(|s| &**s);
                 let test = test::maketest(&test, krate, false,
-                                          &Default::default());
+                                        &Default::default());
                 let channel = if test.contains("#![feature(") {
                     "&amp;version=nightly"
                 } else {
@@ -207,271 +175,186 @@ pub fn render(w: &mut fmt::Formatter,
                     url, test_escaped, channel
                 ))
             });
-            buffer.push_str(&highlight::render_with_highlighting(
-                            &text,
-                            Some("rust-example-rendered"),
-                            None,
-                            playground_button.as_ref().map(String::as_str)));
-        });
-    }
-
-    fn heading(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-               shorter: MarkdownOutputStyle, level: i32) {
-        let mut ret = String::new();
-        let mut id = String::new();
-        event_loop_break!(parser, toc_builder, shorter, ret, true, &mut Some(&mut id),
-                          Event::End(Tag::Header(_)));
-        ret = ret.trim_right().to_owned();
-
-        let id = id.chars().filter_map(|c| {
-            if c.is_alphanumeric() || c == '-' || c == '_' {
-                if c.is_ascii() {
-                    Some(c.to_ascii_lowercase())
-                } else {
-                    Some(c)
-                }
-            } else if c.is_whitespace() && c.is_ascii() {
-                Some('-')
-            } else {
-                None
-            }
-        }).collect::<String>();
-
-        let id = derive_id(id);
-
-        let sec = toc_builder.as_mut().map_or("".to_owned(), |builder| {
-            format!("{} ", builder.push(level as u32, ret.clone(), id.clone()))
-        });
-
-        // Render the HTML
-        buffer.push_str(&format!("<h{lvl} id=\"{id}\" class=\"section-header\">\
-                                  <a href=\"#{id}\">{sec}{}</a></h{lvl}>",
-                                 ret, lvl = level, id = id, sec = sec));
-    }
-
-    fn inline_code(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-                   shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) {
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, false, id, Event::End(Tag::Code));
-        buffer.push_str(&format!("<code>{}</code>",
-                                 Escape(&collapse_whitespace(content.trim_right()))));
+            s.push_str(&highlight::render_with_highlighting(
+                        &text,
+                        Some("rust-example-rendered"),
+                        None,
+                        playground_button.as_ref().map(String::as_str)));
+            Some(Event::Html(s.into()))
+        })
     }
+}
 
-    fn link(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-            shorter: MarkdownOutputStyle, url: &str, mut title: String,
-            id: &mut Option<&mut String>) {
-        event_loop_break!(parser, toc_builder, shorter, title, true, id,
-                          Event::End(Tag::Link(_, _)));
-        buffer.push_str(&format!("<a href=\"{}\">{}</a>", url, title));
-    }
+/// Make headings links with anchor ids and build up TOC.
+struct HeadingLinks<'a, 'b, I: Iterator<Item = Event<'a>>> {
+    inner: I,
+    toc: Option<&'b mut TocBuilder>,
+    buf: VecDeque<Event<'a>>,
+}
 
-    fn paragraph(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-                 shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) {
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, true, id,
-                          Event::End(Tag::Paragraph));
-        buffer.push_str(&format!("<p>{}</p>", content.trim_right()));
+impl<'a, 'b, I: Iterator<Item = Event<'a>>> HeadingLinks<'a, 'b, I> {
+    fn new(iter: I, toc: Option<&'b mut TocBuilder>) -> Self {
+        HeadingLinks {
+            inner: iter,
+            toc: toc,
+            buf: VecDeque::new(),
+        }
     }
+}
 
-    fn table_cell(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-                  shorter: MarkdownOutputStyle) {
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, true, &mut None,
-                          Event::End(Tag::TableHead) |
-                              Event::End(Tag::Table(_)) |
-                              Event::End(Tag::TableRow) |
-                              Event::End(Tag::TableCell));
-        buffer.push_str(&format!("<td>{}</td>", content.trim()));
-    }
+impl<'a, 'b, I: Iterator<Item = Event<'a>>> Iterator for HeadingLinks<'a, 'b, I> {
+    type Item = Event<'a>;
 
-    fn table_row(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-                 shorter: MarkdownOutputStyle) {
-        let mut content = String::new();
-        while let Some(event) = parser.next() {
-            match event {
-                Event::End(Tag::TableHead) |
-                    Event::End(Tag::Table(_)) |
-                    Event::End(Tag::TableRow) => break,
-                Event::Start(Tag::TableCell) => {
-                    table_cell(parser, &mut content, toc_builder, shorter);
-                }
-                x => {
-                    looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None);
-                }
-            }
+    fn next(&mut self) -> Option<Self::Item> {
+        if let Some(e) = self.buf.pop_front() {
+            return Some(e);
         }
-        buffer.push_str(&format!("<tr>{}</tr>", content));
-    }
 
-    fn table_head(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-                  shorter: MarkdownOutputStyle) {
-        let mut content = String::new();
-        while let Some(event) = parser.next() {
-            match event {
-                Event::End(Tag::TableHead) | Event::End(Tag::Table(_)) => break,
-                Event::Start(Tag::TableCell) => {
-                    table_cell(parser, &mut content, toc_builder, shorter);
-                }
-                x => {
-                    looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None);
+        let event = self.inner.next();
+        if let Some(Event::Start(Tag::Header(level))) = event {
+            let mut id = String::new();
+            for event in &mut self.inner {
+                match event {
+                    Event::End(Tag::Header(..)) => break,
+                    Event::Text(ref text) => id.extend(text.chars().filter_map(slugify)),
+                    _ => {},
                 }
+                self.buf.push_back(event);
             }
-        }
-        if !content.is_empty() {
-            buffer.push_str(&format!("<thead><tr>{}</tr></thead>", content.replace("td>", "th>")));
-        }
-    }
+            let id = derive_id(id);
 
-    fn table(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-             shorter: MarkdownOutputStyle) {
-        let mut content = String::new();
-        let mut rows = String::new();
-        while let Some(event) = parser.next() {
-            match event {
-                Event::End(Tag::Table(_)) => break,
-                Event::Start(Tag::TableHead) => {
-                    table_head(parser, &mut content, toc_builder, shorter);
-                }
-                Event::Start(Tag::TableRow) => {
-                    table_row(parser, &mut rows, toc_builder, shorter);
-                }
-                _ => {}
+            if let Some(ref mut builder) = self.toc {
+                let mut html_header = String::new();
+                html::push_html(&mut html_header, self.buf.iter().cloned());
+                let sec = builder.push(level as u32, html_header, id.clone());
+                self.buf.push_front(Event::InlineHtml(format!("{} ", sec).into()));
             }
+
+            self.buf.push_back(Event::InlineHtml(format!("</a></h{}>", level).into()));
+
+            let start_tags = format!("<h{level} id=\"{id}\" class=\"section-header\">\
+                                      <a href=\"#{id}\">",
+                                     id = id,
+                                     level = level);
+            return Some(Event::InlineHtml(start_tags.into()));
         }
-        buffer.push_str(&format!("<table>{}{}</table>",
-                                 content,
-                                 if shorter.is_compact() || rows.is_empty() {
-                                     String::new()
-                                 } else {
-                                     format!("<tbody>{}</tbody>", rows)
-                                 }));
+        event
     }
+}
 
-    fn blockquote(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-                  shorter: MarkdownOutputStyle) {
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, true, &mut None,
-                          Event::End(Tag::BlockQuote));
-        buffer.push_str(&format!("<blockquote>{}</blockquote>", content.trim_right()));
-    }
+/// Extracts just the first paragraph.
+struct SummaryLine<'a, I: Iterator<Item = Event<'a>>> {
+    inner: I,
+    started: bool,
+    depth: u32,
+}
 
-    fn list_item(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-                 shorter: MarkdownOutputStyle) {
-        let mut content = String::new();
-        while let Some(event) = parser.next() {
-            match event {
-                Event::End(Tag::Item) => break,
-                Event::Text(ref s) => {
-                    content.push_str(&format!("{}", Escape(s)));
-                }
-                x => {
-                    looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None);
-                }
-            }
+impl<'a, I: Iterator<Item = Event<'a>>> SummaryLine<'a, I> {
+    fn new(iter: I) -> Self {
+        SummaryLine {
+            inner: iter,
+            started: false,
+            depth: 0,
         }
-        buffer.push_str(&format!("<li>{}</li>", content));
     }
+}
 
-    fn list(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-            shorter: MarkdownOutputStyle) {
-        let mut content = String::new();
-        while let Some(event) = parser.next() {
-            match event {
-                Event::End(Tag::List(_)) => break,
-                Event::Start(Tag::Item) => {
-                    list_item(parser, &mut content, toc_builder, shorter);
-                }
-                x => {
-                    looper(parser, &mut content, Some(x), toc_builder, shorter, &mut None);
-                }
-            }
+impl<'a, I: Iterator<Item = Event<'a>>> Iterator for SummaryLine<'a, I> {
+    type Item = Event<'a>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        if self.started && self.depth == 0 {
+            return None;
+        }
+        if !self.started {
+            self.started = true;
         }
-        buffer.push_str(&format!("<ul>{}</ul>", content));
+        let event = self.inner.next();
+        match event {
+            Some(Event::Start(..)) => self.depth += 1,
+            Some(Event::End(..)) => self.depth -= 1,
+            _ => {}
+        }
+        event
     }
+}
 
-    fn emphasis(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-                shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) {
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, false, id,
-                          Event::End(Tag::Emphasis));
-        buffer.push_str(&format!("<em>{}</em>", content));
-    }
+/// Moves all footnote definitions to the end and add back links to the
+/// references.
+struct Footnotes<'a, I: Iterator<Item = Event<'a>>> {
+    inner: I,
+    footnotes: HashMap<String, (Vec<Event<'a>>, u16)>,
+}
 
-    fn strong(parser: &mut Parser, buffer: &mut String, toc_builder: &mut Option<TocBuilder>,
-              shorter: MarkdownOutputStyle, id: &mut Option<&mut String>) {
-        let mut content = String::new();
-        event_loop_break!(parser, toc_builder, shorter, content, false, id,
-                          Event::End(Tag::Strong));
-        buffer.push_str(&format!("<strong>{}</strong>", content));
+impl<'a, I: Iterator<Item = Event<'a>>> Footnotes<'a, I> {
+    fn new(iter: I) -> Self {
+        Footnotes {
+            inner: iter,
+            footnotes: HashMap::new(),
+        }
     }
+    fn get_entry(&mut self, key: &str) -> &mut (Vec<Event<'a>>, u16) {
+        let new_id = self.footnotes.keys().count() + 1;
+        let key = key.to_owned();
+        self.footnotes.entry(key).or_insert((Vec::new(), new_id as u16))
+    }
+}
 
-    fn looper<'a>(parser: &'a mut Parser, buffer: &mut String, next_event: Option<Event<'a>>,
-                  toc_builder: &mut Option<TocBuilder>, shorter: MarkdownOutputStyle,
-                  id: &mut Option<&mut String>) -> bool {
-        if let Some(event) = next_event {
-            match event {
-                Event::Start(Tag::CodeBlock(lang)) => {
-                    code_block(parser, buffer, &*lang);
-                }
-                Event::Start(Tag::Header(level)) => {
-                    heading(parser, buffer, toc_builder, shorter, level);
-                }
-                Event::Start(Tag::Code) => {
-                    inline_code(parser, buffer, toc_builder, shorter, id);
-                }
-                Event::Start(Tag::Paragraph) => {
-                    paragraph(parser, buffer, toc_builder, shorter, id);
-                }
-                Event::Start(Tag::Link(ref url, ref t)) => {
-                    link(parser, buffer, toc_builder, shorter, url, t.as_ref().to_owned(), id);
-                }
-                Event::Start(Tag::Table(_)) => {
-                    table(parser, buffer, toc_builder, shorter);
-                }
-                Event::Start(Tag::BlockQuote) => {
-                    blockquote(parser, buffer, toc_builder, shorter);
-                }
-                Event::Start(Tag::List(_)) => {
-                    list(parser, buffer, toc_builder, shorter);
-                }
-                Event::Start(Tag::Emphasis) => {
-                    emphasis(parser, buffer, toc_builder, shorter, id);
-                }
-                Event::Start(Tag::Strong) => {
-                    strong(parser, buffer, toc_builder, shorter, id);
-                }
-                Event::Html(h) | Event::InlineHtml(h) => {
-                    buffer.push_str(&*h);
+impl<'a, I: Iterator<Item = Event<'a>>> Iterator for Footnotes<'a, I> {
+    type Item = Event<'a>;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        loop {
+            match self.inner.next() {
+                Some(Event::FootnoteReference(ref reference)) => {
+                    let entry = self.get_entry(&reference);
+                    let reference = format!("<sup id=\"supref{0}\"><a href=\"#ref{0}\">{0}\
+                                             </a></sup>",
+                                            (*entry).1);
+                    return Some(Event::Html(reference.into()));
+                }
+                Some(Event::Start(Tag::FootnoteDefinition(def))) => {
+                    let mut content = Vec::new();
+                    for event in &mut self.inner {
+                        if let Event::End(Tag::FootnoteDefinition(..)) = event {
+                            break;
+                        }
+                        content.push(event);
+                    }
+                    let entry = self.get_entry(&def);
+                    (*entry).0 = content;
+                }
+                Some(e) => return Some(e),
+                None => {
+                    if !self.footnotes.is_empty() {
+                        let mut v: Vec<_> = self.footnotes.drain().map(|(_, x)| x).collect();
+                        v.sort_by(|a, b| a.1.cmp(&b.1));
+                        let mut ret = String::from("<div class=\"footnotes\"><hr><ol>");
+                        for (mut content, id) in v {
+                            write!(ret, "<li id=\"ref{}\">", id).unwrap();
+                            let mut is_paragraph = false;
+                            if let Some(&Event::End(Tag::Paragraph)) = content.last() {
+                                content.pop();
+                                is_paragraph = true;
+                            }
+                            html::push_html(&mut ret, content.into_iter());
+                            write!(ret,
+                                   "&nbsp;<a href=\"#supref{}\" rev=\"footnote\">↩</a>",
+                                   id).unwrap();
+                            if is_paragraph {
+                                ret.push_str("</p>");
+                            }
+                            ret.push_str("</li>");
+                        }
+                        ret.push_str("</ol></div>");
+                        return Some(Event::Html(ret.into()));
+                    } else {
+                        return None;
+                    }
                 }
-                _ => {}
             }
-            shorter.is_fancy()
-        } else {
-            false
         }
     }
-
-    let mut toc_builder = if print_toc {
-        Some(TocBuilder::new())
-    } else {
-        None
-    };
-    let mut buffer = String::new();
-    let mut parser = Parser::new_ext(s, pulldown_cmark::OPTION_ENABLE_TABLES);
-    loop {
-        let next_event = parser.next();
-        if !looper(&mut parser, &mut buffer, next_event, &mut toc_builder, shorter, &mut None) {
-            break
-        }
-    }
-    let mut ret = toc_builder.map_or(Ok(()), |builder| {
-        write!(w, "<nav id=\"TOC\">{}</nav>", builder.into_toc())
-    });
-
-    if ret.is_ok() {
-        ret = w.write_str(&buffer);
-    }
-    ret
 }
 
 pub fn find_testable_code(doc: &str, tests: &mut ::test::Collector, position: Span) {
@@ -618,17 +501,45 @@ impl LangString {
 
 impl<'a> fmt::Display for Markdown<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
-        let Markdown(md, shorter) = *self;
+        let Markdown(md) = *self;
         // This is actually common enough to special-case
         if md.is_empty() { return Ok(()) }
-        render(fmt, md, false, shorter)
+
+        let mut opts = Options::empty();
+        opts.insert(OPTION_ENABLE_TABLES);
+        opts.insert(OPTION_ENABLE_FOOTNOTES);
+
+        let p = Parser::new_ext(md, opts);
+
+        let mut s = String::with_capacity(md.len() * 3 / 2);
+
+        html::push_html(&mut s,
+                        Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
+
+        fmt.write_str(&s)
     }
 }
 
 impl<'a> fmt::Display for MarkdownWithToc<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
         let MarkdownWithToc(md) = *self;
-        render(fmt, md, true, MarkdownOutputStyle::Fancy)
+
+        let mut opts = Options::empty();
+        opts.insert(OPTION_ENABLE_TABLES);
+        opts.insert(OPTION_ENABLE_FOOTNOTES);
+
+        let p = Parser::new_ext(md, opts);
+
+        let mut s = String::with_capacity(md.len() * 3 / 2);
+
+        let mut toc = TocBuilder::new();
+
+        html::push_html(&mut s,
+                        Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, Some(&mut toc)))));
+
+        write!(fmt, "<nav id=\"TOC\">{}</nav>", toc.into_toc())?;
+
+        fmt.write_str(&s)
     }
 }
 
@@ -637,7 +548,41 @@ impl<'a> fmt::Display for MarkdownHtml<'a> {
         let MarkdownHtml(md) = *self;
         // This is actually common enough to special-case
         if md.is_empty() { return Ok(()) }
-        render(fmt, md, false, MarkdownOutputStyle::Fancy)
+
+        let mut opts = Options::empty();
+        opts.insert(OPTION_ENABLE_TABLES);
+        opts.insert(OPTION_ENABLE_FOOTNOTES);
+
+        let p = Parser::new_ext(md, opts);
+
+        // Treat inline HTML as plain text.
+        let p = p.map(|event| match event {
+            Event::Html(text) | Event::InlineHtml(text) => Event::Text(text),
+            _ => event
+        });
+
+        let mut s = String::with_capacity(md.len() * 3 / 2);
+
+        html::push_html(&mut s,
+                        Footnotes::new(CodeBlocks::new(HeadingLinks::new(p, None))));
+
+        fmt.write_str(&s)
+    }
+}
+
+impl<'a> fmt::Display for MarkdownSummaryLine<'a> {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        let MarkdownSummaryLine(md) = *self;
+        // This is actually common enough to special-case
+        if md.is_empty() { return Ok(()) }
+
+        let p = Parser::new(md);
+
+        let mut s = String::new();
+
+        html::push_html(&mut s, SummaryLine::new(p));
+
+        fmt.write_str(&s)
     }
 }
 
@@ -659,14 +604,10 @@ pub fn plain_summary_line(md: &str) -> String {
             let next_event = next_event.unwrap();
             let (ret, is_in) = match next_event {
                 Event::Start(Tag::Paragraph) => (None, 1),
-                Event::Start(Tag::Link(_, ref t)) if !self.is_first => {
-                    (Some(t.as_ref().to_owned()), 1)
-                }
                 Event::Start(Tag::Code) => (Some("`".to_owned()), 1),
                 Event::End(Tag::Code) => (Some("`".to_owned()), -1),
                 Event::Start(Tag::Header(_)) => (None, 1),
                 Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0),
-                Event::End(Tag::Link(_, ref t)) => (Some(t.as_ref().to_owned()), -1),
                 Event::End(Tag::Paragraph) | Event::End(Tag::Header(_)) => (None, -1),
                 _ => (None, 0),
             };
@@ -697,7 +638,7 @@ pub fn plain_summary_line(md: &str) -> String {
 
 #[cfg(test)]
 mod tests {
-    use super::{LangString, Markdown, MarkdownHtml, MarkdownOutputStyle};
+    use super::{LangString, Markdown, MarkdownHtml};
     use super::plain_summary_line;
     use html::render::reset_ids;
 
@@ -737,14 +678,14 @@ mod tests {
     #[test]
     fn issue_17736() {
         let markdown = "# title";
-        format!("{}", Markdown(markdown, MarkdownOutputStyle::Fancy));
+        format!("{}", Markdown(markdown));
         reset_ids(true);
     }
 
     #[test]
     fn test_header() {
         fn t(input: &str, expect: &str) {
-            let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy));
+            let output = format!("{}", Markdown(input));
             assert_eq!(output, expect, "original: {}", input);
             reset_ids(true);
         }
@@ -766,7 +707,7 @@ mod tests {
     #[test]
     fn test_header_ids_multiple_blocks() {
         fn t(input: &str, expect: &str) {
-            let output = format!("{}", Markdown(input, MarkdownOutputStyle::Fancy));
+            let output = format!("{}", Markdown(input));
             assert_eq!(output, expect, "original: {}", input);
         }
 
@@ -797,6 +738,7 @@ mod tests {
         }
 
         t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)");
+        t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)");
         t("code `let x = i32;` ...", "code `let x = i32;` ...");
         t("type `Type<'static>` ...", "type `Type<'static>` ...");
         t("# top header", "top header");
@@ -810,7 +752,8 @@ mod tests {
             assert_eq!(output, expect, "original: {}", input);
         }
 
-        t("`Struct<'a, T>`", "<p><code>Struct&lt;&#39;a, T&gt;</code></p>");
-        t("Struct<'a, T>", "<p>Struct&lt;&#39;a, T&gt;</p>");
+        t("`Struct<'a, T>`", "<p><code>Struct&lt;'a, T&gt;</code></p>\n");
+        t("Struct<'a, T>", "<p>Struct&lt;'a, T&gt;</p>\n");
+        t("Struct<br>", "<p>Struct&lt;br&gt;</p>\n");
     }
 }
diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs
index f0b624105e3..1e1202f0400 100644
--- a/src/librustdoc/html/render.rs
+++ b/src/librustdoc/html/render.rs
@@ -72,7 +72,7 @@ use html::format::{TyParamBounds, WhereClause, href, AbiSpace};
 use html::format::{VisSpace, Method, UnsafetySpace, MutableSpace};
 use html::format::fmt_impl_for_trait_page;
 use html::item_type::ItemType;
-use html::markdown::{self, Markdown, MarkdownHtml, MarkdownOutputStyle};
+use html::markdown::{self, Markdown, MarkdownHtml, MarkdownSummaryLine};
 use html::{highlight, layout};
 
 /// A pair of name and its optional document.
@@ -1651,7 +1651,7 @@ fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLin
             format!("{}", &plain_summary_line(Some(s)))
         };
         write!(w, "<div class='docblock'>{}</div>",
-               Markdown(&markdown, MarkdownOutputStyle::Fancy))?;
+               Markdown(&markdown))?;
     }
     Ok(())
 }
@@ -1684,8 +1684,7 @@ fn get_doc_value(item: &clean::Item) -> Option<&str> {
 fn document_full(w: &mut fmt::Formatter, item: &clean::Item) -> fmt::Result {
     if let Some(s) = get_doc_value(item) {
         write!(w, "<div class='docblock'>{}</div>",
-               Markdown(&format!("{}{}", md_render_assoc_item(item), s),
-                                 MarkdownOutputStyle::Fancy))?;
+               Markdown(&format!("{}{}", md_render_assoc_item(item), s)))?;
     }
     Ok(())
 }
@@ -1873,8 +1872,7 @@ fn item_module(w: &mut fmt::Formatter, cx: &Context,
                        </tr>",
                        name = *myitem.name.as_ref().unwrap(),
                        stab_docs = stab_docs,
-                       docs = shorter(Some(&Markdown(doc_value,
-                                                     MarkdownOutputStyle::Compact).to_string())),
+                       docs = MarkdownSummaryLine(doc_value),
                        class = myitem.type_(),
                        stab = myitem.stability_class().unwrap_or("".to_string()),
                        unsafety_flag = unsafety_flag,
@@ -2904,7 +2902,7 @@ fn render_impl(w: &mut fmt::Formatter, cx: &Context, i: &Impl, link: AssocItemLi
         write!(w, "</span>")?;
         write!(w, "</h3>\n")?;
         if let Some(ref dox) = i.impl_item.doc_value() {
-            write!(w, "<div class='docblock'>{}</div>", Markdown(dox, MarkdownOutputStyle::Fancy))?;
+            write!(w, "<div class='docblock'>{}</div>", Markdown(dox))?;
         }
     }
 
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 5cc0f03e1f6..5fadda030a4 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -25,7 +25,7 @@ use externalfiles::{ExternalHtml, LoadStringError, load_string};
 use html::render::reset_ids;
 use html::escape::Escape;
 use html::markdown;
-use html::markdown::{Markdown, MarkdownWithToc, MarkdownOutputStyle, find_testable_code};
+use html::markdown::{Markdown, MarkdownWithToc, find_testable_code};
 use test::{TestOptions, Collector};
 
 /// Separate any lines at the start of the file that begin with `# ` or `%`.
@@ -96,7 +96,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches,
     let rendered = if include_toc {
         format!("{}", MarkdownWithToc(text))
     } else {
-        format!("{}", Markdown(text, MarkdownOutputStyle::Fancy))
+        format!("{}", Markdown(text))
     };
 
     let err = write!(
diff --git a/src/librustdoc/passes/unindent_comments.rs b/src/librustdoc/passes/unindent_comments.rs
index 4d94c308478..59fef8d2027 100644
--- a/src/librustdoc/passes/unindent_comments.rs
+++ b/src/librustdoc/passes/unindent_comments.rs
@@ -82,7 +82,7 @@ fn unindent(s: &str) -> String {
     });
 
     if !lines.is_empty() {
-        let mut unindented = vec![ lines[0].trim().to_string() ];
+        let mut unindented = vec![ lines[0].trim_left().to_string() ];
         unindented.extend_from_slice(&lines[1..].iter().map(|&line| {
             if line.chars().all(|c| c.is_whitespace()) {
                 line.to_string()
@@ -160,4 +160,15 @@ mod unindent_tests {
         let r = unindent(&s);
         assert_eq!(r, "line1\nline2");
     }
+
+    #[test]
+    fn should_not_trim() {
+        let s = "\t    line1  \n\t    line2".to_string();
+        let r = unindent(&s);
+        assert_eq!(r, "line1  \nline2");
+
+        let s = "    \tline1  \n    \tline2".to_string();
+        let r = unindent(&s);
+        assert_eq!(r, "line1  \nline2");
+    }
 }
diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs
index 1cac11f668d..b3625386209 100644
--- a/src/libstd/ascii.rs
+++ b/src/libstd/ascii.rs
@@ -9,6 +9,20 @@
 // except according to those terms.
 
 //! Operations on ASCII strings and characters.
+//!
+//! Most string operations in Rust act on UTF-8 strings. However, at times it
+//! makes more sense to only consider the ASCII character set for a specific
+//! operation.
+//!
+//! The [`AsciiExt`] trait provides methods that allow for character
+//! operations that only act on the ASCII subset and leave non-ASCII characters
+//! alone.
+//!
+//! The [`escape_default`] function provides an iterator over the bytes of an
+//! escaped version of the character given.
+//!
+//! [`AsciiExt`]: trait.AsciiExt.html
+//! [`escape_default`]: fn.escape_default.html
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
@@ -53,11 +67,11 @@ pub trait AsciiExt {
     /// use std::ascii::AsciiExt;
     ///
     /// let ascii = 'a';
-    /// let utf8 = '❤';
+    /// let non_ascii = '❤';
     /// let int_ascii = 97;
     ///
     /// assert!(ascii.is_ascii());
-    /// assert!(!utf8.is_ascii());
+    /// assert!(!non_ascii.is_ascii());
     /// assert!(int_ascii.is_ascii());
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -79,11 +93,11 @@ pub trait AsciiExt {
     /// use std::ascii::AsciiExt;
     ///
     /// let ascii = 'a';
-    /// let utf8 = '❤';
+    /// let non_ascii = '❤';
     /// let int_ascii = 97;
     ///
     /// assert_eq!('A', ascii.to_ascii_uppercase());
-    /// assert_eq!('❤', utf8.to_ascii_uppercase());
+    /// assert_eq!('❤', non_ascii.to_ascii_uppercase());
     /// assert_eq!(65, int_ascii.to_ascii_uppercase());
     /// ```
     ///
@@ -108,11 +122,11 @@ pub trait AsciiExt {
     /// use std::ascii::AsciiExt;
     ///
     /// let ascii = 'A';
-    /// let utf8 = '❤';
+    /// let non_ascii = '❤';
     /// let int_ascii = 65;
     ///
     /// assert_eq!('a', ascii.to_ascii_lowercase());
-    /// assert_eq!('❤', utf8.to_ascii_lowercase());
+    /// assert_eq!('❤', non_ascii.to_ascii_lowercase());
     /// assert_eq!(97, int_ascii.to_ascii_lowercase());
     /// ```
     ///
@@ -934,8 +948,12 @@ impl AsciiExt for char {
     }
 }
 
-/// An iterator over the escaped version of a byte, constructed via
-/// `std::ascii::escape_default`.
+/// An iterator over the escaped version of a byte.
+///
+/// This `struct` is created by the [`escape_default`] function. See its
+/// documentation for more.
+///
+/// [`escape_default`]: fn.escape_default.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct EscapeDefault {
     range: Range<usize>,
@@ -966,6 +984,38 @@ pub struct EscapeDefault {
 ///
 /// assert_eq!(b'\\', escaped.next().unwrap());
 /// assert_eq!(b't', escaped.next().unwrap());
+///
+/// let mut escaped = ascii::escape_default(b'\r');
+///
+/// assert_eq!(b'\\', escaped.next().unwrap());
+/// assert_eq!(b'r', escaped.next().unwrap());
+///
+/// let mut escaped = ascii::escape_default(b'\n');
+///
+/// assert_eq!(b'\\', escaped.next().unwrap());
+/// assert_eq!(b'n', escaped.next().unwrap());
+///
+/// let mut escaped = ascii::escape_default(b'\'');
+///
+/// assert_eq!(b'\\', escaped.next().unwrap());
+/// assert_eq!(b'\'', escaped.next().unwrap());
+///
+/// let mut escaped = ascii::escape_default(b'"');
+///
+/// assert_eq!(b'\\', escaped.next().unwrap());
+/// assert_eq!(b'"', escaped.next().unwrap());
+///
+/// let mut escaped = ascii::escape_default(b'\\');
+///
+/// assert_eq!(b'\\', escaped.next().unwrap());
+/// assert_eq!(b'\\', escaped.next().unwrap());
+///
+/// let mut escaped = ascii::escape_default(b'\x9d');
+///
+/// assert_eq!(b'\\', escaped.next().unwrap());
+/// assert_eq!(b'x', escaped.next().unwrap());
+/// assert_eq!(b'9', escaped.next().unwrap());
+/// assert_eq!(b'd', escaped.next().unwrap());
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn escape_default(c: u8) -> EscapeDefault {
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs
index 57332170081..a06299eaefe 100644
--- a/src/libstd/collections/hash/map.rs
+++ b/src/libstd/collections/hash/map.rs
@@ -472,7 +472,7 @@ fn pop_internal<K, V>(starting_bucket: FullBucketMut<K, V>)
     }
 
     // Now we've done all our shifting. Return the value we grabbed earlier.
-    (retkey, retval, gap.into_bucket().into_table())
+    (retkey, retval, gap.into_table())
 }
 
 /// Perform robin hood bucket stealing at the given `bucket`. You must
@@ -485,14 +485,14 @@ fn robin_hood<'a, K: 'a, V: 'a>(bucket: FullBucketMut<'a, K, V>,
                                 mut key: K,
                                 mut val: V)
                                 -> FullBucketMut<'a, K, V> {
-    let start_index = bucket.index();
     let size = bucket.table().size();
-    // Save the *starting point*.
-    let mut bucket = bucket.stash();
+    let raw_capacity = bucket.table().capacity();
     // There can be at most `size - dib` buckets to displace, because
     // in the worst case, there are `size` elements and we already are
     // `displacement` buckets away from the initial one.
-    let idx_end = start_index + size - bucket.displacement();
+    let idx_end = (bucket.index() + size - bucket.displacement()) % raw_capacity;
+    // Save the *starting point*.
+    let mut bucket = bucket.stash();
 
     loop {
         let (old_hash, old_key, old_val) = bucket.replace(hash, key, val);
@@ -568,11 +568,8 @@ impl<K, V, S> HashMap<K, V, S>
     // The caller should ensure that invariants by Robin Hood Hashing hold
     // and that there's space in the underlying table.
     fn insert_hashed_ordered(&mut self, hash: SafeHash, k: K, v: V) {
-        let raw_cap = self.raw_capacity();
         let mut buckets = Bucket::new(&mut self.table, hash);
-        // note that buckets.index() keeps increasing
-        // even if the pointer wraps back to the first bucket.
-        let limit_bucket = buckets.index() + raw_cap;
+        let start_index = buckets.index();
 
         loop {
             // We don't need to compare hashes for value swap.
@@ -585,7 +582,7 @@ impl<K, V, S> HashMap<K, V, S>
                 Full(b) => b.into_bucket(),
             };
             buckets.next();
-            debug_assert!(buckets.index() < limit_bucket);
+            debug_assert!(buckets.index() != start_index);
         }
     }
 }
@@ -1244,24 +1241,25 @@ impl<K, V, S> HashMap<K, V, S>
     pub fn retain<F>(&mut self, mut f: F)
         where F: FnMut(&K, &mut V) -> bool
     {
-        if self.table.capacity() == 0 || self.table.size() == 0 {
+        if self.table.size() == 0 {
             return;
         }
+        let mut elems_left = self.table.size();
         let mut bucket = Bucket::head_bucket(&mut self.table);
         bucket.prev();
-        let tail = bucket.index();
-        loop {
+        let start_index = bucket.index();
+        while elems_left != 0 {
             bucket = match bucket.peek() {
                 Full(mut full) => {
+                    elems_left -= 1;
                     let should_remove = {
                         let (k, v) = full.read_mut();
                         !f(k, v)
                     };
                     if should_remove {
-                        let prev_idx = full.index();
                         let prev_raw = full.raw();
                         let (_, _, t) = pop_internal(full);
-                        Bucket::new_from(prev_raw, prev_idx, t)
+                        Bucket::new_from(prev_raw, t)
                     } else {
                         full.into_bucket()
                     }
@@ -1271,9 +1269,7 @@ impl<K, V, S> HashMap<K, V, S>
                 }
             };
             bucket.prev();  // reverse iteration
-            if bucket.index() == tail {
-                break;
-            }
+            debug_assert!(elems_left == 0 || bucket.index() != start_index);
         }
     }
 }
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index da5fb1a4733..9623706548b 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -113,7 +113,7 @@ impl TaggedHashUintPtr {
 /// when the RawTable is created and is accessible with the `tag` and `set_tag`
 /// functions.
 pub struct RawTable<K, V> {
-    capacity: usize,
+    capacity_mask: usize,
     size: usize,
     hashes: TaggedHashUintPtr,
 
@@ -125,10 +125,13 @@ pub struct RawTable<K, V> {
 unsafe impl<K: Send, V: Send> Send for RawTable<K, V> {}
 unsafe impl<K: Sync, V: Sync> Sync for RawTable<K, V> {}
 
+// An unsafe view of a RawTable bucket
+// Valid indexes are within [0..table_capacity)
 pub struct RawBucket<K, V> {
-    hash: *mut HashUint,
+    hash_start: *mut HashUint,
     // We use *const to ensure covariance with respect to K and V
-    pair: *const (K, V),
+    pair_start: *const (K, V),
+    idx: usize,
     _marker: marker::PhantomData<(K, V)>,
 }
 
@@ -141,7 +144,6 @@ impl<K, V> Clone for RawBucket<K, V> {
 
 pub struct Bucket<K, V, M> {
     raw: RawBucket<K, V>,
-    idx: usize,
     table: M,
 }
 
@@ -154,13 +156,11 @@ impl<K, V, M: Copy> Clone for Bucket<K, V, M> {
 
 pub struct EmptyBucket<K, V, M> {
     raw: RawBucket<K, V>,
-    idx: usize,
     table: M,
 }
 
 pub struct FullBucket<K, V, M> {
     raw: RawBucket<K, V>,
-    idx: usize,
     table: M,
 }
 
@@ -232,13 +232,17 @@ fn can_alias_safehash_as_hash() {
     assert_eq!(size_of::<SafeHash>(), size_of::<HashUint>())
 }
 
+// RawBucket methods are unsafe as it's possible to
+// make a RawBucket point to invalid memory using safe code.
 impl<K, V> RawBucket<K, V> {
-    unsafe fn offset(self, count: isize) -> RawBucket<K, V> {
-        RawBucket {
-            hash: self.hash.offset(count),
-            pair: self.pair.offset(count),
-            _marker: marker::PhantomData,
-        }
+    unsafe fn hash(&self) -> *mut HashUint {
+        self.hash_start.offset(self.idx as isize)
+    }
+    unsafe fn pair(&self) -> *mut (K, V) {
+        self.pair_start.offset(self.idx as isize) as *mut (K, V)
+    }
+    unsafe fn hash_pair(&self) -> (*mut HashUint, *mut (K, V)) {
+        (self.hash(), self.pair())
     }
 }
 
@@ -258,7 +262,7 @@ impl<K, V, M> FullBucket<K, V, M> {
     }
     /// Get the raw index.
     pub fn index(&self) -> usize {
-        self.idx
+        self.raw.idx
     }
     /// Get the raw bucket.
     pub fn raw(&self) -> RawBucket<K, V> {
@@ -280,7 +284,7 @@ impl<K, V, M> EmptyBucket<K, V, M> {
 impl<K, V, M> Bucket<K, V, M> {
     /// Get the raw index.
     pub fn index(&self) -> usize {
-        self.idx
+        self.raw.idx
     }
     /// get the table.
     pub fn into_table(self) -> M {
@@ -331,12 +335,11 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> {
         Bucket::at_index(table, hash.inspect() as usize)
     }
 
-    pub fn new_from(r: RawBucket<K, V>, i: usize, t: M)
+    pub fn new_from(r: RawBucket<K, V>, t: M)
         -> Bucket<K, V, M>
     {
         Bucket {
             raw: r,
-            idx: i,
             table: t,
         }
     }
@@ -346,18 +349,16 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> {
         // This is an uncommon case though, so avoid it in release builds.
         debug_assert!(table.capacity() > 0,
                       "Table should have capacity at this point");
-        let ib_index = ib_index & (table.capacity() - 1);
+        let ib_index = ib_index & table.capacity_mask;
         Bucket {
-            raw: unsafe { table.first_bucket_raw().offset(ib_index as isize) },
-            idx: ib_index,
+            raw: table.raw_bucket_at(ib_index),
             table: table,
         }
     }
 
     pub fn first(table: M) -> Bucket<K, V, M> {
         Bucket {
-            raw: table.first_bucket_raw(),
-            idx: 0,
+            raw: table.raw_bucket_at(0),
             table: table,
         }
     }
@@ -401,48 +402,30 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> Bucket<K, V, M> {
     /// the appropriate types to call most of the other functions in
     /// this module.
     pub fn peek(self) -> BucketState<K, V, M> {
-        match unsafe { *self.raw.hash } {
+        match unsafe { *self.raw.hash() } {
             EMPTY_BUCKET => {
                 Empty(EmptyBucket {
                     raw: self.raw,
-                    idx: self.idx,
                     table: self.table,
                 })
             }
             _ => {
                 Full(FullBucket {
                     raw: self.raw,
-                    idx: self.idx,
                     table: self.table,
                 })
             }
         }
     }
 
-    /// Modifies the bucket pointer in place to make it point to the next slot.
+    /// Modifies the bucket in place to make it point to the next slot.
     pub fn next(&mut self) {
-        self.idx += 1;
-        let range = self.table.capacity();
-        // This code is branchless thanks to a conditional move.
-        let dist = if self.idx & (range - 1) == 0 {
-            1 - range as isize
-        } else {
-            1
-        };
-        unsafe {
-            self.raw = self.raw.offset(dist);
-        }
+        self.raw.idx = self.raw.idx.wrapping_add(1) & self.table.capacity_mask;
     }
 
-    /// Modifies the bucket pointer in place to make it point to the previous slot.
+    /// Modifies the bucket in place to make it point to the previous slot.
     pub fn prev(&mut self) {
-        let range = self.table.capacity();
-        let new_idx = self.idx.wrapping_sub(1) & (range - 1);
-        let dist = (new_idx as isize).wrapping_sub(self.idx as isize);
-        self.idx = new_idx;
-        unsafe {
-            self.raw = self.raw.offset(dist);
-        }
+        self.raw.idx = self.raw.idx.wrapping_sub(1) & self.table.capacity_mask;
     }
 }
 
@@ -458,7 +441,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> {
     pub fn into_bucket(self) -> Bucket<K, V, M> {
         Bucket {
             raw: self.raw,
-            idx: self.idx,
             table: self.table,
         }
     }
@@ -466,7 +448,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> EmptyBucket<K, V, M> {
     pub fn gap_peek(self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> {
         let gap = EmptyBucket {
             raw: self.raw,
-            idx: self.idx,
             table: (),
         };
 
@@ -494,15 +475,14 @@ impl<K, V, M> EmptyBucket<K, V, M>
     /// Use `make_hash` to construct a `SafeHash` to pass to this function.
     pub fn put(mut self, hash: SafeHash, key: K, value: V) -> FullBucket<K, V, M> {
         unsafe {
-            *self.raw.hash = hash.inspect();
-            ptr::write(self.raw.pair as *mut (K, V), (key, value));
+            *self.raw.hash() = hash.inspect();
+            ptr::write(self.raw.pair(), (key, value));
 
             self.table.borrow_table_mut().size += 1;
         }
 
         FullBucket {
             raw: self.raw,
-            idx: self.idx,
             table: self.table,
         }
     }
@@ -510,15 +490,14 @@ impl<K, V, M> EmptyBucket<K, V, M>
     /// Puts given key, remain value uninitialized.
     /// It is only used for inplacement insertion.
     pub unsafe fn put_key(mut self, hash: SafeHash, key: K) -> FullBucket<K, V, M> {
-        *self.raw.hash = hash.inspect();
-        let pair_mut = self.raw.pair as *mut (K, V);
-        ptr::write(&mut (*pair_mut).0, key);
+        *self.raw.hash() = hash.inspect();
+        let pair_ptr = self.raw.pair();
+        ptr::write(&mut (*pair_ptr).0, key);
 
         self.table.borrow_table_mut().size += 1;
 
         FullBucket {
             raw: self.raw,
-            idx: self.idx,
             table: self.table,
         }
     }
@@ -536,7 +515,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> {
     pub fn into_bucket(self) -> Bucket<K, V, M> {
         Bucket {
             raw: self.raw,
-            idx: self.idx,
             table: self.table,
         }
     }
@@ -546,7 +524,6 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> {
     pub fn stash(self) -> FullBucket<K, V, Self> {
         FullBucket {
             raw: self.raw,
-            idx: self.idx,
             table: self,
         }
     }
@@ -560,17 +537,20 @@ impl<K, V, M: Deref<Target = RawTable<K, V>>> FullBucket<K, V, M> {
         // Calculates the distance one has to travel when going from
         // `hash mod capacity` onwards to `idx mod capacity`, wrapping around
         // if the destination is not reached before the end of the table.
-        (self.idx.wrapping_sub(self.hash().inspect() as usize)) & (self.table.capacity() - 1)
+        (self.raw.idx.wrapping_sub(self.hash().inspect() as usize)) & self.table.capacity_mask
     }
 
     #[inline]
     pub fn hash(&self) -> SafeHash {
-        unsafe { SafeHash { hash: *self.raw.hash } }
+        unsafe { SafeHash { hash: *self.raw.hash() } }
     }
 
     /// Gets references to the key and value at a given index.
     pub fn read(&self) -> (&K, &V) {
-        unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) }
+        unsafe {
+            let pair_ptr = self.raw.pair();
+            (&(*pair_ptr).0, &(*pair_ptr).1)
+        }
     }
 }
 
@@ -586,11 +566,10 @@ impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> {
         self.table.size -= 1;
 
         unsafe {
-            *self.raw.hash = EMPTY_BUCKET;
-            let (k, v) = ptr::read(self.raw.pair);
+            *self.raw.hash() = EMPTY_BUCKET;
+            let (k, v) = ptr::read(self.raw.pair());
             (EmptyBucket {
                  raw: self.raw,
-                 idx: self.idx,
                  table: self.table,
              },
             k,
@@ -604,9 +583,9 @@ impl<'t, K, V> FullBucket<K, V, &'t mut RawTable<K, V>> {
     pub unsafe fn remove_key(&mut self) {
         self.table.size -= 1;
 
-        *self.raw.hash = EMPTY_BUCKET;
-        let pair_mut = self.raw.pair as *mut (K, V);
-        ptr::drop_in_place(&mut (*pair_mut).0); // only drop key
+        *self.raw.hash() = EMPTY_BUCKET;
+        let pair_ptr = self.raw.pair();
+        ptr::drop_in_place(&mut (*pair_ptr).0); // only drop key
     }
 }
 
@@ -617,8 +596,8 @@ impl<K, V, M> FullBucket<K, V, M>
 {
     pub fn replace(&mut self, h: SafeHash, k: K, v: V) -> (SafeHash, K, V) {
         unsafe {
-            let old_hash = ptr::replace(self.raw.hash as *mut SafeHash, h);
-            let (old_key, old_val) = ptr::replace(self.raw.pair as *mut (K, V), (k, v));
+            let old_hash = ptr::replace(self.raw.hash() as *mut SafeHash, h);
+            let (old_key, old_val) = ptr::replace(self.raw.pair(), (k, v));
 
             (old_hash, old_key, old_val)
         }
@@ -630,8 +609,10 @@ impl<K, V, M> FullBucket<K, V, M>
 {
     /// Gets mutable references to the key and value at a given index.
     pub fn read_mut(&mut self) -> (&mut K, &mut V) {
-        let pair_mut = self.raw.pair as *mut (K, V);
-        unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) }
+        unsafe {
+            let pair_ptr = self.raw.pair();
+            (&mut (*pair_ptr).0, &mut (*pair_ptr).1)
+        }
     }
 }
 
@@ -644,7 +625,10 @@ impl<'t, K, V, M> FullBucket<K, V, M>
     /// in exchange for this, the returned references have a longer lifetime
     /// than the references returned by `read()`.
     pub fn into_refs(self) -> (&'t K, &'t V) {
-        unsafe { (&(*self.raw.pair).0, &(*self.raw.pair).1) }
+        unsafe {
+            let pair_ptr = self.raw.pair();
+            (&(*pair_ptr).0, &(*pair_ptr).1)
+        }
     }
 }
 
@@ -654,8 +638,10 @@ impl<'t, K, V, M> FullBucket<K, V, M>
     /// This works similarly to `into_refs`, exchanging a bucket state
     /// for mutable references into the table.
     pub fn into_mut_refs(self) -> (&'t mut K, &'t mut V) {
-        let pair_mut = self.raw.pair as *mut (K, V);
-        unsafe { (&mut (*pair_mut).0, &mut (*pair_mut).1) }
+        unsafe {
+            let pair_ptr = self.raw.pair();
+            (&mut (*pair_ptr).0, &mut (*pair_ptr).1)
+        }
     }
 }
 
@@ -667,22 +653,23 @@ impl<K, V, M> GapThenFull<K, V, M>
         &self.full
     }
 
-    pub fn into_bucket(self) -> Bucket<K, V, M> {
-        self.full.into_bucket()
+    pub fn into_table(self) -> M {
+        self.full.into_table()
     }
 
     pub fn shift(mut self) -> Result<GapThenFull<K, V, M>, Bucket<K, V, M>> {
         unsafe {
-            *self.gap.raw.hash = mem::replace(&mut *self.full.raw.hash, EMPTY_BUCKET);
-            ptr::copy_nonoverlapping(self.full.raw.pair, self.gap.raw.pair as *mut (K, V), 1);
+            let (gap_hash, gap_pair) = self.gap.raw.hash_pair();
+            let (full_hash, full_pair) = self.full.raw.hash_pair();
+            *gap_hash = mem::replace(&mut *full_hash, EMPTY_BUCKET);
+            ptr::copy_nonoverlapping(full_pair, gap_pair, 1);
         }
 
-        let FullBucket { raw: prev_raw, idx: prev_idx, .. } = self.full;
+        let FullBucket { raw: prev_raw, .. } = self.full;
 
         match self.full.next().peek() {
             Full(bucket) => {
                 self.gap.raw = prev_raw;
-                self.gap.idx = prev_idx;
 
                 self.full = bucket;
 
@@ -761,7 +748,7 @@ impl<K, V> RawTable<K, V> {
         if capacity == 0 {
             return RawTable {
                 size: 0,
-                capacity: 0,
+                capacity_mask: capacity.wrapping_sub(1),
                 hashes: TaggedHashUintPtr::new(EMPTY as *mut HashUint),
                 marker: marker::PhantomData,
             };
@@ -801,25 +788,27 @@ impl<K, V> RawTable<K, V> {
         let hashes = buffer.offset(hash_offset as isize) as *mut HashUint;
 
         RawTable {
-            capacity: capacity,
+            capacity_mask: capacity.wrapping_sub(1),
             size: 0,
             hashes: TaggedHashUintPtr::new(hashes),
             marker: marker::PhantomData,
         }
     }
 
-    fn first_bucket_raw(&self) -> RawBucket<K, V> {
-        let hashes_size = self.capacity * size_of::<HashUint>();
-        let pairs_size = self.capacity * size_of::<(K, V)>();
+    fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> {
+        let hashes_size = self.capacity() * size_of::<HashUint>();
+        let pairs_size = self.capacity() * size_of::<(K, V)>();
 
-        let buffer = self.hashes.ptr() as *mut u8;
         let (pairs_offset, _, oflo) =
             calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>());
         debug_assert!(!oflo, "capacity overflow");
+
+        let buffer = self.hashes.ptr() as *mut u8;
         unsafe {
             RawBucket {
-                hash: self.hashes.ptr(),
-                pair: buffer.offset(pairs_offset as isize) as *const _,
+                hash_start: buffer as *mut HashUint,
+                pair_start: buffer.offset(pairs_offset as isize) as *const (K, V),
+                idx: index,
                 _marker: marker::PhantomData,
             }
         }
@@ -837,7 +826,7 @@ impl<K, V> RawTable<K, V> {
 
     /// The hashtable's capacity, similar to a vector's.
     pub fn capacity(&self) -> usize {
-        self.capacity
+        self.capacity_mask.wrapping_add(1)
     }
 
     /// The number of elements ever `put` in the hashtable, minus the number
@@ -848,8 +837,8 @@ impl<K, V> RawTable<K, V> {
 
     fn raw_buckets(&self) -> RawBuckets<K, V> {
         RawBuckets {
-            raw: self.first_bucket_raw(),
-            hashes_end: unsafe { self.hashes.ptr().offset(self.capacity as isize) },
+            raw: self.raw_bucket_at(0),
+            elems_left: self.size,
             marker: marker::PhantomData,
         }
     }
@@ -857,25 +846,23 @@ impl<K, V> RawTable<K, V> {
     pub fn iter(&self) -> Iter<K, V> {
         Iter {
             iter: self.raw_buckets(),
-            elems_left: self.size(),
         }
     }
 
     pub fn iter_mut(&mut self) -> IterMut<K, V> {
         IterMut {
             iter: self.raw_buckets(),
-            elems_left: self.size(),
             _marker: marker::PhantomData,
         }
     }
 
     pub fn into_iter(self) -> IntoIter<K, V> {
-        let RawBuckets { raw, hashes_end, .. } = self.raw_buckets();
+        let RawBuckets { raw, elems_left, .. } = self.raw_buckets();
         // Replace the marker regardless of lifetime bounds on parameters.
         IntoIter {
             iter: RawBuckets {
                 raw: raw,
-                hashes_end: hashes_end,
+                elems_left: elems_left,
                 marker: marker::PhantomData,
             },
             table: self,
@@ -883,12 +870,12 @@ impl<K, V> RawTable<K, V> {
     }
 
     pub fn drain(&mut self) -> Drain<K, V> {
-        let RawBuckets { raw, hashes_end, .. } = self.raw_buckets();
+        let RawBuckets { raw, elems_left, .. } = self.raw_buckets();
         // Replace the marker regardless of lifetime bounds on parameters.
         Drain {
             iter: RawBuckets {
                 raw: raw,
-                hashes_end: hashes_end,
+                elems_left: elems_left,
                 marker: marker::PhantomData,
             },
             table: unsafe { Shared::new(self) },
@@ -900,18 +887,16 @@ impl<K, V> RawTable<K, V> {
     /// state and should only be used for dropping the table's remaining
     /// entries. It's used in the implementation of Drop.
     unsafe fn rev_drop_buckets(&mut self) {
-        let first_raw = self.first_bucket_raw();
-        let mut raw = first_raw.offset(self.capacity as isize);
+        // initialize the raw bucket past the end of the table
+        let mut raw = self.raw_bucket_at(self.capacity());
         let mut elems_left = self.size;
 
         while elems_left != 0 {
-            debug_assert!(raw.hash != first_raw.hash);
+            raw.idx -= 1;
 
-            raw = raw.offset(-1);
-
-            if *raw.hash != EMPTY_BUCKET {
+            if *raw.hash() != EMPTY_BUCKET {
                 elems_left -= 1;
-                ptr::drop_in_place(raw.pair as *mut (K, V));
+                ptr::drop_in_place(raw.pair());
             }
         }
     }
@@ -931,7 +916,7 @@ impl<K, V> RawTable<K, V> {
 /// this interface is safe, it's not used outside this module.
 struct RawBuckets<'a, K, V> {
     raw: RawBucket<K, V>,
-    hashes_end: *mut HashUint,
+    elems_left: usize,
 
     // Strictly speaking, this should be &'a (K,V), but that would
     // require that K:'a, and we often use RawBuckets<'static...> for
@@ -946,7 +931,7 @@ impl<'a, K, V> Clone for RawBuckets<'a, K, V> {
     fn clone(&self) -> RawBuckets<'a, K, V> {
         RawBuckets {
             raw: self.raw,
-            hashes_end: self.hashes_end,
+            elems_left: self.elems_left,
             marker: marker::PhantomData,
         }
     }
@@ -957,25 +942,36 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> {
     type Item = RawBucket<K, V>;
 
     fn next(&mut self) -> Option<RawBucket<K, V>> {
-        while self.raw.hash != self.hashes_end {
+        if self.elems_left == 0 {
+            return None;
+        }
+
+        loop {
             unsafe {
-                // We are swapping out the pointer to a bucket and replacing
-                // it with the pointer to the next one.
-                let prev = ptr::replace(&mut self.raw, self.raw.offset(1));
-                if *prev.hash != EMPTY_BUCKET {
-                    return Some(prev);
+                let item = self.raw;
+                self.raw.idx += 1;
+                if *item.hash() != EMPTY_BUCKET {
+                    self.elems_left -= 1;
+                    return Some(item);
                 }
             }
         }
+    }
+
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        (self.elems_left, Some(self.elems_left))
+    }
+}
 
-        None
+impl<'a, K, V> ExactSizeIterator for RawBuckets<'a, K, V> {
+    fn len(&self) -> usize {
+        self.elems_left
     }
 }
 
 /// Iterator over shared references to entries in a table.
 pub struct Iter<'a, K: 'a, V: 'a> {
     iter: RawBuckets<'a, K, V>,
-    elems_left: usize,
 }
 
 unsafe impl<'a, K: Sync, V: Sync> Sync for Iter<'a, K, V> {}
@@ -986,16 +982,13 @@ impl<'a, K, V> Clone for Iter<'a, K, V> {
     fn clone(&self) -> Iter<'a, K, V> {
         Iter {
             iter: self.iter.clone(),
-            elems_left: self.elems_left,
         }
     }
 }
 
-
 /// Iterator over mutable references to entries in a table.
 pub struct IterMut<'a, K: 'a, V: 'a> {
     iter: RawBuckets<'a, K, V>,
-    elems_left: usize,
     // To ensure invariance with respect to V
     _marker: marker::PhantomData<&'a mut V>,
 }
@@ -1009,7 +1002,6 @@ impl<'a, K: 'a, V: 'a> IterMut<'a, K, V> {
     pub fn iter(&self) -> Iter<K, V> {
         Iter {
             iter: self.iter.clone(),
-            elems_left: self.elems_left,
         }
     }
 }
@@ -1027,7 +1019,6 @@ impl<K, V> IntoIter<K, V> {
     pub fn iter(&self) -> Iter<K, V> {
         Iter {
             iter: self.iter.clone(),
-            elems_left: self.table.size,
         }
     }
 }
@@ -1044,11 +1035,8 @@ unsafe impl<'a, K: Send, V: Send> Send for Drain<'a, K, V> {}
 
 impl<'a, K, V> Drain<'a, K, V> {
     pub fn iter(&self) -> Iter<K, V> {
-        unsafe {
-            Iter {
-                iter: self.iter.clone(),
-                elems_left: (**self.table).size,
-            }
+        Iter {
+            iter: self.iter.clone(),
         }
     }
 }
@@ -1057,19 +1045,20 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> {
     type Item = (&'a K, &'a V);
 
     fn next(&mut self) -> Option<(&'a K, &'a V)> {
-        self.iter.next().map(|bucket| {
-            self.elems_left -= 1;
-            unsafe { (&(*bucket.pair).0, &(*bucket.pair).1) }
+        self.iter.next().map(|raw| unsafe {
+            let pair_ptr = raw.pair();
+            (&(*pair_ptr).0, &(*pair_ptr).1)
         })
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        (self.elems_left, Some(self.elems_left))
+        self.iter.size_hint()
     }
 }
+
 impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {
     fn len(&self) -> usize {
-        self.elems_left
+        self.iter.len()
     }
 }
 
@@ -1077,20 +1066,20 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> {
     type Item = (&'a K, &'a mut V);
 
     fn next(&mut self) -> Option<(&'a K, &'a mut V)> {
-        self.iter.next().map(|bucket| {
-            self.elems_left -= 1;
-            let pair_mut = bucket.pair as *mut (K, V);
-            unsafe { (&(*pair_mut).0, &mut (*pair_mut).1) }
+        self.iter.next().map(|raw| unsafe {
+            let pair_ptr = raw.pair();
+            (&(*pair_ptr).0, &mut (*pair_ptr).1)
         })
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        (self.elems_left, Some(self.elems_left))
+        self.iter.size_hint()
     }
 }
+
 impl<'a, K, V> ExactSizeIterator for IterMut<'a, K, V> {
     fn len(&self) -> usize {
-        self.elems_left
+        self.iter.len()
     }
 }
 
@@ -1098,23 +1087,23 @@ impl<K, V> Iterator for IntoIter<K, V> {
     type Item = (SafeHash, K, V);
 
     fn next(&mut self) -> Option<(SafeHash, K, V)> {
-        self.iter.next().map(|bucket| {
+        self.iter.next().map(|raw| {
             self.table.size -= 1;
             unsafe {
-                let (k, v) = ptr::read(bucket.pair);
-                (SafeHash { hash: *bucket.hash }, k, v)
+                let (k, v) = ptr::read(raw.pair());
+                (SafeHash { hash: *raw.hash() }, k, v)
             }
         })
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        let size = self.table.size();
-        (size, Some(size))
+        self.iter.size_hint()
     }
 }
+
 impl<K, V> ExactSizeIterator for IntoIter<K, V> {
     fn len(&self) -> usize {
-        self.table.size()
+        self.iter().len()
     }
 }
 
@@ -1123,23 +1112,21 @@ impl<'a, K, V> Iterator for Drain<'a, K, V> {
 
     #[inline]
     fn next(&mut self) -> Option<(SafeHash, K, V)> {
-        self.iter.next().map(|bucket| {
-            unsafe {
-                (*self.table.as_mut_ptr()).size -= 1;
-                let (k, v) = ptr::read(bucket.pair);
-                (SafeHash { hash: ptr::replace(bucket.hash, EMPTY_BUCKET) }, k, v)
-            }
+        self.iter.next().map(|raw| unsafe {
+            (*self.table.as_mut_ptr()).size -= 1;
+            let (k, v) = ptr::read(raw.pair());
+            (SafeHash { hash: ptr::replace(&mut *raw.hash(), EMPTY_BUCKET) }, k, v)
         })
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
-        let size = unsafe { (**self.table).size() };
-        (size, Some(size))
+        self.iter.size_hint()
     }
 }
+
 impl<'a, K, V> ExactSizeIterator for Drain<'a, K, V> {
     fn len(&self) -> usize {
-        unsafe { (**self.table).size() }
+        self.iter.len()
     }
 }
 
@@ -1152,30 +1139,21 @@ impl<'a, K: 'a, V: 'a> Drop for Drain<'a, K, V> {
 impl<K: Clone, V: Clone> Clone for RawTable<K, V> {
     fn clone(&self) -> RawTable<K, V> {
         unsafe {
-            let mut new_ht = RawTable::new_uninitialized(self.capacity());
-
-            {
-                let cap = self.capacity();
-                let mut new_buckets = Bucket::first(&mut new_ht);
-                let mut buckets = Bucket::first(self);
-                while buckets.index() != cap {
-                    match buckets.peek() {
-                        Full(full) => {
-                            let (h, k, v) = {
-                                let (k, v) = full.read();
-                                (full.hash(), k.clone(), v.clone())
-                            };
-                            *new_buckets.raw.hash = h.inspect();
-                            ptr::write(new_buckets.raw.pair as *mut (K, V), (k, v));
-                        }
-                        Empty(..) => {
-                            *new_buckets.raw.hash = EMPTY_BUCKET;
-                        }
-                    }
-                    new_buckets.next();
-                    buckets.next();
+            let cap = self.capacity();
+            let mut new_ht = RawTable::new_uninitialized(cap);
+
+            let mut new_buckets = new_ht.raw_bucket_at(0);
+            let mut buckets = self.raw_bucket_at(0);
+            while buckets.idx < cap {
+                *new_buckets.hash() = *buckets.hash();
+                if *new_buckets.hash() != EMPTY_BUCKET {
+                    let pair_ptr = buckets.pair();
+                    let kv = ((*pair_ptr).0.clone(), (*pair_ptr).1.clone());
+                    ptr::write(new_buckets.pair(), kv);
                 }
-            };
+                buckets.idx += 1;
+                new_buckets.idx += 1;
+            }
 
             new_ht.size = self.size();
 
@@ -1186,7 +1164,7 @@ impl<K: Clone, V: Clone> Clone for RawTable<K, V> {
 
 unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
     fn drop(&mut self) {
-        if self.capacity == 0 {
+        if self.capacity() == 0 {
             return;
         }
 
@@ -1202,8 +1180,8 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
             }
         }
 
-        let hashes_size = self.capacity * size_of::<HashUint>();
-        let pairs_size = self.capacity * size_of::<(K, V)>();
+        let hashes_size = self.capacity() * size_of::<HashUint>();
+        let pairs_size = self.capacity() * size_of::<(K, V)>();
         let (align, _, size, oflo) = calculate_allocation(hashes_size,
                                                           align_of::<HashUint>(),
                                                           pairs_size,
diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs
index ca26dc9527c..6b1267d89b6 100644
--- a/src/libstd/fs.rs
+++ b/src/libstd/fs.rs
@@ -1176,6 +1176,7 @@ impl AsInner<fs_imp::DirEntry> for DirEntry {
 /// This function currently corresponds to the `unlink` function on Unix
 /// and the `DeleteFile` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1212,6 +1213,7 @@ pub fn remove_file<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// This function currently corresponds to the `stat` function on Unix
 /// and the `GetFileAttributesEx` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1245,6 +1247,7 @@ pub fn metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
 /// This function currently corresponds to the `lstat` function on Unix
 /// and the `GetFileAttributesEx` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1287,6 +1290,7 @@ pub fn symlink_metadata<P: AsRef<Path>>(path: P) -> io::Result<Metadata> {
 /// on Windows, `from` can be anything, but `to` must *not* be a directory.
 ///
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1330,6 +1334,7 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()>
 /// `O_CLOEXEC` is set for returned file descriptors.
 /// On Windows, this function currently corresponds to `CopyFileEx`.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1366,6 +1371,7 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<u64> {
 /// This function currently corresponds to the `link` function on Unix
 /// and the `CreateHardLink` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1424,6 +1430,7 @@ pub fn soft_link<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<(
 /// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and
 /// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1457,6 +1464,7 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
 /// This function currently corresponds to the `realpath` function on Unix
 /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1489,6 +1497,7 @@ pub fn canonicalize<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
 /// This function currently corresponds to the `mkdir` function on Unix
 /// and the `CreateDirectory` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1522,6 +1531,7 @@ pub fn create_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// This function currently corresponds to the `mkdir` function on Unix
 /// and the `CreateDirectory` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1562,6 +1572,7 @@ pub fn create_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// This function currently corresponds to the `rmdir` function on Unix
 /// and the `RemoveDirectory` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1599,6 +1610,7 @@ pub fn remove_dir<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions
 /// on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1633,6 +1645,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
 /// This function currently corresponds to the `opendir` function on Unix
 /// and the `FindFirstFile` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1679,6 +1692,7 @@ pub fn read_dir<P: AsRef<Path>>(path: P) -> io::Result<ReadDir> {
 /// This function currently corresponds to the `chmod` function on Unix
 /// and the `SetFileAttributes` function on Windows.
 /// Note that, this [may change in the future][changes].
+///
 /// [changes]: ../io/index.html#platform-specific-behavior
 ///
 /// # Errors
@@ -1726,9 +1740,9 @@ impl DirBuilder {
         }
     }
 
-    /// Indicate that directories create should be created recursively, creating
-    /// all parent directories if they do not exist with the same security and
-    /// permissions settings.
+    /// Indicates that directories should be created recursively, creating all
+    /// parent directories. Parents that do not exist are created with the same
+    /// security and permissions settings.
     ///
     /// This option defaults to `false`.
     ///
@@ -1749,6 +1763,9 @@ impl DirBuilder {
     /// Create the specified directory with the options configured in this
     /// builder.
     ///
+    /// It is considered an error if the directory already exists unless
+    /// recursive mode is enabled.
+    ///
     /// # Examples
     ///
     /// ```no_run
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
index f98a3a87b01..3b82412716e 100644
--- a/src/libstd/io/buffered.rs
+++ b/src/libstd/io/buffered.rs
@@ -21,12 +21,12 @@ use memchr;
 /// The `BufReader` struct adds buffering to any reader.
 ///
 /// It can be excessively inefficient to work directly with a [`Read`] instance.
-/// For example, every call to [`read`] on [`TcpStream`] results in a system call.
-/// A `BufReader` performs large, infrequent reads on the underlying [`Read`]
-/// and maintains an in-memory buffer of the results.
+/// For example, every call to [`read`][`TcpStream::read`] on [`TcpStream`]
+/// results in a system call. A `BufReader` performs large, infrequent reads on
+/// the underlying [`Read`] and maintains an in-memory buffer of the results.
 ///
 /// [`Read`]: ../../std/io/trait.Read.html
-/// [`read`]: ../../std/net/struct.TcpStream.html#method.read
+/// [`TcpStream::read`]: ../../std/net/struct.TcpStream.html#method.read
 /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
 ///
 /// # Examples
@@ -261,9 +261,10 @@ impl<R: Seek> Seek for BufReader<R> {
 /// Wraps a writer and buffers its output.
 ///
 /// It can be excessively inefficient to work directly with something that
-/// implements [`Write`]. For example, every call to [`write`] on [`TcpStream`]
-/// results in a system call. A `BufWriter` keeps an in-memory buffer of data
-/// and writes it to an underlying writer in large, infrequent batches.
+/// implements [`Write`]. For example, every call to
+/// [`write`][`Tcpstream::write`] on [`TcpStream`] results in a system call. A
+/// `BufWriter` keeps an in-memory buffer of data and writes it to an underlying
+/// writer in large, infrequent batches.
 ///
 /// The buffer will be written out when the writer is dropped.
 ///
@@ -303,7 +304,7 @@ impl<R: Seek> Seek for BufReader<R> {
 /// the `stream` is dropped.
 ///
 /// [`Write`]: ../../std/io/trait.Write.html
-/// [`write`]: ../../std/net/struct.TcpStream.html#method.write
+/// [`Tcpstream::write`]: ../../std/net/struct.TcpStream.html#method.write
 /// [`TcpStream`]: ../../std/net/struct.TcpStream.html
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct BufWriter<W: Write> {
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
index 8ebc5c0a8fe..cd096c115ba 100644
--- a/src/libstd/io/mod.rs
+++ b/src/libstd/io/mod.rs
@@ -21,7 +21,8 @@
 //! of other types, and you can implement them for your types too. As such,
 //! you'll see a few different types of I/O throughout the documentation in
 //! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec<T>`]s. For
-//! example, [`Read`] adds a [`read`] method, which we can use on `File`s:
+//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on
+//! `File`s:
 //!
 //! ```
 //! use std::io;
@@ -106,7 +107,7 @@
 //! ```
 //!
 //! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call
-//! to [`write`]:
+//! to [`write`][`Write::write`]:
 //!
 //! ```
 //! use std::io;
@@ -257,13 +258,13 @@
 //! [`Vec<T>`]: ../vec/struct.Vec.html
 //! [`BufReader`]: struct.BufReader.html
 //! [`BufWriter`]: struct.BufWriter.html
-//! [`write`]: trait.Write.html#tymethod.write
+//! [`Write::write`]: trait.Write.html#tymethod.write
 //! [`io::stdout`]: fn.stdout.html
 //! [`println!`]: ../macro.println.html
 //! [`Lines`]: struct.Lines.html
 //! [`io::Result`]: type.Result.html
 //! [`?` operator]: ../../book/syntax-index.html
-//! [`read`]: trait.Read.html#tymethod.read
+//! [`Read::read`]: trait.Read.html#tymethod.read
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index cf119720e5a..bc315d54100 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -58,7 +58,7 @@ pub struct TcpStream(net_imp::TcpStream);
 ///
 /// After creating a `TcpListener` by [`bind`]ing it to a socket address, it listens
 /// for incoming TCP connections. These can be accepted by calling [`accept`] or by
-/// iterating over the [`Incoming`] iterator returned by [`incoming`].
+/// iterating over the [`Incoming`] iterator returned by [`incoming`][`TcpListener::incoming`].
 ///
 /// The socket will be closed when the value is dropped.
 ///
@@ -68,7 +68,7 @@ pub struct TcpStream(net_imp::TcpStream);
 /// [`bind`]: #method.bind
 /// [IETF RFC 793]: https://tools.ietf.org/html/rfc793
 /// [`Incoming`]: ../../std/net/struct.Incoming.html
-/// [`incoming`]: #method.incoming
+/// [`TcpListener::incoming`]: #method.incoming
 ///
 /// # Examples
 ///
diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs
index c71e0b2a703..86e661d7948 100644
--- a/src/libstd/prelude/mod.rs
+++ b/src/libstd/prelude/mod.rs
@@ -56,14 +56,14 @@
 //!   traits indicate fundamental properties of types.
 //! * [`std::ops`]::{[`Drop`], [`Fn`], [`FnMut`], [`FnOnce`]}. Various
 //!   operations for both destructors and overloading `()`.
-//! * [`std::mem`]::[`drop`], a convenience function for explicitly dropping a
-//!   value.
+//! * [`std::mem`]::[`drop`][`mem::drop`], a convenience function for explicitly
+//!   dropping a value.
 //! * [`std::boxed`]::[`Box`], a way to allocate values on the heap.
 //! * [`std::borrow`]::[`ToOwned`], The conversion trait that defines
 //!   [`to_owned`], the generic method for creating an owned type from a
 //!   borrowed type.
-//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines [`clone`],
-//!   the method for producing a copy of a value.
+//! * [`std::clone`]::[`Clone`], the ubiquitous trait that defines
+//!   [`clone`][`Clone::clone`], the method for producing a copy of a value.
 //! * [`std::cmp`]::{[`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] }. The
 //!   comparison traits, which implement the comparison operators and are often
 //!   seen in trait bounds.
@@ -117,8 +117,8 @@
 //! [`ToOwned`]: ../borrow/trait.ToOwned.html
 //! [`ToString`]: ../string/trait.ToString.html
 //! [`Vec`]: ../vec/struct.Vec.html
-//! [`clone`]: ../clone/trait.Clone.html#tymethod.clone
-//! [`drop`]: ../mem/fn.drop.html
+//! [`Clone::clone`]: ../clone/trait.Clone.html#tymethod.clone
+//! [`mem::drop`]: ../mem/fn.drop.html
 //! [`std::borrow`]: ../borrow/index.html
 //! [`std::boxed`]: ../boxed/index.html
 //! [`std::clone`]: ../clone/index.html
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index 7f1a00c707c..8cfd8fcd8c6 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -1070,6 +1070,27 @@ pub fn exit(code: i32) -> ! {
 ///     // execution never gets here
 /// }
 /// ```
+///
+/// The [`abort`] function terminates the process, so the destructor will not
+/// get run on the example below:
+///
+/// ```no_run
+/// use std::process;
+///
+/// struct HasDrop;
+///
+/// impl Drop for HasDrop {
+///     fn drop(&mut self) {
+///         println!("This will never be printed!");
+///     }
+/// }
+///
+/// fn main() {
+///     let _x = HasDrop;
+///     process::abort();
+///     // the destructor implemented for HasDrop will never get run
+/// }
+/// ```
 #[stable(feature = "process_abort", since = "1.17.0")]
 pub fn abort() -> ! {
     unsafe { ::sys::abort_internal() };
diff --git a/src/libstd/sync/barrier.rs b/src/libstd/sync/barrier.rs
index 295a49d6a8e..a7b01e49d2b 100644
--- a/src/libstd/sync/barrier.rs
+++ b/src/libstd/sync/barrier.rs
@@ -50,12 +50,11 @@ struct BarrierState {
     generation_id: usize,
 }
 
-/// A result returned from wait.
+/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`]
+/// have rendezvoused.
 ///
-/// Currently this opaque structure only has one method, [`.is_leader`]. Only
-/// one thread will receive a result that will return `true` from this function.
-///
-/// [`.is_leader`]: #method.is_leader
+/// [`wait`]: struct.Barrier.html#method.wait
+/// [`Barrier`]: struct.Barrier.html
 ///
 /// # Examples
 ///
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
index 71dd94161c0..0da65a4f2e1 100644
--- a/src/libstd/sync/mpsc/mod.rs
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -13,40 +13,50 @@
 //! This module provides message-based communication over channels, concretely
 //! defined among three types:
 //!
-//! * `Sender`
-//! * `SyncSender`
-//! * `Receiver`
+//! * [`Sender`]
+//! * [`SyncSender`]
+//! * [`Receiver`]
 //!
-//! A `Sender` or `SyncSender` is used to send data to a `Receiver`. Both
+//! A [`Sender`] or [`SyncSender`] is used to send data to a [`Receiver`]. Both
 //! senders are clone-able (multi-producer) such that many threads can send
 //! simultaneously to one receiver (single-consumer).
 //!
 //! These channels come in two flavors:
 //!
-//! 1. An asynchronous, infinitely buffered channel. The `channel()` function
+//! 1. An asynchronous, infinitely buffered channel. The [`channel`] function
 //!    will return a `(Sender, Receiver)` tuple where all sends will be
 //!    **asynchronous** (they never block). The channel conceptually has an
 //!    infinite buffer.
 //!
-//! 2. A synchronous, bounded channel. The `sync_channel()` function will return
-//!    a `(SyncSender, Receiver)` tuple where the storage for pending messages
-//!    is a pre-allocated buffer of a fixed size. All sends will be
+//! 2. A synchronous, bounded channel. The [`sync_channel`] function will
+//!    return a `(SyncSender, Receiver)` tuple where the storage for pending
+//!    messages is a pre-allocated buffer of a fixed size. All sends will be
 //!    **synchronous** by blocking until there is buffer space available. Note
-//!    that a bound of 0 is allowed, causing the channel to become a
-//!    "rendezvous" channel where each sender atomically hands off a message to
-//!    a receiver.
+//!    that a bound of 0 is allowed, causing the channel to become a "rendezvous"
+//!    channel where each sender atomically hands off a message to a receiver.
+//!
+//! [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html
+//! [`SyncSender`]: ../../../std/sync/mpsc/struct.SyncSender.html
+//! [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
+//! [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
+//! [`channel`]: ../../../std/sync/mpsc/fn.channel.html
+//! [`sync_channel`]: ../../../std/sync/mpsc/fn.sync_channel.html
 //!
 //! ## Disconnection
 //!
-//! The send and receive operations on channels will all return a `Result`
+//! The send and receive operations on channels will all return a [`Result`]
 //! indicating whether the operation succeeded or not. An unsuccessful operation
 //! is normally indicative of the other half of a channel having "hung up" by
 //! being dropped in its corresponding thread.
 //!
 //! Once half of a channel has been deallocated, most operations can no longer
-//! continue to make progress, so `Err` will be returned. Many applications will
-//! continue to `unwrap()` the results returned from this module, instigating a
-//! propagation of failure among threads if one unexpectedly dies.
+//! continue to make progress, so [`Err`] will be returned. Many applications
+//! will continue to [`unwrap`] the results returned from this module,
+//! instigating a propagation of failure among threads if one unexpectedly dies.
+//!
+//! [`Result`]: ../../../std/result/enum.Result.html
+//! [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+//! [`unwrap`]: ../../../std/result/enum.Result.html#method.unwrap
 //!
 //! # Examples
 //!
@@ -288,7 +298,31 @@ mod mpsc_queue;
 mod spsc_queue;
 
 /// The receiving-half of Rust's channel type. This half can only be owned by
-/// one thread
+/// one thread.
+///
+/// Messages sent to the channel can be retrieved using [`recv`].
+///
+/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+/// use std::time::Duration;
+///
+/// let (send, recv) = channel();
+///
+/// thread::spawn(move || {
+///     send.send("Hello world!").unwrap();
+///     thread::sleep(Duration::from_secs(2)); // block for two seconds
+///     send.send("Delayed for 2 seconds").unwrap();
+/// });
+///
+/// println!("{}", recv.recv().unwrap()); // Received immediately
+/// println!("Waiting...");
+/// println!("{}", recv.recv().unwrap()); // Received after 2 seconds
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Receiver<T> {
     inner: UnsafeCell<Flavor<T>>,
@@ -302,9 +336,12 @@ unsafe impl<T: Send> Send for Receiver<T> { }
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> !Sync for Receiver<T> { }
 
-/// An iterator over messages on a receiver, this iterator will block
-/// whenever `next` is called, waiting for a new message, and `None` will be
-/// returned when the corresponding channel has hung up.
+/// An iterator over messages on a receiver, this iterator will block whenever
+/// [`next`] is called, waiting for a new message, and [`None`] will be returned
+/// when the corresponding channel has hung up.
+///
+/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next
+/// [`None`]: ../../../std/option/enum.Option.html#variant.None
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug)]
 pub struct Iter<'a, T: 'a> {
@@ -312,11 +349,13 @@ pub struct Iter<'a, T: 'a> {
 }
 
 /// An iterator that attempts to yield all pending values for a receiver.
-/// `None` will be returned when there are no pending values remaining or
-/// if the corresponding channel has hung up.
+/// [`None`] will be returned when there are no pending values remaining or if
+/// the corresponding channel has hung up.
 ///
 /// This Iterator will never block the caller in order to wait for data to
-/// become available. Instead, it will return `None`.
+/// become available. Instead, it will return [`None`].
+///
+/// [`None`]: ../../../std/option/enum.Option.html#variant.None
 #[stable(feature = "receiver_try_iter", since = "1.15.0")]
 #[derive(Debug)]
 pub struct TryIter<'a, T: 'a> {
@@ -324,8 +363,12 @@ pub struct TryIter<'a, T: 'a> {
 }
 
 /// An owning iterator over messages on a receiver, this iterator will block
-/// whenever `next` is called, waiting for a new message, and `None` will be
+/// whenever [`next`] is called, waiting for a new message, and [`None`] will be
 /// returned when the corresponding channel has hung up.
+///
+/// [`next`]: ../../../std/iter/trait.Iterator.html#tymethod.next
+/// [`None`]: ../../../std/option/enum.Option.html#variant.None
+///
 #[stable(feature = "receiver_into_iter", since = "1.1.0")]
 #[derive(Debug)]
 pub struct IntoIter<T> {
@@ -334,6 +377,35 @@ pub struct IntoIter<T> {
 
 /// The sending-half of Rust's asynchronous channel type. This half can only be
 /// owned by one thread, but it can be cloned to send to other threads.
+///
+/// Messages can be sent through this channel with [`send`].
+///
+/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
+///
+/// # Examples
+///
+/// ```rust
+/// use std::sync::mpsc::channel;
+/// use std::thread;
+///
+/// let (sender, receiver) = channel();
+/// let sender2 = sender.clone();
+///
+/// // First thread owns sender
+/// thread::spawn(move || {
+///     sender.send(1).unwrap();
+/// });
+///
+/// // Second thread owns sender2
+/// thread::spawn(move || {
+///     sender2.send(2).unwrap();
+/// });
+///
+/// let msg = receiver.recv().unwrap();
+/// let msg2 = receiver.recv().unwrap();
+///
+/// assert_eq!(3, msg + msg2);
+/// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct Sender<T> {
     inner: UnsafeCell<Flavor<T>>,
@@ -349,6 +421,10 @@ impl<T> !Sync for Sender<T> { }
 
 /// The sending-half of Rust's synchronous channel type. This half can only be
 /// owned by one thread, but it can be cloned to send to other threads.
+///
+/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
+/// [`SyncSender::send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send
+///
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct SyncSender<T> {
     inner: Arc<sync::Packet<T>>,
@@ -360,25 +436,32 @@ unsafe impl<T: Send> Send for SyncSender<T> {}
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T> !Sync for SyncSender<T> {}
 
-/// An error returned from the `send` function on channels.
+/// An error returned from the [`send`] function on channels.
 ///
-/// A `send` operation can only fail if the receiving end of a channel is
+/// A [`send`] operation can only fail if the receiving end of a channel is
 /// disconnected, implying that the data could never be received. The error
 /// contains the data being sent as a payload so it can be recovered.
+///
+/// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(PartialEq, Eq, Clone, Copy)]
 pub struct SendError<T>(#[stable(feature = "rust1", since = "1.0.0")] pub T);
 
-/// An error returned from the `recv` function on a `Receiver`.
+/// An error returned from the [`recv`] function on a [`Receiver`].
 ///
-/// The `recv` operation can only fail if the sending half of a channel is
+/// The [`recv`] operation can only fail if the sending half of a channel is
 /// disconnected, implying that no further messages will ever be received.
+///
+/// [`recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv
+/// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct RecvError;
 
-/// This enumeration is the list of the possible reasons that `try_recv` could
+/// This enumeration is the list of the possible reasons that [`try_recv`] could
 /// not return data when called.
+///
+/// [`try_recv`]: ../../../std/sync/mpsc/struct.Receiver.html#method.try_recv
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum TryRecvError {
@@ -393,8 +476,10 @@ pub enum TryRecvError {
     Disconnected,
 }
 
-/// This enumeration is the list of possible errors that `recv_timeout` could
+/// This enumeration is the list of possible errors that [`recv_timeout`] could
 /// not return data when called.
+///
+/// [`recv_timeout`]: ../../../std/sync/mpsc/struct.Receiver.html#method.recv_timeout
 #[derive(PartialEq, Eq, Clone, Copy, Debug)]
 #[stable(feature = "mpsc_recv_timeout", since = "1.12.0")]
 pub enum RecvTimeoutError {
@@ -409,7 +494,9 @@ pub enum RecvTimeoutError {
 }
 
 /// This enumeration is the list of the possible error outcomes for the
-/// `SyncSender::try_send` method.
+/// [`SyncSender::try_send`] method.
+///
+/// [`SyncSender::try_send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.try_send
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(PartialEq, Eq, Clone, Copy)]
 pub enum TrySendError<T> {
@@ -556,10 +643,13 @@ impl<T> Sender<T> {
     /// A successful send occurs when it is determined that the other end of
     /// the channel has not hung up already. An unsuccessful send would be one
     /// where the corresponding receiver has already been deallocated. Note
-    /// that a return value of `Err` means that the data will never be
-    /// received, but a return value of `Ok` does *not* mean that the data
+    /// that a return value of [`Err`] means that the data will never be
+    /// received, but a return value of [`Ok`] does *not* mean that the data
     /// will be received.  It is possible for the corresponding receiver to
-    /// hang up immediately after this function returns `Ok`.
+    /// hang up immediately after this function returns [`Ok`].
+    ///
+    /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+    /// [`Ok`]: ../../../std/result/enum.Result.html#variant.Ok
     ///
     /// This method will never block the current thread.
     ///
@@ -702,9 +792,12 @@ impl<T> SyncSender<T> {
     /// time. If the buffer size is 0, however, it can be guaranteed that the
     /// receiver has indeed received the data if this function returns success.
     ///
-    /// This function will never panic, but it may return `Err` if the
-    /// `Receiver` has disconnected and is no longer able to receive
+    /// This function will never panic, but it may return [`Err`] if the
+    /// [`Receiver`] has disconnected and is no longer able to receive
     /// information.
+    ///
+    /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+    /// [`Receiver`]: ../../../std/sync/mpsc/struct.Receiver.html
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn send(&self, t: T) -> Result<(), SendError<T>> {
         self.inner.send(t).map_err(SendError)
@@ -712,13 +805,16 @@ impl<T> SyncSender<T> {
 
     /// Attempts to send a value on this channel without blocking.
     ///
-    /// This method differs from `send` by returning immediately if the
+    /// This method differs from [`send`] by returning immediately if the
     /// channel's buffer is full or no receiver is waiting to acquire some
-    /// data. Compared with `send`, this function has two failure cases
+    /// data. Compared with [`send`], this function has two failure cases
     /// instead of one (one for disconnection, one for a full buffer).
     ///
-    /// See `SyncSender::send` for notes about guarantees of whether the
+    /// See [`SyncSender::send`] for notes about guarantees of whether the
     /// receiver has received the data or not if this function is successful.
+    ///
+    /// [`send`]: ../../../std/sync/mpsc/struct.Sender.html#method.send
+    /// [`SyncSender::send`]: ../../../std/sync/mpsc/struct.SyncSender.html#method.send
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
         self.inner.try_send(t)
@@ -819,15 +915,18 @@ impl<T> Receiver<T> {
     ///
     /// This function will always block the current thread if there is no data
     /// available and it's possible for more data to be sent. Once a message is
-    /// sent to the corresponding `Sender`, then this receiver will wake up and
+    /// sent to the corresponding [`Sender`], then this receiver will wake up and
     /// return that message.
     ///
-    /// If the corresponding `Sender` has disconnected, or it disconnects while
-    /// this call is blocking, this call will wake up and return `Err` to
+    /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+    /// this call is blocking, this call will wake up and return [`Err`] to
     /// indicate that no more messages can ever be received on this channel.
     /// However, since channels are buffered, messages sent before the disconnect
     /// will still be properly received.
     ///
+    /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html
+    /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+    ///
     /// # Examples
     ///
     /// ```
@@ -907,15 +1006,18 @@ impl<T> Receiver<T> {
     ///
     /// This function will always block the current thread if there is no data
     /// available and it's possible for more data to be sent. Once a message is
-    /// sent to the corresponding `Sender`, then this receiver will wake up and
+    /// sent to the corresponding [`Sender`], then this receiver will wake up and
     /// return that message.
     ///
-    /// If the corresponding `Sender` has disconnected, or it disconnects while
-    /// this call is blocking, this call will wake up and return `Err` to
+    /// If the corresponding [`Sender`] has disconnected, or it disconnects while
+    /// this call is blocking, this call will wake up and return [`Err`] to
     /// indicate that no more messages can ever be received on this channel.
     /// However, since channels are buffered, messages sent before the disconnect
     /// will still be properly received.
     ///
+    /// [`Sender`]: ../../../std/sync/mpsc/struct.Sender.html
+    /// [`Err`]: ../../../std/result/enum.Result.html#variant.Err
+    ///
     /// # Examples
     ///
     /// ```no_run
@@ -993,7 +1095,29 @@ impl<T> Receiver<T> {
     }
 
     /// Returns an iterator that will block waiting for messages, but never
-    /// `panic!`. It will return `None` when the channel has hung up.
+    /// [`panic!`]. It will return [`None`] when the channel has hung up.
+    ///
+    /// [`panic!`]: ../../../std/macro.panic.html
+    /// [`None`]: ../../../std/option/enum.Option.html#variant.None
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use std::sync::mpsc::channel;
+    /// use std::thread;
+    ///
+    /// let (send, recv) = channel();
+    ///
+    /// thread::spawn(move || {
+    ///     send.send(1u8).unwrap();
+    ///     send.send(2u8).unwrap();
+    ///     send.send(3u8).unwrap();
+    /// });
+    ///
+    /// for x in recv.iter() {
+    ///     println!("Got: {}", x);
+    /// }
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn iter(&self) -> Iter<T> {
         Iter { rx: self }
@@ -1001,8 +1125,10 @@ impl<T> Receiver<T> {
 
     /// Returns an iterator that will attempt to yield all pending values.
     /// It will return `None` if there are no more pending values or if the
-    /// channel has hung up. The iterator will never `panic!` or block the
+    /// channel has hung up. The iterator will never [`panic!`] or block the
     /// user by waiting for values.
+    ///
+    /// [`panic!`]: ../../../std/macro.panic.html
     #[stable(feature = "receiver_try_iter", since = "1.15.0")]
     pub fn try_iter(&self) -> TryIter<T> {
         TryIter { rx: self }
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
index d79be2944c9..f2c178a1ad5 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -30,7 +30,7 @@ use sys_common::poison::{self, TryLockError, TryLockResult, LockResult};
 ///
 /// The mutexes in this module implement a strategy called "poisoning" where a
 /// mutex is considered poisoned whenever a thread panics while holding the
-/// lock. Once a mutex is poisoned, all other threads are unable to access the
+/// mutex. Once a mutex is poisoned, all other threads are unable to access the
 /// data by default as it is likely tainted (some invariant is not being
 /// upheld).
 ///
@@ -115,7 +115,7 @@ pub struct Mutex<T: ?Sized> {
     // Note that this mutex is in a *box*, not inlined into the struct itself.
     // Once a native mutex has been used once, its address can never change (it
     // can't be moved). This mutex type can be safely moved at any time, so to
-    // ensure that the native mutex is used correctly we box the inner lock to
+    // ensure that the native mutex is used correctly we box the inner mutex to
     // give it a constant address.
     inner: Box<sys::Mutex>,
     poison: poison::Flag,
@@ -183,7 +183,7 @@ impl<T: ?Sized> Mutex<T> {
     /// Acquires a mutex, blocking the current thread until it is able to do so.
     ///
     /// This function will block the local thread until it is available to acquire
-    /// the mutex. Upon returning, the thread is the only thread with the mutex
+    /// the mutex. Upon returning, the thread is the only thread with the lock
     /// held. An RAII guard is returned to allow scoped unlock of the lock. When
     /// the guard goes out of scope, the mutex will be unlocked.
     ///
@@ -267,9 +267,9 @@ impl<T: ?Sized> Mutex<T> {
         }
     }
 
-    /// Determines whether the lock is poisoned.
+    /// Determines whether the mutex is poisoned.
     ///
-    /// If another thread is active, the lock can still become poisoned at any
+    /// If another thread is active, the mutex can still become poisoned at any
     /// time. You should not trust a `false` value for program correctness
     /// without additional synchronization.
     ///
@@ -312,7 +312,7 @@ impl<T: ?Sized> Mutex<T> {
     #[stable(feature = "mutex_into_inner", since = "1.6.0")]
     pub fn into_inner(self) -> LockResult<T> where T: Sized {
         // We know statically that there are no outstanding references to
-        // `self` so there's no need to lock the inner lock.
+        // `self` so there's no need to lock the inner mutex.
         //
         // To get the inner value, we'd like to call `data.into_inner()`,
         // but because `Mutex` impl-s `Drop`, we can't move out of it, so
@@ -353,7 +353,7 @@ impl<T: ?Sized> Mutex<T> {
     #[stable(feature = "mutex_get_mut", since = "1.6.0")]
     pub fn get_mut(&mut self) -> LockResult<&mut T> {
         // We know statically that there are no other references to `self`, so
-        // there's no need to lock the inner lock.
+        // there's no need to lock the inner mutex.
         let data = unsafe { &mut *self.data.get() };
         poison::map_result(self.poison.borrow(), |_| data )
     }
diff --git a/src/libstd/sys/unix/ext/io.rs b/src/libstd/sys/unix/ext/io.rs
index 75aa72e3cff..296235e173d 100644
--- a/src/libstd/sys/unix/ext/io.rs
+++ b/src/libstd/sys/unix/ext/io.rs
@@ -73,13 +73,6 @@ pub trait IntoRawFd {
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
-impl AsRawFd for RawFd {
-    fn as_raw_fd(&self) -> RawFd {
-        *self
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
 impl AsRawFd for fs::File {
     fn as_raw_fd(&self) -> RawFd {
         self.as_inner().fd().raw()
@@ -91,14 +84,6 @@ impl FromRawFd for fs::File {
         fs::File::from_inner(sys::fs::File::from_inner(fd))
     }
 }
-
-#[stable(feature = "into_raw_os", since = "1.4.0")]
-impl IntoRawFd for RawFd {
-    fn into_raw_fd(self) -> RawFd {
-        self
-    }
-}
-
 #[stable(feature = "into_raw_os", since = "1.4.0")]
 impl IntoRawFd for fs::File {
     fn into_raw_fd(self) -> RawFd {
diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs
index c57751a01d7..854d380d128 100644
--- a/src/libstd/sys/unix/mod.rs
+++ b/src/libstd/sys/unix/mod.rs
@@ -92,7 +92,7 @@ pub fn init() {
 
     #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))]
     unsafe fn reset_sigpipe() {
-        assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0);
+        assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR);
     }
     #[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))]
     unsafe fn reset_sigpipe() {}
diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs
index 51e00fc1ab9..706256ff10e 100644
--- a/src/libstd/sys/unix/pipe.rs
+++ b/src/libstd/sys/unix/pipe.rs
@@ -8,11 +8,9 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use cmp;
 use io;
 use libc::{self, c_int};
 use mem;
-use ptr;
 use sys::{cvt, cvt_r};
 use sys::fd::FileDesc;
 
@@ -80,16 +78,14 @@ pub fn read2(p1: AnonPipe,
     p1.set_nonblocking(true)?;
     p2.set_nonblocking(true)?;
 
-    let max = cmp::max(p1.raw(), p2.raw());
+    let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
+    fds[0].fd = p1.raw();
+    fds[0].events = libc::POLLIN;
+    fds[1].fd = p2.raw();
+    fds[1].events = libc::POLLIN;
     loop {
-        // wait for either pipe to become readable using `select`
-        cvt_r(|| unsafe {
-            let mut read: libc::fd_set = mem::zeroed();
-            libc::FD_SET(p1.raw(), &mut read);
-            libc::FD_SET(p2.raw(), &mut read);
-            libc::select(max + 1, &mut read, ptr::null_mut(), ptr::null_mut(),
-                         ptr::null_mut())
-        })?;
+        // wait for either pipe to become readable using `poll`
+        cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?;
 
         // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
         // EAGAIN. If we hit EOF, then this will happen because the underlying
@@ -109,11 +105,11 @@ pub fn read2(p1: AnonPipe,
                 }
             }
         };
-        if read(&p1, v1)? {
+        if fds[0].revents != 0 && read(&p1, v1)? {
             p2.set_nonblocking(false)?;
             return p2.read_to_end(v2).map(|_| ());
         }
-        if read(&p2, v2)? {
+        if fds[1].revents != 0 && read(&p2, v2)? {
             p1.set_nonblocking(false)?;
             return p1.read_to_end(v1).map(|_| ());
         }
diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs
index c63dd8a47ca..d6e2fed56be 100644
--- a/src/libstd/sys/windows/ext/fs.rs
+++ b/src/libstd/sys/windows/ext/fs.rs
@@ -144,7 +144,7 @@ pub trait OpenOptionsExt {
     /// `CreateFile`).
     ///
     /// If a _new_ file is created because it does not yet exist and
-    ///`.create(true)` or `.create_new(true)` are specified, the new file is
+    /// `.create(true)` or `.create_new(true)` are specified, the new file is
     /// given the attributes declared with `.attributes()`.
     ///
     /// If an _existing_ file is opened with `.create(true).truncate(true)`, its
diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs
index 1419a4af427..759f055c4b1 100644
--- a/src/libstd/sys/windows/ext/process.rs
+++ b/src/libstd/sys/windows/ext/process.rs
@@ -104,6 +104,7 @@ pub trait CommandExt {
     /// Sets the [process creation flags][1] to be passed to `CreateProcess`.
     ///
     /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`.
+    ///
     /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx
     #[stable(feature = "windows_process_extensions", since = "1.16.0")]
     fn creation_flags(&mut self, flags: u32) -> &mut process::Command;
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index edf928d6106..7ab6b82ada3 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -90,7 +90,7 @@
 //! two ways:
 //!
 //! * By spawning a new thread, e.g. using the [`thread::spawn`][`spawn`]
-//!   function, and calling [`thread`] on the [`JoinHandle`].
+//!   function, and calling [`thread`][`JoinHandle::thread`] on the [`JoinHandle`].
 //! * By requesting the current thread, using the [`thread::current`] function.
 //!
 //! The [`thread::current`] function is available even for threads not spawned
@@ -151,14 +151,14 @@
 //! [`Arc`]: ../../std/sync/struct.Arc.html
 //! [`spawn`]: ../../std/thread/fn.spawn.html
 //! [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
-//! [`thread`]: ../../std/thread/struct.JoinHandle.html#method.thread
+//! [`JoinHandle::thread`]: ../../std/thread/struct.JoinHandle.html#method.thread
 //! [`join`]: ../../std/thread/struct.JoinHandle.html#method.join
 //! [`Result`]: ../../std/result/enum.Result.html
 //! [`Ok`]: ../../std/result/enum.Result.html#variant.Ok
 //! [`Err`]: ../../std/result/enum.Result.html#variant.Err
 //! [`panic!`]: ../../std/macro.panic.html
 //! [`Builder`]: ../../std/thread/struct.Builder.html
-//! [`thread::current`]: ../../std/thread/fn.spawn.html
+//! [`thread::current`]: ../../std/thread/fn.current.html
 //! [`Thread`]: ../../std/thread/struct.Thread.html
 //! [`park`]: ../../std/thread/fn.park.html
 //! [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
index c79040424f6..e7c5d8278d9 100644
--- a/src/libsyntax/ext/derive.rs
+++ b/src/libsyntax/ext/derive.rs
@@ -26,7 +26,8 @@ pub fn collect_derives(cx: &mut ExtCtxt, attrs: &mut Vec<ast::Attribute>) -> Vec
             return true;
         }
 
-        match attr.parse_list(cx.parse_sess, |parser| parser.parse_path(PathStyle::Mod)) {
+        match attr.parse_list(cx.parse_sess,
+                              |parser| parser.parse_path_allowing_meta(PathStyle::Mod)) {
             Ok(ref traits) if traits.is_empty() => {
                 cx.span_warn(attr.span, "empty trait list in `derive`");
                 false
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 12d25ca4274..550f1160bed 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -292,9 +292,6 @@ declare_features! (
     // Allows attributes on lifetime/type formal parameters in generics (RFC 1327)
     (active, generic_param_attrs, "1.11.0", Some(34761)),
 
-    // The #![windows_subsystem] attribute
-    (active, windows_subsystem, "1.14.0", Some(37499)),
-
     // Allows #[link(..., cfg(..))]
     (active, link_cfg, "1.14.0", Some(37406)),
 
@@ -337,11 +334,15 @@ declare_features! (
     // `extern "x86-interrupt" fn()`
     (active, abi_x86_interrupt, "1.17.0", Some(40180)),
 
+
     // Allows the `catch {...}` expression
     (active, catch_expr, "1.17.0", Some(31436)),
 
     // See rust-lang/rfcs#1414. Allows code like `let x: &'static u32 = &42` to work.
     (active, rvalue_static_promotion, "1.15.1", Some(38865)),
+
+    // Used to preserve symbols (see llvm.used)
+    (active, used, "1.18.0", Some(40289)),
 );
 
 declare_features! (
@@ -408,7 +409,8 @@ declare_features! (
     (accepted, static_recursion, "1.17.0", Some(29719)),
     // pub(restricted) visibilities (RFC 1422)
     (accepted, pub_restricted, "1.17.0", Some(32409)),
-
+    // The #![windows_subsystem] attribute
+    (accepted, windows_subsystem, "1.18.0", Some(37499)),
 );
 // If you change this, please modify src/doc/unstable-book as well. You must
 // move that documentation into the relevant place in the other docs, and
@@ -748,6 +750,10 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                   "unwind_attributes",
                                   "#[unwind] is experimental",
                                   cfg_fn!(unwind_attributes))),
+    ("used", Whitelisted, Gated(
+        Stability::Unstable, "used",
+        "the `#[used]` attribute is an experimental feature",
+        cfg_fn!(used))),
 
     // used in resolve
     ("prelude_import", Whitelisted, Gated(Stability::Unstable,
@@ -768,11 +774,7 @@ pub const BUILTIN_ATTRIBUTES: &'static [(&'static str, AttributeType, AttributeG
                                         "unboxed_closures are still evolving",
                                         cfg_fn!(unboxed_closures))),
 
-    ("windows_subsystem", Whitelisted, Gated(Stability::Unstable,
-                                             "windows_subsystem",
-                                             "the windows subsystem attribute \
-                                              is currently unstable",
-                                             cfg_fn!(windows_subsystem))),
+    ("windows_subsystem", Whitelisted, Ungated),
 
     ("proc_macro_attribute", Normal, Gated(Stability::Unstable,
                                            "proc_macro",
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index 23fc1351426..43d21015a4f 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -570,20 +570,33 @@ impl<'a> Parser<'a> {
             expected.dedup();
             let expect = tokens_to_string(&expected[..]);
             let actual = self.this_token_to_string();
-            Err(self.fatal(
-                &(if expected.len() > 1 {
-                    (format!("expected one of {}, found `{}`",
-                             expect,
-                             actual))
-                } else if expected.is_empty() {
-                    (format!("unexpected token: `{}`",
-                             actual))
+            let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
+                let short_expect = if expected.len() > 6 {
+                    format!("{} possible tokens", expected.len())
                 } else {
-                    (format!("expected {}, found `{}`",
-                             expect,
-                             actual))
-                })[..]
-            ))
+                    expect.clone()
+                };
+                (format!("expected one of {}, found `{}`", expect, actual),
+                 (self.prev_span.next_point(), format!("expected one of {} here", short_expect)))
+            } else if expected.is_empty() {
+                (format!("unexpected token: `{}`", actual),
+                 (self.prev_span, "unexpected token after this".to_string()))
+            } else {
+                (format!("expected {}, found `{}`", expect, actual),
+                 (self.prev_span.next_point(), format!("expected {} here", expect)))
+            };
+            let mut err = self.fatal(&msg_exp);
+            let sp = if self.token == token::Token::Eof {
+                // This is EOF, don't want to point at the following char, but rather the last token
+                self.prev_span
+            } else {
+                label_sp
+            };
+            err.span_label(sp, &label_exp);
+            if !sp.source_equal(&self.span) {
+                err.span_label(self.span, &"unexpected token");
+            }
+            Err(err)
         }
     }
 
@@ -1773,6 +1786,26 @@ impl<'a> Parser<'a> {
         })
     }
 
+    /// Like `parse_path`, but also supports parsing `Word` meta items into paths for back-compat.
+    /// This is used when parsing derive macro paths in `#[derive]` attributes.
+    pub fn parse_path_allowing_meta(&mut self, mode: PathStyle) -> PResult<'a, ast::Path> {
+        let meta_ident = match self.token {
+            token::Interpolated(ref nt) => match **nt {
+                token::NtMeta(ref meta) => match meta.node {
+                    ast::MetaItemKind::Word => Some(ast::Ident::with_empty_ctxt(meta.name)),
+                    _ => None,
+                },
+                _ => None,
+            },
+            _ => None,
+        };
+        if let Some(ident) = meta_ident {
+            self.bump();
+            return Ok(ast::Path::from_ident(self.prev_span, ident));
+        }
+        self.parse_path(mode)
+    }
+
     /// Examples:
     /// - `a::b<T,U>::c<V,W>`
     /// - `a::b<T,U>::c(V) -> W`
@@ -4667,25 +4700,30 @@ impl<'a> Parser<'a> {
         })
     }
 
-    fn complain_if_pub_macro(&mut self, visa: &Visibility, span: Span) {
-        match *visa {
-            Visibility::Inherited => (),
+    fn complain_if_pub_macro(&mut self, vis: &Visibility, sp: Span) {
+        if let Err(mut err) = self.complain_if_pub_macro_diag(vis, sp) {
+            err.emit();
+        }
+    }
+
+    fn complain_if_pub_macro_diag(&mut self, vis: &Visibility, sp: Span) -> PResult<'a, ()> {
+        match *vis {
+            Visibility::Inherited => Ok(()),
             _ => {
                 let is_macro_rules: bool = match self.token {
                     token::Ident(sid) => sid.name == Symbol::intern("macro_rules"),
                     _ => false,
                 };
                 if is_macro_rules {
-                    self.diagnostic().struct_span_err(span, "can't qualify macro_rules \
-                                                             invocation with `pub`")
-                                     .help("did you mean #[macro_export]?")
-                                     .emit();
+                    let mut err = self.diagnostic()
+                        .struct_span_err(sp, "can't qualify macro_rules invocation with `pub`");
+                    err.help("did you mean #[macro_export]?");
+                    Err(err)
                 } else {
-                    self.diagnostic().struct_span_err(span, "can't qualify macro \
-                                                             invocation with `pub`")
-                                     .help("try adjusting the macro to put `pub` \
-                                            inside the invocation")
-                                     .emit();
+                    let mut err = self.diagnostic()
+                        .struct_span_err(sp, "can't qualify macro invocation with `pub`");
+                    err.help("try adjusting the macro to put `pub` inside the invocation");
+                    Err(err)
                 }
             }
         }
@@ -4696,14 +4734,36 @@ impl<'a> Parser<'a> {
                          -> PResult<'a, (Ident, Vec<ast::Attribute>, ast::ImplItemKind)> {
         // code copied from parse_macro_use_or_failure... abstraction!
         if self.token.is_path_start() {
-            // method macro.
+            // Method macro.
 
             let prev_span = self.prev_span;
-            self.complain_if_pub_macro(&vis, prev_span);
+            // Before complaining about trying to set a macro as `pub`,
+            // check if `!` comes after the path.
+            let err = self.complain_if_pub_macro_diag(&vis, prev_span);
 
             let lo = self.span;
             let pth = self.parse_path(PathStyle::Mod)?;
-            self.expect(&token::Not)?;
+            let bang_err = self.expect(&token::Not);
+            if let Err(mut err) = err {
+                if let Err(mut bang_err) = bang_err {
+                    // Given this code `pub path(`, it seems like this is not setting the
+                    // visibility of a macro invocation, but rather a mistyped method declaration.
+                    // Create a diagnostic pointing out that `fn` is missing.
+                    //
+                    // x |     pub path(&self) {
+                    //   |        ^ missing `fn` for method declaration
+
+                    err.cancel();
+                    bang_err.cancel();
+                    //     pub  path(
+                    //        ^^ `sp` below will point to this
+                    let sp = prev_span.between(self.prev_span);
+                    err = self.diagnostic()
+                        .struct_span_err(sp, "missing `fn` for method declaration");
+                    err.span_label(sp, &"missing `fn`");
+                }
+                return Err(err);
+            }
 
             // eat a matched-delimiter token tree:
             let (delim, tts) = self.expect_delimited_token_tree()?;
diff --git a/src/libsyntax/ptr.rs b/src/libsyntax/ptr.rs
index 58750158931..15111bbba0a 100644
--- a/src/libsyntax/ptr.rs
+++ b/src/libsyntax/ptr.rs
@@ -43,6 +43,8 @@ use std::{mem, ptr, slice, vec};
 
 use serialize::{Encodable, Decodable, Encoder, Decoder};
 
+use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
+                                           HashStable};
 /// An owned smart pointer.
 #[derive(Hash, PartialEq, Eq, PartialOrd, Ord)]
 pub struct P<T: ?Sized> {
@@ -215,3 +217,13 @@ impl<T: Decodable> Decodable for P<[T]> {
         }))
     }
 }
+
+impl<CTX, T> HashStable<CTX> for P<T>
+    where T: ?Sized + HashStable<CTX>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (**self).hash_stable(hcx, hasher);
+    }
+}
diff --git a/src/libsyntax/util/rc_slice.rs b/src/libsyntax/util/rc_slice.rs
index 195fb23f9d8..2d9fd7aa875 100644
--- a/src/libsyntax/util/rc_slice.rs
+++ b/src/libsyntax/util/rc_slice.rs
@@ -12,6 +12,9 @@ use std::fmt;
 use std::ops::Deref;
 use std::rc::Rc;
 
+use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult,
+                                           HashStable};
+
 #[derive(Clone)]
 pub struct RcSlice<T> {
     data: Rc<Box<[T]>>,
@@ -41,3 +44,13 @@ impl<T: fmt::Debug> fmt::Debug for RcSlice<T> {
         fmt::Debug::fmt(self.deref(), f)
     }
 }
+
+impl<CTX, T> HashStable<CTX> for RcSlice<T>
+    where T: HashStable<CTX>
+{
+    fn hash_stable<W: StableHasherResult>(&self,
+                                          hcx: &mut CTX,
+                                          hasher: &mut StableHasher<W>) {
+        (**self).hash_stable(hcx, hasher);
+    }
+}
diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs
index 947192a0a23..9b88b9f7696 100644
--- a/src/libsyntax_pos/lib.rs
+++ b/src/libsyntax_pos/lib.rs
@@ -83,7 +83,13 @@ impl Span {
     /// Returns a new span representing just the end-point of this span
     pub fn end_point(self) -> Span {
         let lo = cmp::max(self.hi.0 - 1, self.lo.0);
-        Span { lo: BytePos(lo), hi: self.hi, ctxt: self.ctxt }
+        Span { lo: BytePos(lo), ..self }
+    }
+
+    /// Returns a new span representing the next character after the end-point of this span
+    pub fn next_point(self) -> Span {
+        let lo = cmp::max(self.hi.0, self.lo.0 + 1);
+        Span { lo: BytePos(lo), hi: BytePos(lo + 1), ..self }
     }
 
     /// Returns `self` if `self` is not the dummy span, and `other` otherwise.
@@ -183,6 +189,30 @@ impl Span {
             Span { hi: end.hi, ..self }
         }
     }
+
+    pub fn between(self, end: Span) -> Span {
+        Span {
+            lo: self.hi,
+            hi: end.lo,
+            ctxt: if end.ctxt == SyntaxContext::empty() {
+                end.ctxt
+            } else {
+                self.ctxt
+            }
+        }
+    }
+
+    pub fn until(self, end: Span) -> Span {
+        Span {
+            lo: self.lo,
+            hi: end.lo,
+            ctxt: if end.ctxt == SyntaxContext::empty() {
+                end.ctxt
+            } else {
+                self.ctxt
+            }
+        }
+    }
 }
 
 #[derive(Clone, Debug)]
diff --git a/src/libtest/stats.rs b/src/libtest/stats.rs
index 077d57a9da3..f04394f7166 100644
--- a/src/libtest/stats.rs
+++ b/src/libtest/stats.rs
@@ -39,8 +39,10 @@ pub trait Stats {
     ///
     /// Note: this method sacrifices performance at the altar of accuracy
     /// Depends on IEEE-754 arithmetic guarantees. See proof of correctness at:
-    /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric Predicates"]
-    /// (http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps)
+    /// ["Adaptive Precision Floating-Point Arithmetic and Fast Robust Geometric
+    /// Predicates"][paper]
+    ///
+    /// [paper]: http://www.cs.cmu.edu/~quake-papers/robust-arithmetic.ps
     fn sum(&self) -> f64;
 
     /// Minimum value of the samples.
diff --git a/src/libunwind/build.rs b/src/libunwind/build.rs
index ed3d5212bf2..9b8099d55a0 100644
--- a/src/libunwind/build.rs
+++ b/src/libunwind/build.rs
@@ -35,7 +35,8 @@ fn main() {
     } else if target.contains("dragonfly") {
         println!("cargo:rustc-link-lib=gcc_pic");
     } else if target.contains("windows-gnu") {
-        println!("cargo:rustc-link-lib=gcc_eh");
+        println!("cargo:rustc-link-lib=static-nobundle=gcc_eh");
+        println!("cargo:rustc-link-lib=static-nobundle=pthread");
     } else if target.contains("fuchsia") {
         println!("cargo:rustc-link-lib=unwind");
     }
diff --git a/src/libunwind/lib.rs b/src/libunwind/lib.rs
index 7fa2ce650fd..d4d52322ada 100644
--- a/src/libunwind/lib.rs
+++ b/src/libunwind/lib.rs
@@ -17,6 +17,7 @@
 #![feature(cfg_target_vendor)]
 #![feature(staged_api)]
 #![feature(unwind_attributes)]
+#![feature(static_nobundle)]
 
 #![cfg_attr(not(target_env = "msvc"), feature(libc))]
 
diff --git a/src/test/codegen/personality_lifetimes.rs b/src/test/codegen/personality_lifetimes.rs
new file mode 100644
index 00000000000..e0de64b26df
--- /dev/null
+++ b/src/test/codegen/personality_lifetimes.rs
@@ -0,0 +1,41 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-msvc
+
+// compile-flags: -O -C no-prepopulate-passes
+
+#![crate_type="lib"]
+
+struct S;
+
+impl Drop for S {
+    fn drop(&mut self) {
+    }
+}
+
+fn might_unwind() {
+}
+
+// CHECK-LABEL: @test
+#[no_mangle]
+pub fn test() {
+    let _s = S;
+    // Check that the personality slot alloca gets a lifetime start in each cleanup block, not just
+    // in the first one.
+    // CHECK-LABEL: cleanup:
+    // CHECK: bitcast{{.*}}personalityslot
+    // CHECK-NEXT: call void @llvm.lifetime.start
+    // CHECK-LABEL: cleanup1:
+    // CHECK: bitcast{{.*}}personalityslot
+    // CHECK-NEXT: call void @llvm.lifetime.start
+    might_unwind();
+    might_unwind();
+}
diff --git a/src/test/compile-fail/feature-gate-used.rs b/src/test/compile-fail/feature-gate-used.rs
new file mode 100644
index 00000000000..68679d7dac8
--- /dev/null
+++ b/src/test/compile-fail/feature-gate-used.rs
@@ -0,0 +1,15 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#[used]
+fn foo() {}
+//~^^ ERROR the `#[used]` attribute is an experimental feature
+
+fn main() {}
diff --git a/src/test/compile-fail/issue-40610.rs b/src/test/compile-fail/issue-40610.rs
new file mode 100644
index 00000000000..aec20b4ad87
--- /dev/null
+++ b/src/test/compile-fail/issue-40610.rs
@@ -0,0 +1,16 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn f(_: &[f32]) {}
+
+fn main() {
+    () + f(&[1.0]);
+    //~^ ERROR binary operation `+` cannot be applied to type `()`
+}
diff --git a/src/test/compile-fail/issue-40861.rs b/src/test/compile-fail/issue-40861.rs
new file mode 100644
index 00000000000..e525b3954f5
--- /dev/null
+++ b/src/test/compile-fail/issue-40861.rs
@@ -0,0 +1,16 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn f(_: &[f32]) {}
+
+fn main() {
+    ()[f(&[1.0])];
+    //~^ ERROR cannot index a value of type `()`
+}
diff --git a/src/test/compile-fail/windows-subsystem-invalid.rs b/src/test/compile-fail/windows-subsystem-invalid.rs
index e0003440719..7772cfd6a2c 100644
--- a/src/test/compile-fail/windows-subsystem-invalid.rs
+++ b/src/test/compile-fail/windows-subsystem-invalid.rs
@@ -10,7 +10,6 @@
 
 // error-pattern: invalid windows subsystem `wrong`, only `windows` and `console` are allowed
 
-#![feature(windows_subsystem)]
 #![windows_subsystem = "wrong"]
 
 fn main() {}
diff --git a/src/test/parse-fail/match-refactor-to-expr.rs b/src/test/parse-fail/match-refactor-to-expr.rs
index 37b66601e70..e2fee1d1895 100644
--- a/src/test/parse-fail/match-refactor-to-expr.rs
+++ b/src/test/parse-fail/match-refactor-to-expr.rs
@@ -14,7 +14,9 @@ fn main() {
     let foo =
         match //~ NOTE did you mean to remove this `match` keyword?
         Some(4).unwrap_or_else(5)
-        ; //~ ERROR expected one of `.`, `?`, `{`, or an operator, found `;`
+        //~^ NOTE expected one of `.`, `?`, `{`, or an operator here
+        ; //~ NOTE unexpected token
+        //~^ ERROR expected one of `.`, `?`, `{`, or an operator, found `;`
 
     println!("{}", foo)
 }
diff --git a/src/test/run-make/multiple-emits/Makefile b/src/test/run-make/multiple-emits/Makefile
new file mode 100644
index 00000000000..e126422835c
--- /dev/null
+++ b/src/test/run-make/multiple-emits/Makefile
@@ -0,0 +1,7 @@
+-include ../tools.mk
+
+all:
+	$(RUSTC) foo.rs --emit=asm,llvm-ir -o $(TMPDIR)/out 2>&1
+	rm $(TMPDIR)/out.ll $(TMPDIR)/out.s
+	$(RUSTC) foo.rs --emit=asm,llvm-ir -o $(TMPDIR)/out2.ext 2>&1
+	rm $(TMPDIR)/out2.ll $(TMPDIR)/out2.s
diff --git a/src/test/run-make/multiple-emits/foo.rs b/src/test/run-make/multiple-emits/foo.rs
new file mode 100644
index 00000000000..8ae3d072362
--- /dev/null
+++ b/src/test/run-make/multiple-emits/foo.rs
@@ -0,0 +1,11 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {}
diff --git a/src/test/run-make/save-analysis-fail/foo.rs b/src/test/run-make/save-analysis-fail/foo.rs
index e331f65abb7..a996aa4fad5 100644
--- a/src/test/run-make/save-analysis-fail/foo.rs
+++ b/src/test/run-make/save-analysis-fail/foo.rs
@@ -448,3 +448,8 @@ fn test_format_args() {
     print!("{0} + {} = {}", x, y);
     print!("x is {}, y is {1}, name is {n}", x, y, n = name);
 }
+
+extern {
+    static EXTERN_FOO: u8;
+    fn extern_foo(a: u8, b: i32) -> String;
+}
diff --git a/src/test/run-make/save-analysis/foo.rs b/src/test/run-make/save-analysis/foo.rs
index e8b69729af6..3fe1479f5f2 100644
--- a/src/test/run-make/save-analysis/foo.rs
+++ b/src/test/run-make/save-analysis/foo.rs
@@ -11,6 +11,7 @@
 #![ crate_name = "test" ]
 #![feature(box_syntax)]
 #![feature(rustc_private)]
+#![feature(associated_type_defaults)]
 
 extern crate graphviz;
 // A simple rust project
@@ -441,3 +442,19 @@ fn test_format_args() {
     print!("{0} + {} = {}", x, y);
     print!("x is {}, y is {1}, name is {n}", x, y, n = name);
 }
+
+struct FrameBuffer;
+
+struct SilenceGenerator;
+
+impl Iterator for SilenceGenerator {
+    type Item = FrameBuffer;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        panic!();
+    }
+}
+
+trait Foo {
+    type Bar = FrameBuffer;
+}
diff --git a/src/test/run-make/used/Makefile b/src/test/run-make/used/Makefile
new file mode 100644
index 00000000000..9d7aa30f874
--- /dev/null
+++ b/src/test/run-make/used/Makefile
@@ -0,0 +1,11 @@
+-include ../tools.mk
+
+ifdef IS_WINDOWS
+# Do nothing on MSVC.
+all:
+	exit 0
+else
+all:
+	$(RUSTC) -C opt-level=3 --emit=obj used.rs
+	nm $(TMPDIR)/used.o | grep FOO
+endif
diff --git a/src/test/run-make/used/used.rs b/src/test/run-make/used/used.rs
new file mode 100644
index 00000000000..186cd0fdf5e
--- /dev/null
+++ b/src/test/run-make/used/used.rs
@@ -0,0 +1,17 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "lib"]
+#![feature(used)]
+
+#[used]
+static FOO: u32 = 0;
+
+static BAR: u32 = 0;
diff --git a/src/test/run-make/windows-subsystem/console.rs b/src/test/run-make/windows-subsystem/console.rs
index 3aedb0ecab7..ffad1e35ee6 100644
--- a/src/test/run-make/windows-subsystem/console.rs
+++ b/src/test/run-make/windows-subsystem/console.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(windows_subsystem)]
 #![windows_subsystem = "console"]
 
 fn main() {}
diff --git a/src/test/run-make/windows-subsystem/windows.rs b/src/test/run-make/windows-subsystem/windows.rs
index 5d875a5a1bf..33cbe320591 100644
--- a/src/test/run-make/windows-subsystem/windows.rs
+++ b/src/test/run-make/windows-subsystem/windows.rs
@@ -8,7 +8,6 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(windows_subsystem)]
 #![windows_subsystem = "windows"]
 
 fn main() {}
diff --git a/src/test/run-pass/const-err.rs b/src/test/run-pass/const-err.rs
index a1c9ff8a21e..f7f79356a0b 100644
--- a/src/test/run-pass/const-err.rs
+++ b/src/test/run-pass/const-err.rs
@@ -13,6 +13,10 @@
 #![deny(const_err)]
 
 const X: *const u8 = b"" as _;
+const Y: bool = 'A' == 'B';
+const Z: char = 'A';
+const W: bool = Z <= 'B';
+
 
 fn main() {
     let _ = ((-1 as i8) << 8 - 1) as f32;
diff --git a/src/test/compile-fail/windows-subsystem-gated.rs b/src/test/run-pass/issue-40962.rs
index 63f891a2af7..b35cfa12eab 100644
--- a/src/test/compile-fail/windows-subsystem-gated.rs
+++ b/src/test/run-pass/issue-40962.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,9 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// gate-test-windows_subsystem
+macro_rules! m {
+    ($i:meta) => {
+        #[derive($i)]
+        struct S;
+    }
+}
 
-#![windows_subsystem = "console"]
-//~^ ERROR: the windows subsystem attribute is currently unstable
+m!(Clone);
 
 fn main() {}
diff --git a/src/test/rustdoc/check-hard-break.rs b/src/test/rustdoc/check-hard-break.rs
new file mode 100644
index 00000000000..f048b64d104
--- /dev/null
+++ b/src/test/rustdoc/check-hard-break.rs
@@ -0,0 +1,20 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+// ignore-tidy-end-whitespace
+
+// @has foo/fn.f.html
+// @has - '<p>hard break:<br />'
+// @has - 'after hard break</p>'
+/// hard break:  
+/// after hard break
+pub fn f() {}
diff --git a/src/test/rustdoc/check-rule-image-footnote.rs b/src/test/rustdoc/check-rule-image-footnote.rs
new file mode 100644
index 00000000000..46542677857
--- /dev/null
+++ b/src/test/rustdoc/check-rule-image-footnote.rs
@@ -0,0 +1,44 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+// ignore-tidy-linelength
+
+// @has foo/fn.f.html
+// @has - '<p>markdown test</p>'
+// @has - '<p>this is a <a href="https://example.com" title="this is a title">link</a>.</p>'
+// @has - '<hr />'
+// @has - '<p>a footnote<sup id="supref1"><a href="#ref1">1</a></sup>.</p>'
+// @has - '<p>another footnote<sup id="supref2"><a href="#ref2">2</a></sup>.</p>'
+// @has - '<p><img src="https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png" alt="Rust" /></p>'
+// @has - '<div class="footnotes"><hr><ol><li id="ref1">'
+// @has - '<p>Thing&nbsp;<a href="#supref1" rev="footnote">↩</a></p></li><li id="ref2">'
+// @has - '<p>Another Thing&nbsp;<a href="#supref2" rev="footnote">↩</a></p></li></ol></div>'
+/// markdown test
+///
+/// this is a [link].
+///
+/// [link]: https://example.com "this is a title"
+///
+/// -----------
+///
+/// a footnote[^footnote].
+///
+/// another footnote[^footnotebis].
+///
+/// [^footnote]: Thing
+///
+///
+/// [^footnotebis]: Another Thing
+///
+///
+/// ![Rust](https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png)
+pub fn f() {}
diff --git a/src/test/rustdoc/test-lists.rs b/src/test/rustdoc/test-lists.rs
new file mode 100644
index 00000000000..29f157e0425
--- /dev/null
+++ b/src/test/rustdoc/test-lists.rs
@@ -0,0 +1,36 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_name = "foo"]
+
+// @has foo/fn.f.html
+// @has - //ol/li "list"
+// @has - //ol/li/ol/li "fooooo"
+// @has - //ol/li/ol/li "x"
+// @has - //ol/li "foo"
+/// 1. list
+///     1. fooooo
+///     2. x
+/// 2. foo
+pub fn f() {}
+
+// @has foo/fn.foo2.html
+// @has - //ul/li "normal list"
+// @has - //ul/li/ul/li "sub list"
+// @has - //ul/li/ul/li "new elem still same elem and again same elem!"
+// @has - //ul/li "new big elem"
+/// * normal list
+///     * sub list
+///     * new elem
+///       still same elem
+///
+///       and again same elem!
+/// * new big elem
+pub fn foo2() {}
diff --git a/src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs
index 158d3606104..a72ad0351e3 100644
--- a/src/test/compile-fail/coherence-overlapping-inherent-impl-trait.rs
+++ b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.rs
@@ -11,6 +11,6 @@
 #![allow(dead_code)]
 
 trait C {}
-impl C { fn f() {} } //~ ERROR duplicate definitions with name `f`
+impl C { fn f() {} }
 impl C { fn f() {} }
 fn main() { }
diff --git a/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr
new file mode 100644
index 00000000000..7f1ab929c6f
--- /dev/null
+++ b/src/test/ui/codemap_tests/coherence-overlapping-inherent-impl-trait.stderr
@@ -0,0 +1,10 @@
+error[E0592]: duplicate definitions with name `f`
+  --> $DIR/coherence-overlapping-inherent-impl-trait.rs:14:10
+   |
+14 | impl C { fn f() {} }
+   |          ^^^^^^^^^ duplicate definitions for `f`
+15 | impl C { fn f() {} }
+   |          --------- other definition for `f`
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/inherent-overlap.rs b/src/test/ui/codemap_tests/overlapping_inherent_impls.rs
index 18e77ddfd2c..a626b63b31b 100644
--- a/src/test/compile-fail/inherent-overlap.rs
+++ b/src/test/ui/codemap_tests/overlapping_inherent_impls.rs
@@ -16,7 +16,7 @@
 struct Foo;
 
 impl Foo {
-    fn id() {} //~ ERROR duplicate definitions
+    fn id() {}
 }
 
 impl Foo {
@@ -26,7 +26,7 @@ impl Foo {
 struct Bar<T>(T);
 
 impl<T> Bar<T> {
-    fn bar(&self) {} //~ ERROR duplicate definitions
+    fn bar(&self) {}
 }
 
 impl Bar<u32> {
@@ -36,7 +36,7 @@ impl Bar<u32> {
 struct Baz<T>(T);
 
 impl<T: Copy> Baz<T> {
-    fn baz(&self) {} //~ ERROR duplicate definitions
+    fn baz(&self) {}
 }
 
 impl<T> Baz<Vec<T>> {
diff --git a/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr
new file mode 100644
index 00000000000..de8a24cf33f
--- /dev/null
+++ b/src/test/ui/codemap_tests/overlapping_inherent_impls.stderr
@@ -0,0 +1,29 @@
+error[E0592]: duplicate definitions with name `id`
+  --> $DIR/overlapping_inherent_impls.rs:19:5
+   |
+19 |     fn id() {}
+   |     ^^^^^^^^^^ duplicate definitions for `id`
+...
+23 |     fn id() {}
+   |     ---------- other definition for `id`
+
+error[E0592]: duplicate definitions with name `bar`
+  --> $DIR/overlapping_inherent_impls.rs:29:5
+   |
+29 |     fn bar(&self) {}
+   |     ^^^^^^^^^^^^^^^^ duplicate definitions for `bar`
+...
+33 |     fn bar(&self) {}
+   |     ---------------- other definition for `bar`
+
+error[E0592]: duplicate definitions with name `baz`
+  --> $DIR/overlapping_inherent_impls.rs:39:5
+   |
+39 |     fn baz(&self) {}
+   |     ^^^^^^^^^^^^^^^^ duplicate definitions for `baz`
+...
+43 |     fn baz(&self) {}
+   |     ---------------- other definition for `baz`
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/did_you_mean/issue-39544.rs b/src/test/ui/did_you_mean/issue-39544.rs
index 6331fc5771f..d7c89355606 100644
--- a/src/test/ui/did_you_mean/issue-39544.rs
+++ b/src/test/ui/did_you_mean/issue-39544.rs
@@ -51,3 +51,9 @@ pub fn with_arg(z: Z, w: &Z) {
     let _ = &mut z.x;
     let _ = &mut w.x;
 }
+
+pub fn with_tuple() {
+    let mut y = 0;
+    let x = (&y,);
+    *x.0 = 1;
+}
diff --git a/src/test/ui/did_you_mean/issue-39544.stderr b/src/test/ui/did_you_mean/issue-39544.stderr
index e1e229a8b05..2e98bc65e9e 100644
--- a/src/test/ui/did_you_mean/issue-39544.stderr
+++ b/src/test/ui/did_you_mean/issue-39544.stderr
@@ -90,5 +90,11 @@ error: cannot borrow immutable field `w.x` as mutable
 52 |     let _ = &mut w.x;
    |                  ^^^ cannot mutably borrow immutable field
 
-error: aborting due to 11 previous errors
+error: cannot assign to immutable borrowed content `*x.0`
+  --> $DIR/issue-39544.rs:58:5
+   |
+58 |     *x.0 = 1;
+   |     ^^^^^^^^ cannot borrow as mutable
+
+error: aborting due to 12 previous errors
 
diff --git a/src/test/ui/did_you_mean/issue-40006.rs b/src/test/ui/did_you_mean/issue-40006.rs
new file mode 100644
index 00000000000..cf75929bae2
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-40006.rs
@@ -0,0 +1,21 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct S;
+
+impl S {
+    pub hello_method(&self) {
+        println!("Hello");
+    }
+}
+
+fn main() {
+    S.hello_method();
+}
diff --git a/src/test/ui/did_you_mean/issue-40006.stderr b/src/test/ui/did_you_mean/issue-40006.stderr
new file mode 100644
index 00000000000..460958027ad
--- /dev/null
+++ b/src/test/ui/did_you_mean/issue-40006.stderr
@@ -0,0 +1,8 @@
+error: missing `fn` for method declaration
+  --> $DIR/issue-40006.rs:14:8
+   |
+14 |     pub hello_method(&self) {
+   |        ^ missing `fn`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/resolve/token-error-correct-3.stderr b/src/test/ui/resolve/token-error-correct-3.stderr
index 5be23d8ca48..849787e383f 100644
--- a/src/test/ui/resolve/token-error-correct-3.stderr
+++ b/src/test/ui/resolve/token-error-correct-3.stderr
@@ -14,13 +14,16 @@ error: expected one of `,`, `.`, `?`, or an operator, found `;`
   --> $DIR/token-error-correct-3.rs:23:35
    |
 23 |             callback(path.as_ref();  //~ NOTE: unclosed delimiter
-   |                                   ^
+   |                                   ^ expected one of `,`, `.`, `?`, or an operator here
 
 error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
   --> $DIR/token-error-correct-3.rs:29:9
    |
+25 |             fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
+   |                                                             - expected one of `.`, `;`, `?`, `}`, or an operator here
+...
 29 |         } else { //~ ERROR: incorrect close delimiter: `}`
-   |         ^
+   |         ^ unexpected token
 
 error[E0425]: cannot find function `is_directory` in this scope
   --> $DIR/token-error-correct-3.rs:21:13
diff --git a/src/test/ui/resolve/token-error-correct.stderr b/src/test/ui/resolve/token-error-correct.stderr
index 248a923efaf..226fa6469bc 100644
--- a/src/test/ui/resolve/token-error-correct.stderr
+++ b/src/test/ui/resolve/token-error-correct.stderr
@@ -32,7 +32,7 @@ error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `f
   --> $DIR/token-error-correct.rs:14:13
    |
 14 |     foo(bar(;
-   |             ^
+   |             ^ expected one of 18 possible tokens here
 
 error: expected expression, found `)`
   --> $DIR/token-error-correct.rs:23:1
diff --git a/src/test/ui/span/issue-34264.stderr b/src/test/ui/span/issue-34264.stderr
index c79db54eaef..98183e2f082 100644
--- a/src/test/ui/span/issue-34264.stderr
+++ b/src/test/ui/span/issue-34264.stderr
@@ -2,19 +2,19 @@ error: expected one of `:` or `@`, found `<`
   --> $DIR/issue-34264.rs:11:14
    |
 11 | fn foo(Option<i32>, String) {}
-   |              ^
+   |              ^ expected one of `:` or `@` here
 
 error: expected one of `:` or `@`, found `)`
   --> $DIR/issue-34264.rs:11:27
    |
 11 | fn foo(Option<i32>, String) {}
-   |                           ^
+   |                           ^ expected one of `:` or `@` here
 
 error: expected one of `:` or `@`, found `,`
   --> $DIR/issue-34264.rs:12:9
    |
 12 | fn bar(x, y: usize) {}
-   |         ^
+   |         ^ expected one of `:` or `@` here
 
 error[E0061]: this function takes 2 parameters but 3 parameters were supplied
   --> $DIR/issue-34264.rs:16:9
diff --git a/src/test/ui/suggestions/confuse-field-and-method/private-field.rs b/src/test/ui/suggestions/confuse-field-and-method/private-field.rs
new file mode 100644
index 00000000000..94cf38fb32f
--- /dev/null
+++ b/src/test/ui/suggestions/confuse-field-and-method/private-field.rs
@@ -0,0 +1,29 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub mod animal {
+    pub struct Dog {
+        pub age: usize,
+        dog_age: usize,
+    }
+
+    impl Dog {
+        pub fn new(age: usize) -> Dog {
+            Dog { age: age, dog_age: age * 7 }
+        }
+    }
+}
+
+fn main() {
+    let dog = animal::Dog::new(3);
+    let dog_age = dog.dog_age();
+    //let dog_age = dog.dog_age;
+    println!("{}", dog_age);
+}
diff --git a/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr b/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr
new file mode 100644
index 00000000000..d07885915d2
--- /dev/null
+++ b/src/test/ui/suggestions/confuse-field-and-method/private-field.stderr
@@ -0,0 +1,8 @@
+error: no method named `dog_age` found for type `animal::Dog` in the current scope
+  --> $DIR/private-field.rs:26:23
+   |
+26 |     let dog_age = dog.dog_age();
+   |                       ^^^^^^^ private field, not a method
+
+error: aborting due to previous error
+
diff --git a/src/test/parse-fail/bounds-obj-parens.rs b/src/test/ui/token/bounds-obj-parens.rs
index ad59d4a52d7..02c119cf727 100644
--- a/src/test/parse-fail/bounds-obj-parens.rs
+++ b/src/test/ui/token/bounds-obj-parens.rs
@@ -12,4 +12,6 @@
 
 type A = Box<(Fn(D::Error) -> E) + 'static + Send + Sync>; // OK (but see #39318)
 
-FAIL //~ ERROR
+FAIL
+//~^ ERROR
+//~| ERROR
diff --git a/src/test/ui/token/bounds-obj-parens.stderr b/src/test/ui/token/bounds-obj-parens.stderr
new file mode 100644
index 00000000000..4d60be15eca
--- /dev/null
+++ b/src/test/ui/token/bounds-obj-parens.stderr
@@ -0,0 +1,8 @@
+error: expected one of `!` or `::`, found `<eof>`
+  --> $DIR/bounds-obj-parens.rs:15:1
+   |
+15 | FAIL
+   | ^^^^ expected one of `!` or `::` here
+
+error: aborting due to previous error
+
diff --git a/src/test/compile-fail/issue-10636-2.rs b/src/test/ui/token/issue-10636-2.rs
index beaf9e5059f..93759123618 100644
--- a/src/test/compile-fail/issue-10636-2.rs
+++ b/src/test/ui/token/issue-10636-2.rs
@@ -14,5 +14,7 @@
 pub fn trace_option(option: Option<isize>) {
     option.map(|some| 42; //~ NOTE: unclosed delimiter
                           //~^ ERROR: expected one of
+                          //~| NOTE: expected one of
+                          //~| NOTE: unexpected token
 } //~ ERROR: incorrect close delimiter
 //~^ ERROR: expected expression, found `)`
diff --git a/src/test/ui/token/issue-10636-2.stderr b/src/test/ui/token/issue-10636-2.stderr
new file mode 100644
index 00000000000..b0bae1248b9
--- /dev/null
+++ b/src/test/ui/token/issue-10636-2.stderr
@@ -0,0 +1,28 @@
+error: incorrect close delimiter: `}`
+  --> $DIR/issue-10636-2.rs:19:1
+   |
+19 | } //~ ERROR: incorrect close delimiter
+   | ^
+   |
+note: unclosed delimiter
+  --> $DIR/issue-10636-2.rs:15:15
+   |
+15 |     option.map(|some| 42; //~ NOTE: unclosed delimiter
+   |               ^
+
+error: expected one of `,`, `.`, `?`, or an operator, found `;`
+  --> $DIR/issue-10636-2.rs:15:25
+   |
+15 |     option.map(|some| 42; //~ NOTE: unclosed delimiter
+   |                         ^ expected one of `,`, `.`, `?`, or an operator here
+
+error: expected expression, found `)`
+  --> $DIR/issue-10636-2.rs:19:1
+   |
+19 | } //~ ERROR: incorrect close delimiter
+   | ^
+
+error: main function not found
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/compile-fail/macro-incomplete-parse.rs b/src/test/ui/token/macro-incomplete-parse.rs
index c2ac99d1f6a..47374fc3c60 100644
--- a/src/test/compile-fail/macro-incomplete-parse.rs
+++ b/src/test/ui/token/macro-incomplete-parse.rs
@@ -20,6 +20,8 @@ macro_rules! ignored_item {
 
 macro_rules! ignored_expr {
     () => ( 1,  //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
+                //~^ NOTE expected one of `.`, `;`, `?`, `}`, or an operator here
+                //~| NOTE unexpected token
             2 )
 }
 
diff --git a/src/test/ui/token/macro-incomplete-parse.stderr b/src/test/ui/token/macro-incomplete-parse.stderr
new file mode 100644
index 00000000000..f23d97586b8
--- /dev/null
+++ b/src/test/ui/token/macro-incomplete-parse.stderr
@@ -0,0 +1,32 @@
+error: macro expansion ignores token `,` and any following
+  --> $DIR/macro-incomplete-parse.rs:17:9
+   |
+17 |         , //~ ERROR macro expansion ignores token `,`
+   |         ^
+   |
+note: caused by the macro expansion here; the usage of `ignored_item!` is likely invalid in item context
+  --> $DIR/macro-incomplete-parse.rs:32:1
+   |
+32 | ignored_item!(); //~ NOTE caused by the macro expansion here
+   | ^^^^^^^^^^^^^^^^
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
+  --> $DIR/macro-incomplete-parse.rs:22:14
+   |
+22 |     () => ( 1,  //~ ERROR expected one of `.`, `;`, `?`, `}`, or an operator, found `,`
+   |              ^ expected one of `.`, `;`, `?`, `}`, or an operator here
+
+error: macro expansion ignores token `,` and any following
+  --> $DIR/macro-incomplete-parse.rs:29:14
+   |
+29 |     () => ( 1, 2 ) //~ ERROR macro expansion ignores token `,`
+   |              ^
+   |
+note: caused by the macro expansion here; the usage of `ignored_pat!` is likely invalid in pattern context
+  --> $DIR/macro-incomplete-parse.rs:37:9
+   |
+37 |         ignored_pat!() => (), //~ NOTE caused by the macro expansion here
+   |         ^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/parse-fail/trailing-plus-in-bounds.rs b/src/test/ui/token/trailing-plus-in-bounds.rs
index 4a2e6d5bdcd..2bb2c97790c 100644
--- a/src/test/parse-fail/trailing-plus-in-bounds.rs
+++ b/src/test/ui/token/trailing-plus-in-bounds.rs
@@ -16,4 +16,6 @@ fn main() {
     let x: Box<Debug+> = box 3 as Box<Debug+>; // Trailing `+` is OK
 }
 
-FAIL //~ ERROR
+FAIL
+//~^ ERROR
+//~| ERROR
diff --git a/src/test/ui/token/trailing-plus-in-bounds.stderr b/src/test/ui/token/trailing-plus-in-bounds.stderr
new file mode 100644
index 00000000000..c765a434b8a
--- /dev/null
+++ b/src/test/ui/token/trailing-plus-in-bounds.stderr
@@ -0,0 +1,8 @@
+error: expected one of `!` or `::`, found `<eof>`
+  --> $DIR/trailing-plus-in-bounds.rs:19:1
+   |
+19 | FAIL
+   | ^^^^ expected one of `!` or `::` here
+
+error: aborting due to previous error
+
diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs
index 5db2ad83a0a..efadde99227 100644
--- a/src/tools/error_index_generator/main.rs
+++ b/src/tools/error_index_generator/main.rs
@@ -24,7 +24,7 @@ use std::path::PathBuf;
 
 use syntax::diagnostics::metadata::{get_metadata_dir, ErrorMetadataMap, ErrorMetadata};
 
-use rustdoc::html::markdown::{Markdown, MarkdownOutputStyle, PLAYGROUND};
+use rustdoc::html::markdown::{Markdown, PLAYGROUND};
 use rustc_serialize::json;
 
 enum OutputFormat {
@@ -100,7 +100,7 @@ impl Formatter for HTMLFormatter {
 
         // Description rendered as markdown.
         match info.description {
-            Some(ref desc) => write!(output, "{}", Markdown(desc, MarkdownOutputStyle::Fancy))?,
+            Some(ref desc) => write!(output, "{}", Markdown(desc))?,
             None => write!(output, "<p>No description.</p>\n")?,
         }
 
diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs
index 3808c05c6b9..0dbf0d4316a 100644
--- a/src/tools/tidy/src/pal.rs
+++ b/src/tools/tidy/src/pal.rs
@@ -75,7 +75,7 @@ const EXCEPTION_PATHS: &'static [&'static str] = &[
     "src/libtest", // Probably should defer to unstable std::sys APIs
 
     // std testing crates, ok for now at least
-    "src/libcoretest",
+    "src/libcore/tests",
 
     // non-std crates
     "src/test",
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 2233f8c3529..012301299e0 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -110,6 +110,7 @@ pub fn check(path: &Path, bad: &mut bool) {
         let skip_cr = contents.contains("ignore-tidy-cr");
         let skip_tab = contents.contains("ignore-tidy-tab");
         let skip_length = contents.contains("ignore-tidy-linelength");
+        let skip_end_whitespace = contents.contains("ignore-tidy-end-whitespace");
         for (i, line) in contents.split("\n").enumerate() {
             let mut err = |msg: &str| {
                 println!("{}:{}: {}", file.display(), i + 1, msg);
@@ -122,7 +123,7 @@ pub fn check(path: &Path, bad: &mut bool) {
             if line.contains("\t") && !skip_tab {
                 err("tab character");
             }
-            if line.ends_with(" ") || line.ends_with("\t") {
+            if !skip_end_whitespace && (line.ends_with(" ") || line.ends_with("\t")) {
                 err("trailing whitespace");
             }
             if line.contains("\r") && !skip_cr {